aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/ta_control.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/ta_control.c')
-rw-r--r--src/common/ta_control.c90
1 files changed, 71 insertions, 19 deletions
diff --git a/src/common/ta_control.c b/src/common/ta_control.c
index ccb60e2b..6fe409a2 100644
--- a/src/common/ta_control.c
+++ b/src/common/ta_control.c
@@ -1,6 +1,7 @@
/* Loop control for Timing Advance */
/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -12,39 +13,90 @@
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+/* Related specs: 3GPP TS 45.010 sections 5.5, 5.6 */
+
#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/bts_trx.h>
#include <osmo-bts/logging.h>
-/* 90% of one bit duration in 1/256 symbols: 256*0.9 */
-#define TOA256_9OPERCENT 230
+/* 3GPP TS 45.010 sec 5.6.3 Delay assessment error:
+ * 75% of one bit duration in 1/256 symbols: 256*0.75 */
+#define TOA256_THRESH 192
/* rqd_ta value range */
#define TA_MIN 0
#define TA_MAX 63
-void lchan_ms_ta_ctrl(struct gsm_lchan *lchan)
+/* TODO: make configurable over osmo-bts VTY? Pass it BSC->BTS? */
+#define TA_MAX_INC_STEP 2
+#define TA_MAX_DEC_STEP 2
+
+
+/*! compute the new "Ordered Timing Advance" communicated to the MS and store it in lchan.
+ * \param lchan logical channel for which to compute (and in which to store) new power value.
+ * \param[in] ms_tx_ta The TA used by the MS and reported in L1SACCH, see struct gsm_sacch_l1_hdr field "ta".
+ * \param[in] toa256 Time of Arrival (in 1/256th bits) computed at Rx side
+ */
+void lchan_ms_ta_ctrl(struct gsm_lchan *lchan, uint8_t ms_tx_ta, int16_t toa256)
{
- int16_t toa256 = lchan->meas.ms_toa256;
-
- if (toa256 < -TOA256_9OPERCENT && lchan->rqd_ta > TA_MIN) {
- LOGPLCHAN(lchan, DLOOP, LOGL_INFO,
- "TOA is too early (%d), now lowering TA from %d to %d\n",
- toa256, lchan->rqd_ta, lchan->rqd_ta - 1);
- lchan->rqd_ta--;
- } else if (toa256 > TOA256_9OPERCENT && lchan->rqd_ta < TA_MAX) {
- LOGPLCHAN(lchan, DLOOP, LOGL_INFO,
- "TOA is too late (%d), now raising TA from %d to %d\n",
- toa256, lchan->rqd_ta, lchan->rqd_ta + 1);
- lchan->rqd_ta++;
- } else
+ int16_t new_ta;
+ /* Shall we skip current block based on configured interval? */
+
+ /* TA control interval: how many blocks do we skip? */
+ if (lchan->ta_ctrl.skip_block_num-- > 0)
+ return;
+
+ /* Reset the number of SACCH blocks to be skipped:
+ * ctrl_interval=0 => 0 blocks to skip,
+ * ctrl_interval=1 => 1 blocks to skip,
+ * ctrl_interval=2 => 3 blocks to skip,
+ * so basically ctrl_interval * 2 - 1. */
+ lchan->ta_ctrl.skip_block_num = lchan->ts->trx->ta_ctrl_interval * 2 - 1;
+
+ int16_t delta_ta = toa256/256;
+ if (toa256 >= 0) {
+ if ((toa256 - (256 * delta_ta)) > TOA256_THRESH)
+ delta_ta++;
+ if (delta_ta > TA_MAX_INC_STEP)
+ delta_ta = TA_MAX_INC_STEP;
+ } else {
+ if ((toa256 - (256 * delta_ta)) < -TOA256_THRESH)
+ delta_ta--;
+ if (delta_ta < -TA_MAX_DEC_STEP)
+ delta_ta = -TA_MAX_DEC_STEP;
+ }
+
+ new_ta = ms_tx_ta + delta_ta;
+
+ /* Make sure new_ta is never negative: */
+ if (new_ta < TA_MIN)
+ new_ta = TA_MIN;
+
+ /* Don't ask for out of range TA: */
+ if (new_ta > TA_MAX)
+ new_ta = TA_MAX;
+
+ if (lchan->ta_ctrl.current == (uint8_t)new_ta) {
LOGPLCHAN(lchan, DLOOP, LOGL_DEBUG,
- "TOA is correct (%d), keeping current TA of %d\n",
- toa256, lchan->rqd_ta);
+ "Keeping current TA at %u: TOA was %d\n",
+ lchan->ta_ctrl.current, toa256);
+ return;
+ }
+
+ LOGPLCHAN(lchan, DLOOP, LOGL_INFO,
+ "%s TA %u => %u: TOA was too %s (%d)\n",
+ (uint8_t)new_ta > lchan->ta_ctrl.current ? "Raising" : "Lowering",
+ lchan->ta_ctrl.current, (uint8_t)new_ta,
+ (uint8_t)new_ta > lchan->ta_ctrl.current ? "late" : "early",
+ toa256);
+
+ /* store the resulting new TA in the lchan */
+ lchan->ta_ctrl.current = (uint8_t)new_ta;
}