<p>Vadim Yanitskiy has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/10460">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">trxcon/scheduler: add TCH/H channel support<br><br>Change-Id: Ibb2a0850692c5ff86b13b820af10b12085589e67<br>---<br>M src/host/trxcon/Makefile.am<br>M src/host/trxcon/sched_lchan_desc.c<br>A src/host/trxcon/sched_lchan_tchh.c<br>M src/host/trxcon/sched_trx.c<br>M src/host/trxcon/sched_trx.h<br>5 files changed, 329 insertions(+), 7 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/60/10460/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/host/trxcon/Makefile.am b/src/host/trxcon/Makefile.am</span><br><span>index c9cc170..7095cb5 100644</span><br><span>--- a/src/host/trxcon/Makefile.am</span><br><span>+++ b/src/host/trxcon/Makefile.am</span><br><span>@@ -35,6 +35,7 @@</span><br><span>   sched_lchan_desc.c \</span><br><span>         sched_lchan_xcch.c \</span><br><span>         sched_lchan_tchf.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  sched_lchan_tchh.c \</span><br><span>         sched_lchan_rach.c \</span><br><span>         sched_lchan_sch.c \</span><br><span>  sched_mframe.c \</span><br><span>diff --git a/src/host/trxcon/sched_lchan_desc.c b/src/host/trxcon/sched_lchan_desc.c</span><br><span>index 37d1273..4cac439 100644</span><br><span>--- a/src/host/trxcon/sched_lchan_desc.c</span><br><span>+++ b/src/host/trxcon/sched_lchan_desc.c</span><br><span>@@ -27,10 +27,7 @@</span><br><span> </span><br><span> /* TODO: implement */</span><br><span> #define tx_pdtch_fn  NULL</span><br><span style="color: hsl(0, 100%, 40%);">-#define tx_tchh_fn  NULL</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> #define rx_pdtch_fn     NULL</span><br><span style="color: hsl(0, 100%, 40%);">-#define rx_tchh_fn  NULL</span><br><span> </span><br><span> /* Forward declaration of handlers */</span><br><span> int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span>@@ -54,6 +51,14 @@</span><br><span> int tx_tchf_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span>         struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int rx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span style="color: hsl(120, 100%, 40%);">+    struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid,</span><br><span style="color: hsl(120, 100%, 40%);">+      sbit_t *bits, int8_t rssi, int16_t toa256);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int tx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span style="color: hsl(120, 100%, 40%);">+    struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> const struct trx_lchan_desc trx_lchan_desc[_TRX_CHAN_MAX] = {</span><br><span>       {</span><br><span>            TRXC_IDLE,              "IDLE",</span><br><span>diff --git a/src/host/trxcon/sched_lchan_tchh.c b/src/host/trxcon/sched_lchan_tchh.c</span><br><span>new file mode 100644</span><br><span>index 0000000..678fca8</span><br><span>--- /dev/null</span><br><span>+++ b/src/host/trxcon/sched_lchan_tchh.c</span><br><span>@@ -0,0 +1,316 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * OsmocomBB <-> SDR connection bridge</span><br><span style="color: hsl(120, 100%, 40%);">+ * TDMA scheduler: handlers for DL / UL bursts on logical channels</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2018 by Vadim Yanitskiy <axilirator@gmail.com></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2018 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 General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 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 General Public License along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</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 <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_04_08.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm_utils.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/codec/codec.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "l1ctl_proto.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "scheduler.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "sched_trx.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "logging.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_if.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trxcon.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "l1ctl.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int rx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid,</span><br><span style="color: hsl(120, 100%, 40%);">+      sbit_t *bits, int8_t rssi, int16_t toa256)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct trx_lchan_desc *lchan_desc;</span><br><span style="color: hsl(120, 100%, 40%);">+      int n_errors = -1, n_bits_total, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+  sbit_t *buffer, *offset;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t l2[128], *mask;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t *first_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+   bool facch_now;</span><br><span style="color: hsl(120, 100%, 40%);">+       size_t l2_len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Set up pointers */</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_desc = &trx_lchan_desc[lchan->type];</span><br><span style="color: hsl(120, 100%, 40%);">+     first_fn = &lchan->rx_first_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+        mask = &lchan->rx_burst_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+  buffer = lchan->rx_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGP(DSCHD, LOGL_DEBUG, "Traffic received on %s: fn=%u ts=%u bid=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+             lchan_desc->name, fn, ts->index, bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Reset internal state */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (bid == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* FIXME: clean up old measurements */</span><br><span style="color: hsl(120, 100%, 40%);">+                memset(&lchan->meas, 0x00, sizeof(lchan->meas));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* FIXME: clear history buffer: no need? */</span><br><span style="color: hsl(120, 100%, 40%);">+           memset(buffer + 464, 0, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               *first_fn = fn;</span><br><span style="color: hsl(120, 100%, 40%);">+               *mask = 0x00;</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%);">+  /* Update mask and RSSI */</span><br><span style="color: hsl(120, 100%, 40%);">+    lchan->meas.rssi_sum += rssi;</span><br><span style="color: hsl(120, 100%, 40%);">+      lchan->meas.toa256_sum += toa256;</span><br><span style="color: hsl(120, 100%, 40%);">+  lchan->meas.rssi_num++;</span><br><span style="color: hsl(120, 100%, 40%);">+    lchan->meas.toa256_num++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Copy burst to the end of buffer of 6 bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+     offset = buffer + bid * 116 + 464;</span><br><span style="color: hsl(120, 100%, 40%);">+    memcpy(offset, bits + 3, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(offset + 58, bits + 87, 58);</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%);">+               LOGP(DSCHD, LOGL_ERROR, "Received incomplete traffic frame at "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "fn=%u (%u/%u) for %s\n", *first_fn,</span><br><span style="color: hsl(120, 100%, 40%);">+                        (*first_fn) % ts->mf_layout->period,</span><br><span style="color: hsl(120, 100%, 40%);">+                    ts->mf_layout->period,</span><br><span style="color: hsl(120, 100%, 40%);">+                  lchan_desc->name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Send BFI */</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%);">+   /* skip second of two TCH frames of FACCH was received */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (lchan->dl_ongoing_facch) {</span><br><span style="color: hsl(120, 100%, 40%);">+             lchan->dl_ongoing_facch = false;</span><br><span style="color: hsl(120, 100%, 40%);">+           memcpy(buffer, buffer + 232, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+            memcpy(buffer + 232, buffer + 464, 232);</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%);">+   /* May we have a FACCH/H frame on the current frame number? */</span><br><span style="color: hsl(120, 100%, 40%);">+        facch_now = sched_facch_h_dl_end(lchan->type, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (lchan->tch_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SIGN:</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_CMODE_SPEECH_V1: /* HR */</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = gsm0503_tch_hr_decode(l2, buffer,</span><br><span style="color: hsl(120, 100%, 40%);">+                        !facch_now, &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%);">+                /**</span><br><span style="color: hsl(120, 100%, 40%);">+            * TODO: AMR requires a dedicated loop,</span><br><span style="color: hsl(120, 100%, 40%);">+                * which will be implemented later...</span><br><span style="color: hsl(120, 100%, 40%);">+          */</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DSCHD, LOGL_ERROR, "AMR isn't supported yet\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           return -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DSCHD, LOGL_ERROR, "Invalid TCH mode: %u\n", lchan->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%);">+   /* Shift buffer by 4 bursts for interleaving */</span><br><span style="color: hsl(120, 100%, 40%);">+       memcpy(buffer, buffer + 232, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+    memcpy(buffer + 232, buffer + 464, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Check decoding result */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DSCHD, LOGL_ERROR, "Received bad TCH frame ending at "</span><br><span style="color: hsl(120, 100%, 40%);">+                 "fn=%u for %s: %d\n", fn, lchan_desc->name, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Send BFI */</span><br><span style="color: hsl(120, 100%, 40%);">+                goto bfi;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (rc == GSM_MACBLOCK_LEN) {</span><br><span style="color: hsl(120, 100%, 40%);">+          lchan->dl_ongoing_facch = true;</span><br><span style="color: hsl(120, 100%, 40%);">+            /* FACCH received, forward it to the higher layers */</span><br><span style="color: hsl(120, 100%, 40%);">+         sched_send_dt_ind(trx, ts, lchan, l2, GSM_MACBLOCK_LEN,</span><br><span style="color: hsl(120, 100%, 40%);">+                       n_errors, false, false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* Send BFI instead of a stolen TCH frame */</span><br><span style="color: hsl(120, 100%, 40%);">+          goto bfi;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* A good TCH frame received */</span><br><span style="color: hsl(120, 100%, 40%);">+               l2_len = rc;</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 a traffic frame to the higher layers */</span><br><span style="color: hsl(120, 100%, 40%);">+       return sched_send_dt_ind(trx, ts, lchan, l2, l2_len,</span><br><span style="color: hsl(120, 100%, 40%);">+          n_errors, false, true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bfi:</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Bad frame indication */</span><br><span style="color: hsl(120, 100%, 40%);">+    l2_len = sched_bad_frame_ind(l2, lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Didn't try to decode */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (n_errors < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          n_errors = 116 * 4;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Send a BFI frame to the higher layers */</span><br><span style="color: hsl(120, 100%, 40%);">+   return sched_send_dt_ind(trx, ts, lchan, l2, l2_len,</span><br><span style="color: hsl(120, 100%, 40%);">+          n_errors, true, 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%);">+int tx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span style="color: hsl(120, 100%, 40%);">+      struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct trx_lchan_desc *lchan_desc;</span><br><span style="color: hsl(120, 100%, 40%);">+      ubit_t burst[GSM_BURST_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+  ubit_t *buffer, *offset;</span><br><span style="color: hsl(120, 100%, 40%);">+      const uint8_t *tsc;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t *mask;</span><br><span style="color: hsl(120, 100%, 40%);">+        size_t l2_len;</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%);">+     /* Set up pointers */</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_desc = &trx_lchan_desc[lchan->type];</span><br><span style="color: hsl(120, 100%, 40%);">+     mask = &lchan->tx_burst_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+  buffer = lchan->tx_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bid > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Align to the first burst */</span><br><span style="color: hsl(120, 100%, 40%);">+                if (*mask == 0x00)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return 0;</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%);">+   if (*mask == 0x00) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Align transmission of the first FACCH/H frame */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (lchan->tch_mode == GSM48_CMODE_SIGN)</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!sched_facch_h_ul_start(lchan->type, fn))</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%);">+   /* Shift buffer by 2 bursts back for interleaving */</span><br><span style="color: hsl(120, 100%, 40%);">+  memcpy(buffer, buffer + 232, 232);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Also shift TX burst mask */</span><br><span style="color: hsl(120, 100%, 40%);">+        *mask = *mask << 2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* If FACCH/H blocks are still pending */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (lchan->ul_facch_blocks > 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+               memcpy(buffer + 232, buffer + 464, 232);</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%);">+   /* Check the current TCH mode */</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (lchan->tch_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SIGN:</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_CMODE_SPEECH_V1: /* HR */</span><br><span style="color: hsl(120, 100%, 40%);">+          l2_len = GSM_HR_BYTES + 1;</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%);">+                /**</span><br><span style="color: hsl(120, 100%, 40%);">+            * TODO: AMR requires a dedicated loop,</span><br><span style="color: hsl(120, 100%, 40%);">+                * which will be implemented later...</span><br><span style="color: hsl(120, 100%, 40%);">+          */</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DSCHD, LOGL_ERROR, "AMR isn't supported yet, "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "dropping frame...\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Forget this primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+           sched_prim_drop(lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+               return -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DSCHD, LOGL_ERROR, "Invalid TCH mode: %u, "</span><br><span style="color: hsl(120, 100%, 40%);">+                    "dropping frame...\n", lchan->tch_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Forget this primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+           sched_prim_drop(lchan);</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%);">+   /* Determine payload length */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (PRIM_IS_FACCH(lchan->prim)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          l2_len = GSM_MACBLOCK_LEN; /* FACCH */</span><br><span style="color: hsl(120, 100%, 40%);">+        } else if (lchan->prim->payload_len != l2_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DSCHD, LOGL_ERROR, "Primitive has odd length %zu "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "(expected %zu for TCH or %u for FACCH), so dropping...\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 lchan->prim->payload_len, l2_len, GSM_MACBLOCK_LEN);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Forget this primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+           sched_prim_drop(lchan);</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%);">+   /* Encode the payload */</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = gsm0503_tch_hr_encode(buffer, lchan->prim->payload, l2_len);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DSCHD, LOGL_ERROR, "Failed to encode L2 payload\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Forget this primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+           sched_prim_drop(lchan);</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%);">+   /* A FACCH/H frame occupies 6 bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (PRIM_IS_FACCH(lchan->prim))</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan->ul_facch_blocks = 6;</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%);">+ /* Determine which burst should be sent */</span><br><span style="color: hsl(120, 100%, 40%);">+    offset = buffer + bid * 116;</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%);">+  /* Choose proper TSC */</span><br><span style="color: hsl(120, 100%, 40%);">+       tsc = sched_nb_training_bits[trx->tsc];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Compose a new burst */</span><br><span style="color: hsl(120, 100%, 40%);">+     memset(burst, 0, 3); /* TB */</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst + 3, offset, 58); /* Payload 1/2 */</span><br><span style="color: hsl(120, 100%, 40%);">+      memcpy(burst + 61, tsc, 26); /* TSC */</span><br><span style="color: hsl(120, 100%, 40%);">+        memcpy(burst + 87, offset + 58, 58); /* Payload 2/2 */</span><br><span style="color: hsl(120, 100%, 40%);">+        memset(burst + 145, 0, 3); /* TB */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DSCHD, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u burst=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           lchan_desc->name, fn, ts->index, bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Forward burst to transceiver */</span><br><span style="color: hsl(120, 100%, 40%);">+    sched_trx_handle_tx_burst(trx, ts, lchan, fn, burst);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* In case of a FACCH/H frame, one block less */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (lchan->ul_facch_blocks)</span><br><span style="color: hsl(120, 100%, 40%);">+                lchan->ul_facch_blocks--;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if ((*mask & 0x0f) == 0x0f) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /**</span><br><span style="color: hsl(120, 100%, 40%);">+            * If no more FACCH/H blocks pending,</span><br><span style="color: hsl(120, 100%, 40%);">+          * confirm data / traffic sending</span><br><span style="color: hsl(120, 100%, 40%);">+              */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!lchan->ul_facch_blocks)</span><br><span style="color: hsl(120, 100%, 40%);">+                       sched_send_dt_conf(trx, ts, lchan, fn,</span><br><span style="color: hsl(120, 100%, 40%);">+                                PRIM_IS_TCH(lchan->prim));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Forget processed primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+              sched_prim_drop(lchan);</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%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/host/trxcon/sched_trx.c b/src/host/trxcon/sched_trx.c</span><br><span>index 8bd3c72..bc51d96 100644</span><br><span>--- a/src/host/trxcon/sched_trx.c</span><br><span>+++ b/src/host/trxcon/sched_trx.c</span><br><span>@@ -463,7 +463,7 @@</span><br><span>  /* TCH specific variables */</span><br><span>         if (CHAN_IS_TCH(lchan->type)) {</span><br><span>           lchan->dl_ongoing_facch = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-         lchan->ul_ongoing_facch = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               lchan->ul_facch_blocks = 0;</span><br><span> </span><br><span>           lchan->tch_mode = GSM48_CMODE_SIGN;</span><br><span> </span><br><span>diff --git a/src/host/trxcon/sched_trx.h b/src/host/trxcon/sched_trx.h</span><br><span>index f8898cd..57b4782 100644</span><br><span>--- a/src/host/trxcon/sched_trx.h</span><br><span>+++ b/src/host/trxcon/sched_trx.h</span><br><span>@@ -171,9 +171,9 @@</span><br><span>    uint8_t tch_mode;</span><br><span> </span><br><span>        /*! \brief FACCH/H on downlink */</span><br><span style="color: hsl(0, 100%, 40%);">-       uint8_t dl_ongoing_facch;</span><br><span style="color: hsl(0, 100%, 40%);">-       /*! \brief FACCH/H on uplink */</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t ul_ongoing_facch;</span><br><span style="color: hsl(120, 100%, 40%);">+     bool dl_ongoing_facch;</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! \brief pending FACCH/H blocks on Uplink */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t ul_facch_blocks;</span><br><span> </span><br><span>         struct {</span><br><span>             /*! \brief Number of RSSI values */</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/10460">change 10460</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/10460"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmocom-bb </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ibb2a0850692c5ff86b13b820af10b12085589e67 </div>
<div style="display:none"> Gerrit-Change-Number: 10460 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Vadim Yanitskiy <axilirator@gmail.com> </div>