<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmocom-bb/+/17352">View Change</a></p><div style="white-space:pre-wrap">Approvals:
laforge: Looks good to me, approved
pespin: Looks good to me, but someone else must approve
Jenkins Builder: Verified
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">trxcon/scheduler: substitute lost TDMA frames on Downlink<br><br>It may happen that one or more Downlink bursts are lost on their<br>way to the MS due to a variety of reasons. Modern transceivers<br>supporting TRXDv1 protocol would substitute lost bursts with<br>so-called NOPE indications. Hovewer, neither fake_trx.py nor<br>grgsm_trx do support this feature at the moment.<br><br>We can still detect and compensate TDMA frame loss per logical<br>channels in the same way as it's already done in osmo-bts-trx.<br>In short, we should keep TDMA frame number of the last received<br>burst in the logical channel state, and using the appropriate<br>multiframe layout, check if there were any gaps between TDMA<br>frame number of the current burst and the stored one.<br><br>Change-Id: I3551d79796a3730565c2c70577e9d134e636f275<br>---<br>M src/host/trxcon/sched_trx.c<br>M src/host/trxcon/sched_trx.h<br>2 files changed, 100 insertions(+), 55 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/host/trxcon/sched_trx.c b/src/host/trxcon/sched_trx.c</span><br><span>index e6e759a..ba75b6f 100644</span><br><span>--- a/src/host/trxcon/sched_trx.c</span><br><span>+++ b/src/host/trxcon/sched_trx.c</span><br><span>@@ -321,9 +321,6 @@</span><br><span> if (ts == NULL)</span><br><span> return -EINVAL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Flush TS frame counter */</span><br><span style="color: hsl(0, 100%, 40%);">- ts->mf_last_fn = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Undefine multiframe layout */</span><br><span> ts->mf_layout = NULL;</span><br><span> </span><br><span>@@ -491,6 +488,9 @@</span><br><span> </span><br><span> /* Reset ciphering state */</span><br><span> memset(&lchan->a5, 0x00, sizeof(lchan->a5));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Reset TDMA frame statistics */</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(&lchan->tdma, 0x00, sizeof(lchan->tdma));</span><br><span> }</span><br><span> </span><br><span> int sched_trx_deactivate_lchan(struct trx_ts *ts, enum trx_lchan_type chan)</span><br><span>@@ -610,8 +610,65 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int subst_frame_loss(struct trx_lchan_state *lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+ trx_lchan_rx_func *handler,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t fn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct trx_multiframe *mf;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct trx_frame *fp;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int elapsed, i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Wait until at least one TDMA frame is processed */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan->tdma.num_proc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EAGAIN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Short alias for the current multiframe */</span><br><span style="color: hsl(120, 100%, 40%);">+ mf = lchan->ts->mf_layout;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* How many frames elapsed since the last one? */</span><br><span style="color: hsl(120, 100%, 40%);">+ elapsed = TDMA_FN_SUB(fn, lchan->tdma.last_proc);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (elapsed > mf->period) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DSCHD, LOGL_NOTICE, "Too many (>%u) contiguous TDMA frames elapsed (%u) "</span><br><span style="color: hsl(120, 100%, 40%);">+ "since the last processed fn=%u\n", mf->period,</span><br><span style="color: hsl(120, 100%, 40%);">+ elapsed, lchan->tdma.last_proc);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (elapsed == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DSCHD, LOGL_ERROR, "No TDMA frames elapsed since the last processed "</span><br><span style="color: hsl(120, 100%, 40%);">+ "fn=%u, must be a bug?\n", lchan->tdma.last_proc);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EIO;</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%);">+ /* TODO: make bits constant */</span><br><span style="color: hsl(120, 100%, 40%);">+ static sbit_t bits[148] = { 0 };</span><br><span style="color: hsl(120, 100%, 40%);">+ struct trx_meas_set fake_meas = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .fn = lchan->tdma.last_proc,</span><br><span style="color: hsl(120, 100%, 40%);">+ .rssi = -120,</span><br><span style="color: hsl(120, 100%, 40%);">+ .toa256 = 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%);">+ /* Traverse from fp till the current frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < elapsed - 1; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ fp = &mf->frames[TDMA_FN_INC(&fake_meas.fn) % mf->period];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fp->dl_chan != lchan->type)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DSCHD, LOGL_NOTICE, "Substituting lost TDMA frame %u on %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ fake_meas.fn, trx_lchan_desc[lchan->type].name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ handler(lchan->ts->trx, lchan->ts, lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+ fake_meas.fn, fp->dl_bid,</span><br><span style="color: hsl(120, 100%, 40%);">+ bits, &fake_meas);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Update TDMA frame statistics */</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan->tdma.last_proc = fake_meas.fn;</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan->tdma.num_proc++;</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan->tdma.num_lost++;</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 style="color: hsl(120, 100%, 40%);">+</span><br><span> int sched_trx_handle_rx_burst(struct trx_instance *trx, uint8_t tn,</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t burst_fn, sbit_t *bits, uint16_t nbits,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t fn, sbit_t *bits, uint16_t nbits,</span><br><span> const struct trx_meas_set *meas)</span><br><span> {</span><br><span> struct trx_lchan_state *lchan;</span><br><span>@@ -620,7 +677,6 @@</span><br><span> </span><br><span> trx_lchan_rx_func *handler;</span><br><span> enum trx_lchan_type chan;</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t fn, elapsed;</span><br><span> uint8_t offset, bid;</span><br><span> </span><br><span> /* Check whether required timeslot is allocated and configured */</span><br><span>@@ -631,61 +687,42 @@</span><br><span> return -EINVAL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Calculate how many frames have been elapsed */</span><br><span style="color: hsl(0, 100%, 40%);">- elapsed = TDMA_FN_SUB(burst_fn, ts->mf_last_fn);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Get frame from multiframe */</span><br><span style="color: hsl(120, 100%, 40%);">+ offset = fn % ts->mf_layout->period;</span><br><span style="color: hsl(120, 100%, 40%);">+ frame = ts->mf_layout->frames + offset;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /**</span><br><span style="color: hsl(0, 100%, 40%);">- * If not too many frames have been elapsed,</span><br><span style="color: hsl(0, 100%, 40%);">- * start counting from last fn + 1</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">- if (elapsed < 10)</span><br><span style="color: hsl(0, 100%, 40%);">- fn = TDMA_FN_SUM(ts->mf_last_fn, 1);</span><br><span style="color: hsl(0, 100%, 40%);">- else</span><br><span style="color: hsl(0, 100%, 40%);">- fn = burst_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Get required info from frame */</span><br><span style="color: hsl(120, 100%, 40%);">+ bid = frame->dl_bid;</span><br><span style="color: hsl(120, 100%, 40%);">+ chan = frame->dl_chan;</span><br><span style="color: hsl(120, 100%, 40%);">+ handler = trx_lchan_desc[chan].rx_fn;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- while (1) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* Get frame from multiframe */</span><br><span style="color: hsl(0, 100%, 40%);">- offset = fn % ts->mf_layout->period;</span><br><span style="color: hsl(0, 100%, 40%);">- frame = ts->mf_layout->frames + offset;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Omit bursts which have no handler, like IDLE bursts.</span><br><span style="color: hsl(120, 100%, 40%);">+ * TODO: handle noise indications during IDLE frames. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!handler)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENODEV;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Get required info from frame */</span><br><span style="color: hsl(0, 100%, 40%);">- bid = frame->dl_bid;</span><br><span style="color: hsl(0, 100%, 40%);">- chan = frame->dl_chan;</span><br><span style="color: hsl(0, 100%, 40%);">- handler = trx_lchan_desc[chan].rx_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Find required channel state */</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan = sched_trx_find_lchan(ts, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENODEV;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Omit bursts which have no handler, like IDLE bursts */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!handler)</span><br><span style="color: hsl(0, 100%, 40%);">- goto next_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Ensure that channel is active */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!lchan->active)</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Find required channel state */</span><br><span style="color: hsl(0, 100%, 40%);">- lchan = sched_trx_find_lchan(ts, chan);</span><br><span style="color: hsl(0, 100%, 40%);">- if (lchan == NULL)</span><br><span style="color: hsl(0, 100%, 40%);">- goto next_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Compensate lost TDMA frames (if any) */</span><br><span style="color: hsl(120, 100%, 40%);">+ subst_frame_loss(lchan, handler, fn);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Ensure that channel is active */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!lchan->active)</span><br><span style="color: hsl(0, 100%, 40%);">- goto next_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Perform A5/X decryption if required */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (lchan->a5.algo)</span><br><span style="color: hsl(120, 100%, 40%);">+ sched_trx_a5_burst_dec(lchan, fn, bits);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Reached current fn */</span><br><span style="color: hsl(0, 100%, 40%);">- if (fn == burst_fn) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* Perform A5/X decryption if required */</span><br><span style="color: hsl(0, 100%, 40%);">- if (lchan->a5.algo)</span><br><span style="color: hsl(0, 100%, 40%);">- sched_trx_a5_burst_dec(lchan, fn, bits);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Put burst to handler */</span><br><span style="color: hsl(120, 100%, 40%);">+ handler(trx, ts, lchan, fn, bid, bits, meas);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Put burst to handler */</span><br><span style="color: hsl(0, 100%, 40%);">- handler(trx, ts, lchan, fn, bid, bits, meas);</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%);">-next_frame:</span><br><span style="color: hsl(0, 100%, 40%);">- /* Reached current fn */</span><br><span style="color: hsl(0, 100%, 40%);">- if (fn == burst_fn)</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%);">- TDMA_FN_INC(&fn);</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%);">- /* Set last processed frame number */</span><br><span style="color: hsl(0, 100%, 40%);">- ts->mf_last_fn = fn;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Update TDMA frame statistics */</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan->tdma.last_proc = fn;</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan->tdma.num_proc++;</span><br><span> </span><br><span> return 0;</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 44f502c..cf63df1 100644</span><br><span>--- a/src/host/trxcon/sched_trx.h</span><br><span>+++ b/src/host/trxcon/sched_trx.h</span><br><span>@@ -209,6 +209,16 @@</span><br><span> /*! \brief AVG measurements of the last received block */</span><br><span> struct trx_meas_set meas_avg;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief TDMA loss detection state */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Last processed TDMA frame number */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t last_proc;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Number of processed TDMA frames */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned long num_proc;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Number of lost TDMA frames */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned long num_lost;</span><br><span style="color: hsl(120, 100%, 40%);">+ } tdma;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief SACCH state */</span><br><span> struct {</span><br><span> /*! \brief Cached measurement report (last received) */</span><br><span>@@ -255,8 +265,6 @@</span><br><span> struct trx_ts {</span><br><span> /*! \brief Timeslot index within a frame (0..7) */</span><br><span> uint8_t index;</span><br><span style="color: hsl(0, 100%, 40%);">- /*! \brief Last received frame number */</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t mf_last_fn;</span><br><span> </span><br><span> /*! \brief Pointer to multiframe layout */</span><br><span> const struct trx_multiframe *mf_layout;</span><br><span>@@ -356,7 +364,7 @@</span><br><span> void sched_prim_flush_queue(struct llist_head *list);</span><br><span> </span><br><span> int sched_trx_handle_rx_burst(struct trx_instance *trx, uint8_t tn,</span><br><span style="color: hsl(0, 100%, 40%);">- uint32_t burst_fn, sbit_t *bits, uint16_t nbits,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint32_t fn, sbit_t *bits, uint16_t nbits,</span><br><span> const struct trx_meas_set *meas);</span><br><span> int sched_trx_handle_tx_burst(struct trx_instance *trx,</span><br><span> struct trx_ts *ts, struct trx_lchan_state *lchan,</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmocom-bb/+/17352">change 17352</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/osmocom-bb/+/17352"/><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-Change-Id: I3551d79796a3730565c2c70577e9d134e636f275 </div>
<div style="display:none"> Gerrit-Change-Number: 17352 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </div>
<div style="display:none"> Gerrit-Owner: fixeria <axilirator@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: fixeria <axilirator@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>