diff options
author | Yves Godin <yves.godin@nutaq.com> | 2016-12-22 13:32:14 -0500 |
---|---|---|
committer | Yves Godin <yves.godin@nutaq.com> | 2016-12-22 13:32:14 -0500 |
commit | 2adc18ff23aa00664e2d4f8607b12c695b34095d (patch) | |
tree | 4dd464c6ebac6bb6c39ecf57509f23a2627b8c59 | |
parent | ac5c989e516630610cfc2db9610234eac491251a (diff) | |
parent | 847f4ae30a8e4e7f44eb750616bbfdd3cc8a388e (diff) |
Merge branch 'nrw/litecell15-merge-master-22122016' into 'nrw/litecell15-next'
Nrw/litecell15 merge master 22122016
This MR should have: *
See merge request !64
69 files changed, 2161 insertions, 704 deletions
@@ -1,26 +1,29 @@ -Repository forw the Osmocom BTS implementation. += Repository for the Osmocom BTS implementation. = -This code implementes the Layer 2 and higher of a more or less -conventional GSM BTS (Base Transceiver Station) - however, using an -Abis/IP interface, rather than the old-fashioned E1/T1. +For most complete and accurate information, please refer to +https://osmocom.org/projects/osmobts/wiki -Specifically, this includes - * BTS-Side implementation of TS 08.58 (RSL) and TS 12.21 (OML) - * BTS-Side implementation of LAPDm (using libosmocore/libosmogsm) - * A somewhat separated interface between those higher layer parts - and the Layer1 interface. +To submit patches, please refer to +https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit +(Note: github pull requests are rejected by a bot) + +== Summary == -Right now, only one hardware and Layer1 are supported: The sysmocom -sysmoBTS. +This code implements Layer 2 and higher of a more or less conventional GSM BTS +(Base Transceiver Station) - however, using an Abis/IP interface, rather than +the old-fashioned E1/T1. -There is some experimental and way incomplete code to use a couple of -OsmocomBB phones and run them in the BTS. However, the required code -for the Calypso DSP code have not been written yet. This would still -require a lot of work. +Specifically, this includes + * BTS-side implementation of TS 08.58 (RSL) and TS 12.21 (OML) + * BTS-side implementation of LAPDm (using libosmocore/libosmogsm) + * A somewhat separated interface between those higher layer parts and the + Layer1 interface. -Some additional work is being done in using some parts of the OpenBTS -L1FEC and glue it against omso-bts. This code is called osmo-trx and -requires the jolly/trx branch of this repository. +Several kinds of BTS hardware are supported: + * sysmocom sysmoBTS + * Octasic octphy + * Nutaq litecell 1.5 + * software-defined radio based osmo-bts-trx (e.g. B210) == Known Limitations == @@ -52,5 +55,3 @@ implementation: * Doesn't yet include MAC address in Abis/IP Identity message * MphConfig.CNF can be returned to the wrong callback. E.g. with Tx Power and ciphering. The dispatch should take a look at the hLayer3. - - diff --git a/configure.ac b/configure.ac index 0951e187..3fd6b8a1 100644 --- a/configure.ac +++ b/configure.ac @@ -3,6 +3,9 @@ AC_INIT([osmo-bts], m4_esyscmd([./git-version-gen .tarball-version]), [openbsc-devel@lists.openbsc.org]) +dnl *This* is the root dir, even if an install-sh exists in ../ or ../../ +AC_CONFIG_AUX_DIR([.]) + AM_INIT_AUTOMAKE([dist-bzip2]) AC_CONFIG_TESTDIR(tests) @@ -15,6 +18,13 @@ AC_PROG_CC AC_PROG_INSTALL AC_PROG_RANLIB +dnl check for pkg-config (explained in detail in libosmocore/configure.ac) +AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no) +if test "x$PKG_CONFIG_INSTALLED" = "xno"; then + AC_MSG_WARN([You need to install pkg-config]) +fi +PKG_PROG_PKG_CONFIG([0.20]) + dnl checks for header files AC_HEADER_STDC @@ -65,6 +75,7 @@ if test "$enable_octphy" = "yes" ; then AC_CHECK_HEADER([octphy/octvc1/gsm/octvc1_gsm_default.h],[], [AC_MSG_ERROR([octphy/octvc1/gsm/octvc1_gsm_default.h can not be found in $octsdr2g_incdir])], [#include <octphy/octvc1/gsm/octvc1_gsm_default.h>]) + AC_CHECK_MEMBER([tOCTVC1_GSM_TRX_CONFIG.usCentreArfcn], AC_DEFINE([OCTPHY_MULTI_TRX], [1], [Define to 1 if your octphy header files support multi-trx]), [], [#include <octphy/octvc1/gsm/octvc1_gsm_api.h>]) CPPFLAGS=$oldCPPFLAGS fi diff --git a/contrib/dtx_check.gawk b/contrib/dtx_check.gawk new file mode 100755 index 00000000..9a3ddcf6 --- /dev/null +++ b/contrib/dtx_check.gawk @@ -0,0 +1,89 @@ +#!/usr/bin/gawk -f + +# Expected input format: FN TYPE + +BEGIN { + DELTA = 0 + ERR = 0 + FORCE = 0 + FN = 0 + SILENCE = 0 + TYPE = "" + CHK = "" + U_MAX = 8 * 20 + 120 / 26 + U_MIN = 8 * 20 - 120 / 26 + F_MAX = 3 * 20 + 120 / 26 + F_MIN = 3 * 20 - 120 / 26 +} + +{ + if (NR > 2) { # we have data from previous record to compare to + DELTA = ($1 - FN) * 120 / 26 + CHK = "OK" + if ("FACCH" == $2 && "ONSET" == TYPE) { # ONSET due to FACCH is NOT a talkspurt + SILENCE = 1 + } + if (("UPDATE" == TYPE || "FIRST" == TYPE) && ("FACCH" == $2 || "SPEECH" == $2)) { # check for missing ONSET: + CHK = "FAIL: missing ONSET (" $2 ") after " TYPE "." + ERR++ + } + if ("SID_P1" == $2) { + CHK = "FAIL: regular AMR payload with FT SID and STI=0 (should be either pyaload Update or STI=1)." + ERR++ + } + if ("FORCED_FIRST" == $2 || "FORCED_NODATA" == $2 || "FORCED_F_P2" == $2 || "FORCED_F_INH" == $2 || "FORCED_U_INH" == $2) { + CHK = "FAIL: event " $2 " inserted by DSP." + FORCE++ + ERR++ + } + if ("FIRST_P2" != $2 && "FIRST_P1" == TYPE) { + CHK = "FAIL: " TYPE " followed by " $2 " instead of P2." + ERR++ + } + if ("FIRST" == $2 && "FIRST" == TYPE) { + CHK = "FAIL: multiple SID FIRST in a row." + ERR++ + } + if ("OK" == CHK && "ONSET" != $2) { # check inter-SID distances: + if ("UPDATE" == TYPE) { + if (DELTA > U_MAX) { + CHK = "FAIL: delta (" $1 - FN "fn) from previous SID UPDATE (@" FN ") too big " DELTA "ms > " U_MAX "ms." + ERR++ + } + if ("UPDATE" == $2 && DELTA < U_MIN) { + CHK = "FAIL: delta (" $1 - FN "fn) from previous SID UPDATE (@" FN ") too small " DELTA "ms < " U_MIN "ms." + ERR++ + } + } + if ("FIRST" == TYPE) { + if (DELTA > F_MAX) { + CHK = "FAIL: delta (" $1 - FN "fn) from previous SID FIRST (@" FN ") too big " DELTA "ms > " F_MAX "ms." + ERR++ + } + if ("UPDATE" == $2 && DELTA < F_MIN) { + CHK = "FAIL: delta (" $1 - FN "fn) from previous SID UPDATE (@" FN ") too small " DELTA "ms < " F_MIN "ms." + ERR++ + } + } + } + if ("FACCH" == TYPE && "FIRST" != $2 && "FACCH" != $2 && 1 == SILENCE) { # check FACCH handling + CHK = "FAIL: incorrect silence resume with " $2 " after FACCH." + ERR++ + } + } + if ("SPEECH" == $2 || "ONSET" == $2) { # talkspurt + SILENCE = 0 + } + if ("UPDATE" == $2 || "FIRST" == $2) { # silence + SILENCE = 1 + } + print $1, $2, CHK + if ($2 != "EMPTY") { # skip over EMPTY records + TYPE = $2 + FN = $1 + } +} + +END { + print "Check completed: found " ERR " errors (" FORCE " events inserted by DSP) in " NR " records." +} diff --git a/contrib/jenkins_bts_model.sh b/contrib/jenkins_bts_model.sh new file mode 100755 index 00000000..58eac5b1 --- /dev/null +++ b/contrib/jenkins_bts_model.sh @@ -0,0 +1,33 @@ +#!/bin/sh +bts_model="$1" + +if [ ! -d "./contrib" ]; then + echo "Run ./contrib/jenkins_bts_model.sh from the root of the osmo-bts tree" + exit 1 +fi + +set -x -e + +case "$bts_model" in + + sysmo) + ./contrib/jenkins_sysmobts.sh + ;; + + oct) + ./contrib/jenkins_oct.sh + ;; + + trx) + ./contrib/jenkins_bts_trx.sh + ;; + + oct+trx) + ./contrib/jenkins_oct_and_bts_trx.sh + ;; + + *) + set +x + echo "Unknown BTS model '$bts_model'" + ;; +esac diff --git a/contrib/jenkins_bts_trx.sh b/contrib/jenkins_bts_trx.sh new file mode 100755 index 00000000..c4f05a93 --- /dev/null +++ b/contrib/jenkins_bts_trx.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +set -ex + +base="$PWD" +deps="$base/deps" +inst="$deps/install" +export deps inst + +mkdir "$deps" || true +rm -rf "$inst" + +export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" +export LD_LIBRARY_PATH="$inst/lib" + +osmo-build-dep.sh libosmocore +osmo-build-dep.sh libosmo-abis + +cd "$deps" + +# Get osmo-pcu for pcuif_proto.h +osmo-deps.sh osmo-pcu + +# Get openbsc for gsm_data_shared.* +osmo-deps.sh openbsc + +cd "$base" + +set +x +echo +echo +echo +echo " =============================== osmo-bts-trx ===============================" +echo +set -x + +autoreconf --install --force +configure_flags="\ + --with-openbsc=$deps/openbsc/openbsc/include \ + --with-osmo-pcu=$deps/osmo-pcu/include \ + --enable-trx \ + " +./configure $configure_flags +$MAKE $PARALLEL_MAKE +$MAKE check \ + || cat-testlogs.sh +DISTCHECK_CONFIGURE_FLAGS="$configure_flags" \ + $MAKE distcheck \ + || cat-testlogs.sh diff --git a/contrib/jenkins_oct.sh b/contrib/jenkins_oct.sh index 32b14073..4fecd0a3 100755 --- a/contrib/jenkins_oct.sh +++ b/contrib/jenkins_oct.sh @@ -2,33 +2,29 @@ set -ex -rm -rf deps/install -mkdir deps || true -cd deps +base="$PWD" +deps="$base/deps" +inst="$deps/install" +export deps inst + +mkdir "$deps" || true +rm -rf "$inst" # Get the headers.. +cd "$deps" git clone git://git.osmocom.org/openbsc || true cd openbsc git pull --rebase +cd "$base" +osmo-build-dep.sh libosmocore -# Build the dependency -cd ../ +export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" +export LD_LIBRARY_PATH="$inst/lib" -osmo-deps.sh libosmocore -cd libosmocore -autoreconf --install --force -./configure --prefix=$PWD/../install -$MAKE $PARALLEL_MAKE install +osmo-build-dep.sh libosmo-abis -cd ../ -osmo-deps.sh libosmo-abis -cd libosmo-abis -autoreconf --install --force -PKG_CONFIG_PATH=$PWD/../install/lib/pkgconfig ./configure --prefix=$PWD/../install -PKG_CONFIG_PATH=$PWD/../install/lib/pkgconfig $MAKE $PARALLEL_MAKE install - -cd ../ +cd "$deps" if ! test -d layer1-api; then git clone git://git.osmocom.org/octphy-2g-headers layer1-api @@ -43,11 +39,21 @@ else git reset --hard $FIRMWARE_VERSION fi +cd "$base" + +set +x +echo +echo +echo +echo " =============================== osmo-bts-octphy ===============================" +echo +set -x -# Build osmo-bts -cd ../../ autoreconf --install --force -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure --with-openbsc=$PWD/deps/openbsc/openbsc/include --with-octsdr-2g=$PWD/deps/layer1-api/ --enable-octphy -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE check -DISTCHECK_CONFIGURE_FLAGS="--with-octsdr-2g=$PWD/deps/layer1-api/ --with-openbsc=$PWD/deps/openbsc/openbsc/include --enable-octphy" PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck +./configure --with-openbsc="$deps/openbsc/openbsc/include" --with-octsdr-2g="$deps/layer1-api/" --enable-octphy +$MAKE $PARALLEL_MAKE +$MAKE check \ + || cat-testlogs.sh +DISTCHECK_CONFIGURE_FLAGS="--with-octsdr-2g=$deps/layer1-api/ --with-openbsc=$deps/openbsc/openbsc/include --enable-octphy" \ + $MAKE distcheck \ + || cat-testlogs.sh diff --git a/contrib/jenkins_oct_and_bts_trx.sh b/contrib/jenkins_oct_and_bts_trx.sh new file mode 100755 index 00000000..0740bd03 --- /dev/null +++ b/contrib/jenkins_oct_and_bts_trx.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +set -ex + +base="$PWD" +deps="$base/deps" +inst="$deps/install" +export deps inst + +mkdir "$deps" || true +rm -rf "$inst" + +export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" +export LD_LIBRARY_PATH="$inst/lib" + +osmo-build-dep.sh libosmocore +osmo-build-dep.sh libosmo-abis + +cd "$deps" + +# Get osmo-pcu for pcuif_proto.h +osmo-deps.sh osmo-pcu + +# Get openbsc for gsm_data_shared.* +osmo-deps.sh openbsc + +cd "$deps" +if ! test -d layer1-api; +then + git clone git://git.osmocom.org/octphy-2g-headers layer1-api +fi +cd layer1-api +git fetch origin +if [ $FIRMWARE_VERSION = "master" ]; +then +git reset --hard origin/master +else +git reset --hard $FIRMWARE_VERSION +fi + +cd "$base" + +set +x +echo +echo +echo +echo " =============================== osmo-bts-octphy+trx ===============================" +echo +set -x + +autoreconf --install --force +configure_flags="\ + --with-openbsc=$deps/openbsc/openbsc/include \ + --with-osmo-pcu=$deps/osmo-pcu/include \ + --with-octsdr-2g=$deps/layer1-api/ \ + --enable-octphy \ + --enable-trx \ + " +./configure $configure_flags +$MAKE $PARALLEL_MAKE +$MAKE check \ + || cat-testlogs.sh +DISTCHECK_CONFIGURE_FLAGS="$configure_flags" \ + $MAKE distcheck \ + || cat-testlogs.sh diff --git a/contrib/jenkins_sysmobts.sh b/contrib/jenkins_sysmobts.sh index 051c8e0c..be544a78 100755 --- a/contrib/jenkins_sysmobts.sh +++ b/contrib/jenkins_sysmobts.sh @@ -2,33 +2,29 @@ set -ex -rm -rf deps/install -mkdir deps || true -cd deps +base="$PWD" +deps="$base/deps" +inst="$deps/install" +export deps inst + +mkdir "$deps" || true +rm -rf "$inst" # Get the headers.. +cd "$deps" git clone git://git.osmocom.org/openbsc || true cd openbsc git pull --rebase +cd "$base" +osmo-build-dep.sh libosmocore -# Build the dependency -cd ../ - -osmo-deps.sh libosmocore -cd libosmocore -autoreconf --install --force -./configure --prefix=$PWD/../install -$MAKE $PARALLEL_MAKE install +export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" +export LD_LIBRARY_PATH="$inst/lib" -cd ../ -osmo-deps.sh libosmo-abis -cd libosmo-abis -autoreconf --install --force -PKG_CONFIG_PATH=$PWD/../install/lib/pkgconfig ./configure --prefix=$PWD/../install -PKG_CONFIG_PATH=$PWD/../install/lib/pkgconfig $MAKE $PARALLEL_MAKE install +osmo-build-dep.sh libosmo-abis -cd ../ +cd "$deps" if ! test -d layer1-api; then git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api @@ -42,20 +38,29 @@ git reset --hard origin/master else git reset --hard $FIRMWARE_VERSION fi -mkdir -p $PWD/../install/include/sysmocom/femtobts/ -cp include/*.h ../install/include/sysmocom/femtobts/ +mkdir -p "$inst/include/sysmocom/femtobts" +cp include/*.h "$inst/include/sysmocom/femtobts/" +cd "$base" -# Build osmo-bts -cd ../../ -autoreconf --install --force -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure --enable-sysmocom-bts --with-openbsc=$PWD/deps/openbsc/openbsc/include -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE -PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE check -DISTCHECK_CONFIGURE_FLAGS="--enable-sysmocom-bts --with-openbsc=$PWD/deps/openbsc/openbsc/include" PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck +set +x +echo +echo +echo +echo " =============================== osmo-bts-sysmo ===============================" +echo +set -x +autoreconf --install --force +./configure --enable-sysmocom-bts --with-openbsc="$deps/openbsc/openbsc/include" +$MAKE $PARALLEL_MAKE +$MAKE check \ + || cat-testlogs.sh +DISTCHECK_CONFIGURE_FLAGS="--enable-sysmocom-bts --with-openbsc=$deps/openbsc/openbsc/include" \ + $MAKE distcheck \ + || cat-testlogs.sh # This will not work for the femtobts if [ $FIRMWARE_VERSION != "femtobts_v2.7" ]; then - PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE -C contrib/sysmobts-calib + $MAKE -C contrib/sysmobts-calib fi diff --git a/contrib/superfemto.sh b/contrib/superfemto.sh new file mode 100755 index 00000000..19dc4107 --- /dev/null +++ b/contrib/superfemto.sh @@ -0,0 +1,110 @@ +#!/bin/sh + +# Split common DSP call log file (produced by superfemto-compatible firmware) into 4 separate call leg files (MO/MT & DL/UL) with events in format "FN EVENT_TYPE": +# MO Mobile Originated +# MT Mobile Terminated +# DL DownLink (BTS -> L1) +# UL UpLink (L1 -> BTS) + +if [ -z $1 ]; then + echo "expecting DSP log file name as parameter" + exit 1 +fi + +# MO handle appear 1st in the logs +MO=$(grep 'h=' $1 | head -n 1 | cut -f2 -d',' | cut -f2 -d= | cut -f1 -d']') + +# direction markers: +DLST="_CodeBurst" +ULST="_DecodeAndIdentify" + +# DL sed filters: +D_EMP='s/ Empty frame request!/EMPTY/i' +D_FAC='s/ Coding a FACCH\/. frame !!/FACCH/i' +D_FST='s/ Coding a RTP SID First frame !!/FIRST/i' +D_FS1='s/ Coding a SID First P1 frame !!/FIRST_P1/i' +D_FS2='s/ Coding a SID First P2 frame !!/FIRST_P2/i' +D_RP1='s/ Coding a RTP SID P1 frame !!/SID_P1/i' +D_UPD='s/ Coding a RTP SID Update frame !!/UPDATE/i' +D_SPE='s/ Coding a RTP Speech frame !!/SPEECH/i' +D_ONS='s/ Coding a Onset frame !!/ONSET/i' +D_FO1='s/ A speech frame is following a NoData or SID First without an Onset./FORCED_FIRST/i' +D_FO2='s/ A speech frame is following a NoData without an Onset./FORCED_NODATA/i' +D_FP2='s/ A speech frame is following a NoData or SID_FIRST_P2 without an Onset./FORCED_F_P2/i' +D_FIN='s/ A speech frame is following a SID_FIRST without inhibit. A SID_FIRST_INH will be inserted./FORCED_F_INH/i' +D_UIN='s/ A speech frame is following a SID_UPDATE without inhibit. A SID_UPDATE_INH will be inserted./FORCED_U_INH/i' + +# UL sed filters: +U_NOD='s/ It is a No Data frame !!/NODATA/i' +U_ONS='s/ It is an ONSET frame !!/ONSET/i' +U_UPD='s/ It is a SID UPDATE frame !!/UPDATE/i' +U_FST='s/ It is a SID FIRST frame !!/FIRST/i' +U_FP1='s/ It is a SID-First P1 frame !!/FIRST_P1/i' +U_FP2='s/ It is a SID-First P2 frame !!/FIRST_P2/i' +U_SPE='s/ It is a SPEECH frame *!!/SPEECH/i' +U_UIN='s/ It is a SID update InH frame !!/UPD_INH/i' +U_FIN='s/ It is a SID-First InH frame !!/FST_INH/i' +U_RAT='s/ It is a RATSCCH data frame !!/RATSCCH/i' + +DL () { # filter downlink-related entries + grep $DLST $1 > $1.DL.tmp +} + +UL () { # uplink does not require special fix + grep $ULST $1 > $1.UL.tmp.fix +} + +DL $1 +UL $1 + +FIX() { # add MO/MT marker from preceding line to inserted ONSETs so filtering works as expected + cat $1.DL.tmp | awk 'BEGIN{ FS=" h="; H="" } { if (NF > 1) { H = $2; print $1 "h=" $2 } else { print $1 ", h=" H } }' > $1.DL.tmp.fix +} + +FIX $1 + +MO() { # filter MO call DL or UL logs + grep "h=$MO" $1.tmp.fix > $1.MO.raw +} + +MT() { # filter MT call DL or UL logs + grep -v "h=$MO" $1.tmp.fix > $1.MT.raw +} + +MO $1.DL +MT $1.DL +MO $1.UL +MT $1.UL + +PREP() { # prepare logs for reformatting + cat $1.raw | cut -f2 -d')' | cut -f1 -d',' | cut -f2 -d'>' | sed 's/\[u32Fn/fn/' | sed 's/\[ u32Fn/fn/' | sed 's/fn = /fn=/' | sed 's/fn=//' | sed 's/\[Fn=//' | sed 's/ An Onset will be inserted.//' > $1.tmp1 +} + +PREP "$1.DL.MT" +PREP "$1.DL.MO" +PREP "$1.UL.MT" +PREP "$1.UL.MO" + +RD() { # reformat DL logs for consistency checks + cat $1.tmp1 | sed "$D_FST" | sed "$D_SPE" | sed "$D_FS1" | sed "$D_FS2" | sed "$D_UIN" | sed "$D_FIN" | sed "$D_UPD" | sed "$D_INH" | sed "$D_RP1" | sed "$D_ONS" | sed "$D_EMP" | sed "$D_FAC" | sed "$D_FO1" | sed "$D_FO2" | sed "$D_FP2" > $1.tmp2 +} + +RU() { # reformat UL logs for consistency checks + cat $1.tmp1 | sed "$U_FST" | sed "$U_SPE" | sed "$U_FP1" | sed "$U_FP2" | sed "$U_UPD" | sed "$U_ONS" | sed "$U_NOD" | sed "$U_UIN" | sed "$U_FIN" | sed "$U_RAT" > $1.tmp2 +} + +RD "$1.DL.MT" +RD "$1.DL.MO" +RU "$1.UL.MT" +RU "$1.UL.MO" + +SW() { # swap fields + cat $1.tmp2 | awk '{ print $2, $1 }' > $1 +} + +SW "$1.DL.MT" +SW "$1.DL.MO" +SW "$1.UL.MT" +SW "$1.UL.MO" + +rm $1.*.tmp* diff --git a/debian/compat b/debian/compat index 7f8f011e..ec635144 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -7 +9 diff --git a/debian/control b/debian/control index d067e317..e1a58b28 100644 --- a/debian/control +++ b/debian/control @@ -1,12 +1,24 @@ Source: osmo-bts +Maintainer: Holger Hans Peter Freyther <holger@moiji-mobile.com> Section: net Priority: optional -Maintainer: Holger Hans Peter Freyther <holger@moiji-mobile.com> -Build-Depends: debhelper (>= 7.0.0~), dh-autoreconf, dh-systemd (>= 1.5), autotools-dev, pkg-config, libosmocore-dev, libortp-dev, libosmo-abis-dev, libosmo-netif-dev -Standards-Version: 3.8.4 -Homepage: http://osmocom.org/projects/osmobts -Vcs-Git: git://git.osmocom.org/osmo-bts +Build-Depends: debhelper (>= 9), + pkg-config, + dh-autoreconf, + dh-systemd (>= 1.5), + autotools-dev, + pkg-config, + libosmocore-dev, + openbsc-dev, + libosmo-abis-dev, + libosmo-netif-dev, + libgps-dev, + libortp-dev, + txt2man +Standards-Version: 3.9.8 Vcs-Browser: http://git.osmocom.org/osmo-bts/ +Vcs-Git: git://git.osmocom.org/osmo-bts +Homepage: https://projects.osmocom.org/projects/osmobts Package: osmo-bts-trx Architecture: any diff --git a/debian/rules b/debian/rules index f7f941b3..80ba0b2c 100755 --- a/debian/rules +++ b/debian/rules @@ -5,7 +5,7 @@ DEBVERS := $(shell echo '$(DEBIAN)' | cut -d- -f1) VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g') #export DH_VERBOSE=1 -export DEB_BUILD_HARDENING=1 +export DEB_BUILD_MAINT_OPTIONS = hardening=+all %: @@ -20,3 +20,13 @@ override_dh_autoreconf: override_dh_auto_configure: dh_auto_configure -- --enable-trx + +override_dh_clean: + dh_clean + $(RM) tests/package.m4 + $(RM) tests/testsuite + +# Print test results in case of a failure +override_dh_auto_test: + dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false) + diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index d0b55ff9..ef4165f3 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \ oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \ handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h \ - power_control.h scheduler.h scheduler_backend.h phy_link.h + power_control.h scheduler.h scheduler_backend.h phy_link.h \ + dtx_dl_amr_fsm.h diff --git a/include/osmo-bts/amr.h b/include/osmo-bts/amr.h index 6bdc41fc..f3132874 100644 --- a/include/osmo-bts/amr.h +++ b/include/osmo-bts/amr.h @@ -11,7 +11,8 @@ void amr_log_mr_conf(int ss, int logl, const char *pfx, int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc, const uint8_t *mr_conf, unsigned int len); -int get_amr_mode_idx(const struct amr_multirate_conf *amr_mrc, uint8_t cmi); +void amr_set_mode_pref(uint8_t *data, const struct amr_multirate_conf *amr_mrc, + uint8_t cmi, uint8_t cmr); unsigned int amr_get_initial_mode(struct gsm_lchan *lchan); #endif /* _OSMO_BTS_AMR_H */ diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h index ec58eddc..567772ec 100644 --- a/include/osmo-bts/bts.h +++ b/include/osmo-bts/bts.h @@ -36,7 +36,7 @@ uint8_t *lchan_sacch_get(struct gsm_lchan *lchan); int lchan_init_lapdm(struct gsm_lchan *lchan); void load_timer_start(struct gsm_bts *bts); - +uint8_t num_agch(struct gsm_bts_trx *trx, const char * arg); void bts_update_status(enum bts_global_status which, int on); int trx_ms_pwr_ctrl_is_osmo(struct gsm_bts_trx *trx); diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index 7e2d0887..7a87d786 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -45,6 +45,9 @@ int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan); int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap); +int bts_model_lchan_deactivate(struct gsm_lchan *lchan); +int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan); + void bts_model_abis_close(struct gsm_bts *bts); int bts_model_ctrl_cmds_install(struct gsm_bts *bts); diff --git a/include/osmo-bts/dtx_dl_amr_fsm.h b/include/osmo-bts/dtx_dl_amr_fsm.h new file mode 100644 index 00000000..4fb2f251 --- /dev/null +++ b/include/osmo-bts/dtx_dl_amr_fsm.h @@ -0,0 +1,38 @@ +#pragma once + +#include <osmocom/core/fsm.h> +#include <osmocom/core/utils.h> +#include <osmocom/core/logging.h> + +/* DTX DL AMR FSM */ + +#define X(s) (1 << (s)) + +enum dtx_dl_amr_fsm_states { + ST_VOICE, + ST_SID_F1, + ST_SID_F2, + ST_F1_INH, + ST_U_INH, + ST_F1_INH_REC, + ST_U_INH_REC, + ST_SID_U, + ST_ONSET_V, + ST_ONSET_F, + ST_ONSET_V_REC, + ST_ONSET_F_REC, + ST_FACCH, +}; + +enum dtx_dl_amr_fsm_events { + E_VOICE, + E_ONSET, + E_FACCH, + E_COMPL, + E_INHIB, + E_SID_F, + E_SID_U, +}; + +extern const struct value_string dtx_dl_amr_fsm_event_names[]; +extern struct osmo_fsm dtx_dl_amr_fsm; diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index ed864d61..ceae25f1 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -86,6 +86,7 @@ struct gsm_bts_role_bts { char *bsc_oml_host; struct llist_head oml_queue; unsigned int rtp_jitter_buf_ms; + bool rtp_jitter_adaptive; struct { uint8_t ciphers; /* flags A5/1==0x1, A5/2==0x2, A5/3==0x4 */ } support; diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h index 981cd756..dcebc1d8 100644 --- a/include/osmo-bts/l1sap.h +++ b/include/osmo-bts/l1sap.h @@ -1,6 +1,12 @@ #ifndef L1SAP_H #define L1SAP_H +#include <osmocom/gsm/protocol/gsm_04_08.h> + +/* lchan link ID */ +#define LID_SACCH 0x40 +#define LID_DEDIC 0x00 + /* timeslot and subslot from chan_nr */ #define L1SAP_CHAN2TS(chan_nr) (chan_nr & 7) #define L1SAP_CHAN2SS_TCHH(chan_nr) ((chan_nr >> 3) & 1) @@ -8,7 +14,7 @@ #define L1SAP_CHAN2SS_SDCCH8(chan_nr) ((chan_nr >> 3) & 7) /* logical channel from chan_nr + link_id */ -#define L1SAP_IS_LINK_SACCH(link_id) ((link_id & 0xC0) == 0x40) +#define L1SAP_IS_LINK_SACCH(link_id) ((link_id & 0xC0) == LID_SACCH) #define L1SAP_IS_CHAN_TCHF(chan_nr) ((chan_nr & 0xf8) == 0x08) #define L1SAP_IS_CHAN_TCHH(chan_nr) ((chan_nr & 0xf0) == 0x10) #define L1SAP_IS_CHAN_SDCCH4(chan_nr) ((chan_nr & 0xe0) == 0x20) @@ -28,6 +34,12 @@ #define L1SAP_FN2PTCCHBLOCK(fn) ((fn / 104) & 3) #define L1SAP_IS_PTCCH(fn) ((fn % 52) == 12) +static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { + 0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, + 0x2B, 0x2B, 0x2B +}; + /* subslot from any chan_nr */ static inline uint8_t l1sap_chan2ss(uint8_t chan_nr) { @@ -55,7 +67,8 @@ int l1sap_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn, /* call-back function for incoming RTP */ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, - unsigned int rtp_pl_len, bool marker); + unsigned int rtp_pl_len, uint16_t seq_number, + uint32_t timestamp, bool marker); /* channel control */ int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *tp); diff --git a/include/osmo-bts/msg_utils.h b/include/osmo-bts/msg_utils.h index f03eb438..55e8475d 100644 --- a/include/osmo-bts/msg_utils.h +++ b/include/osmo-bts/msg_utils.h @@ -5,14 +5,23 @@ #pragma once #include <osmo-bts/gsm_data.h> +#include <osmo-bts/dtx_dl_amr_fsm.h> + +#include <osmocom/codec/codec.h> #include <stdbool.h> struct msgb; -/* Access 1st byte of msgb control buffer */ +/* Access 1st part of msgb control buffer */ #define rtpmsg_marker_bit(x) ((x)->cb[0]) +/* Access 2nd part of msgb control buffer */ +#define rtpmsg_seq(x) ((x)->cb[1]) + +/* Access 3rd part of msgb control buffer */ +#define rtpmsg_ts(x) ((x)->cb[2]) + /** * Classification of OML message. ETSI for plain GSM 12.21 * messages and IPA/Osmo for manufacturer messages. @@ -24,10 +33,15 @@ enum { }; void lchan_set_marker(bool t, struct gsm_lchan *lchan); -void save_last_sid(struct gsm_lchan *lchan, uint8_t *l1_payload, size_t length, - uint32_t fn, bool update); +bool dtx_dl_amr_enabled(const struct gsm_lchan *lchan); +void dtx_dispatch(struct gsm_lchan *lchan, enum dtx_dl_amr_fsm_events e); +bool dtx_recursion(const struct gsm_lchan *lchan); +void dtx_int_signal(struct gsm_lchan *lchan); +void dtx_cache_payload(struct gsm_lchan *lchan, const uint8_t *l1_payload, + size_t length, uint32_t fn, int update); +int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl, + size_t rtp_pl_len, uint32_t fn, uint8_t *l1_payload, + bool marker, uint8_t *len, uint8_t *ft_out); uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn); -bool dtx_amr_sid_optional(const struct gsm_lchan *lchan, uint32_t fn); -bool dtx_sched_optional(struct gsm_lchan *lchan, uint32_t fn); int msg_verify_ipa_structure(struct msgb *msg); int msg_verify_oml_structure(struct msgb *msg); diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h index 753dfd4b..b12d78f7 100644 --- a/include/osmo-bts/phy_link.h +++ b/include/osmo-bts/phy_link.h @@ -7,6 +7,7 @@ #include <osmo-bts/scheduler.h> #include <linux/if_packet.h> +#include "btsconfig.h" struct gsm_bts_trx; @@ -63,6 +64,10 @@ struct phy_link { uint32_t rf_port_index; uint32_t rx_gain_db; uint32_t tx_atten_db; +#if OCTPHY_MULTI_TRX == 1 + /* arfcn used by TRX with id 0 */ + uint16_t center_arfcn; +#endif struct octphy_hdl *hdl; } octphy; diff --git a/include/osmo-bts/rsl.h b/include/osmo-bts/rsl.h index 093e9cb7..a2a6e3d9 100644 --- a/include/osmo-bts/rsl.h +++ b/include/osmo-bts/rsl.h @@ -9,8 +9,11 @@ enum { LCHAN_REL_ACT_RSL, LCHAN_REL_ACT_PCU, LCHAN_REL_ACT_OML, + LCHAN_REL_ACT_REACT, }; +#define LCHAN_FN_DUMMY 0xFFFFFFFF + int msgb_queue_flush(struct llist_head *list); int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg); @@ -24,6 +27,8 @@ int rsl_tx_conn_fail(struct gsm_lchan *lchan, uint8_t cause); int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan); int rsl_tx_hando_det(struct gsm_lchan *lchan, uint8_t *ho_delay); +int lchan_deactivate(struct gsm_lchan *lchan); + /* call-back for LAPDm code, called when it wants to send msgs UP */ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx); diff --git a/src/common/Makefile.am b/src/common/Makefile.am index e7ecebbd..d104c481 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) -AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOTRAU_CFLAGS) -LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS) +AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOCODEC_CFLAGS) +LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOCODEC_LIBS) if ENABLE_LC15BTS AM_CFLAGS += -DENABLE_LC15BTS @@ -11,6 +11,7 @@ libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ rsl.c vty.c paging.c measurement.c amr.c lchan.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \ - l1sap.c cbch.c power_control.c main.c phy_link.c + l1sap.c cbch.c power_control.c main.c phy_link.c \ + dtx_dl_amr_fsm.c libl1sched_a_SOURCES = scheduler.c diff --git a/src/common/amr.c b/src/common/amr.c index 56ed4302..05d1aaac 100644 --- a/src/common/amr.c +++ b/src/common/amr.c @@ -22,7 +22,8 @@ void amr_log_mr_conf(int ss, int logl, const char *pfx, LOGPC(ss, logl, "\n"); } -int get_amr_mode_idx(const struct amr_multirate_conf *amr_mrc, uint8_t cmi) +static inline int get_amr_mode_idx(const struct amr_multirate_conf *amr_mrc, + uint8_t cmi) { unsigned int i; for (i = 0; i < amr_mrc->num_modes; i++) { @@ -32,6 +33,46 @@ int get_amr_mode_idx(const struct amr_multirate_conf *amr_mrc, uint8_t cmi) return -EINVAL; } +static inline uint8_t set_cmr_mode_idx(const struct amr_multirate_conf *amr_mrc, + uint8_t cmr) +{ + int rc; + + /* Codec Mode Request is in upper 4 bits of RTP payload header, + * and we simply copy the CMR into the CMC */ + if (cmr == 0xF) { + /* FIXME: we need some state about the last codec mode */ + return 0; + } + + rc = get_amr_mode_idx(amr_mrc, cmr); + if (rc < 0) { + /* FIXME: we need some state about the last codec mode */ + LOGP(DRTP, LOGL_INFO, "RTP->L1: overriding CMR %u\n", cmr); + return 0; + } + return rc; +} + +static inline uint8_t set_cmi_mode_idx(const struct amr_multirate_conf *amr_mrc, + uint8_t cmi) +{ + int rc = get_amr_mode_idx(amr_mrc, cmi); + if (rc < 0) { + LOGP(DRTP, LOGL_ERROR, "AMR CMI %u not part of AMR MR set\n", + cmi); + return 0; + } + return rc; +} + +void amr_set_mode_pref(uint8_t *data, const struct amr_multirate_conf *amr_mrc, + uint8_t cmi, uint8_t cmr) +{ + data[0] = set_cmi_mode_idx(amr_mrc, cmi); + data[1] = set_cmr_mode_idx(amr_mrc, cmr); +} + /* parse a GSM 04.08 MultiRate Config IE (10.5.2.21aa) in a more * comfortable internal data structure */ int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc, @@ -42,7 +83,7 @@ int amr_parse_mr_conf(struct amr_multirate_conf *amr_mrc, int i, j = 0; if (mr_version != 1) { - LOGP(DRSL, LOGL_ERROR, "AMR Multirate Version %u unknonw\n", + LOGP(DRSL, LOGL_ERROR, "AMR Multirate Version %u unknown\n", mr_version); goto ret_einval; } diff --git a/src/common/bts.c b/src/common/bts.c index 42ac0967..e701b57f 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -40,6 +40,7 @@ #include <osmo-bts/abis.h> #include <osmo-bts/bts.h> #include <osmo-bts/bts_model.h> +#include <osmo-bts/dtx_dl_amr_fsm.h> #include <osmo-bts/pcu_if.h> #include <osmo-bts/rsl.h> #include <osmo-bts/oml.h> @@ -109,6 +110,7 @@ int bts_init(struct gsm_bts *bts) /* configurable via VTY */ btsb->paging_state = paging_init(btsb, 200, 0); btsb->ul_power_target = -75; /* dBm default */ + btsb->rtp_jitter_adaptive = false; /* configurable via OML */ btsb->load.ccch.load_ind_period = 112; @@ -180,6 +182,8 @@ int bts_init(struct gsm_bts *bts) INIT_LLIST_HEAD(&btsb->lc15.ceased_alarm_list); #endif + /* register DTX DL FSM */ + osmo_fsm_register(&dtx_dl_amr_fsm); return rc; } diff --git a/src/common/dtx_dl_amr_fsm.c b/src/common/dtx_dl_amr_fsm.c new file mode 100644 index 00000000..d903b0cf --- /dev/null +++ b/src/common/dtx_dl_amr_fsm.c @@ -0,0 +1,365 @@ +/* DTX DL AMR FSM */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * 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. + * + * 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/>. + * + */ + +#include <osmo-bts/dtx_dl_amr_fsm.h> +#include <osmo-bts/logging.h> + +void dtx_fsm_voice(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_VOICE: + case E_FACCH: + break; + case E_SID_F: + case E_SID_U: + osmo_fsm_inst_state_chg(fi, ST_SID_F1, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Inexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_sid_f1(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_SID_F: +/* FIXME: what shall we do if we get SID-FIRST _again_ (twice in a row)? + Was observed during testing, let's just ignore it for now */ + break; + case E_SID_U: + osmo_fsm_inst_state_chg(fi, ST_SID_U, 0, 0); + break; + case E_VOICE: + osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0); + break; + case E_FACCH: + osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0); + break; + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_SID_F2, 0, 0); + break; + case E_INHIB: + osmo_fsm_inst_state_chg(fi, ST_F1_INH, 0, 0); + break; + case E_ONSET: + osmo_fsm_inst_state_chg(fi, ST_ONSET_V, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_sid_f2(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_SID_U: + osmo_fsm_inst_state_chg(fi, ST_SID_U, 0, 0); + break; + case E_VOICE: + osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0); + break; + case E_FACCH: + osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0); + break; + case E_ONSET: + osmo_fsm_inst_state_chg(fi, ST_ONSET_V, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_f1_inh(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_F1_INH_REC, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_u_inh(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_U_INH_REC, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_f1_inh_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_u_inh_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_sid_upd(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_FACCH: + osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0); + break; + case E_VOICE: + osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0); + break; + case E_INHIB: + osmo_fsm_inst_state_chg(fi, ST_U_INH, 0, 0); + break; + case E_SID_U: + case E_SID_F: +/* FIXME: what shall we do if we get SID-FIRST _after_ sending SID-UPDATE? + Was observed during testing, let's just ignore it for now */ + break; + case E_ONSET: + osmo_fsm_inst_state_chg(fi, ST_ONSET_V, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_onset_v(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_ONSET_V_REC, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_onset_f(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_ONSET_F_REC, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_onset_v_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_onset_f_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_FACCH, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +void dtx_fsm_facch(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + switch (event) { + case E_SID_U: + case E_SID_F: + case E_FACCH: + break; + case E_VOICE: + osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0); + break; + case E_COMPL: + osmo_fsm_inst_state_chg(fi, ST_SID_F1, 0, 0); + break; + default: + LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event); + OSMO_ASSERT(0); + break; + } +} + +static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = { + /* default state for non-DTX and DTX when SPEECH is in progress */ + [ST_VOICE] = { + .in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_VOICE) | X(E_FACCH), + .out_state_mask = X(ST_SID_F1), + .name = "Voice", + .action = dtx_fsm_voice, + }, + /* SID-FIRST or SID-FIRST-P1 in case of AMR HR: + start of silence period (might be interrupted in case of AMR HR) */ + [ST_SID_F1]= { + .in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_VOICE) | X(E_FACCH) | X(E_COMPL) | X(E_INHIB) | X(E_ONSET), + .out_state_mask = X(ST_SID_U) | X(ST_VOICE) | X(ST_ONSET_F) | X(ST_SID_F2) | X(ST_F1_INH) | X(ST_ONSET_V), + .name = "SID-FIRST (P1)", + .action = dtx_fsm_sid_f1, + }, + /* SID-FIRST P2 (only for AMR HR): + actual start of silence period in case of AMR HR */ + [ST_SID_F2]= { + .in_event_mask = X(E_SID_U) | X(E_VOICE) | X(E_FACCH) | X(E_ONSET), + .out_state_mask = X(ST_SID_U) | X(ST_VOICE) | X(ST_ONSET_F) | X(ST_ONSET_V), + .name = "SID-FIRST (P2)", + .action = dtx_fsm_sid_f2, + }, + /* SID-FIRST Inhibited: incoming SPEECH (only for AMR HR) */ + [ST_F1_INH]= { + .in_event_mask = X(E_COMPL), + .out_state_mask = X(ST_F1_INH_REC), + .name = "SID-FIRST (Inh)", + .action = dtx_fsm_f1_inh, + }, + /* SID-UPDATE Inhibited: incoming SPEECH (only for AMR HR) */ + [ST_U_INH]= { + .in_event_mask = X(E_COMPL), + .out_state_mask = X(ST_U_INH_REC), + .name = "SID-UPDATE (Inh)", + .action = dtx_fsm_u_inh, + }, + /* SID-FIRST Inhibition recursion in progress: + Inhibit itself was already sent, now have to send the voice that caused it */ + [ST_F1_INH_REC]= { + .in_event_mask = X(E_COMPL), + .out_state_mask = X(ST_VOICE), + .name = "SID-FIRST (Inh, Rec)", + .action = dtx_fsm_f1_inh_rec, + }, + /* SID-UPDATE Inhibition recursion in progress: + Inhibit itself was already sent, now have to send the voice that caused it */ + [ST_U_INH_REC]= { + .in_event_mask = X(E_COMPL), + .out_state_mask = X(ST_VOICE), + .name = "SID-UPDATE (Inh, Rec)", + .action = dtx_fsm_u_inh_rec, + }, + /* Silence period with periodic comfort noise data updates */ + [ST_SID_U]= { + .in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_INHIB) | X(E_SID_U) | X(E_SID_F) | X(E_ONSET), + .out_state_mask = X(ST_ONSET_F) | X(ST_VOICE) | X(ST_U_INH) | X(ST_SID_U) | X(ST_ONSET_V), + .name = "SID-UPDATE", + .action = dtx_fsm_sid_upd, + }, + /* ONSET - end of silent period due to incoming SPEECH frame */ + [ST_ONSET_V]= { + .in_event_mask = X(E_COMPL), + .out_state_mask = X(ST_ONSET_V_REC), + .name = "ONSET (SPEECH)", + .action = dtx_fsm_onset_v, + }, + /* ONSET - end of silent period due to incoming FACCH frame */ + [ST_ONSET_F]= { + .in_event_mask = X(E_COMPL), + .out_state_mask = X(ST_ONSET_F_REC), + .name = "ONSET (FACCH)", + .action = dtx_fsm_onset_f, + }, + /* ONSET recursion in progress: + ONSET itself was already sent, now have to send the voice that caused it */ + [ST_ONSET_V_REC]= { + .in_event_mask = X(E_COMPL), + .out_state_mask = X(ST_VOICE), + .name = "ONSET (SPEECH, Rec)", + .action = dtx_fsm_onset_v_rec, + }, + /* ONSET recursion in progress: + ONSET itself was already sent, now have to send the data that caused it */ + [ST_ONSET_F_REC]= { + .in_event_mask = X(E_COMPL), + .out_state_mask = X(ST_FACCH), + .name = "ONSET (FACCH, Rec)", + .action = dtx_fsm_onset_f_rec, + }, + /* FACCH sending state: no SPEECH was observed before so once we're done + FSM should get back to silent period via SID-FIRST */ + [ST_FACCH]= { + .in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_COMPL) | X(E_SID_U) | X(E_SID_F), + .out_state_mask = X(ST_VOICE) | X(ST_SID_F1), + .name = "FACCH", + .action = dtx_fsm_facch, + }, +}; + +const struct value_string dtx_dl_amr_fsm_event_names[] = { + { E_VOICE, "Voice" }, + { E_ONSET, "ONSET" }, + { E_FACCH, "FACCH" }, + { E_COMPL, "Complete" }, + { E_INHIB, "Inhibit" }, + { E_SID_F, "SID-FIRST" }, + { E_SID_U, "SID-UPDATE" }, + { 0, NULL } +}; + +struct osmo_fsm dtx_dl_amr_fsm = { + .name = "DTX DL AMR FSM", + .states = dtx_dl_amr_fsm_states, + .num_states = ARRAY_SIZE(dtx_dl_amr_fsm_states), + .event_names = dtx_dl_amr_fsm_event_names, + .log_subsys = DL1C, +}; diff --git a/src/common/l1sap.c b/src/common/l1sap.c index a0d886f2..fa09ca84 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -39,6 +39,7 @@ #include <osmo-bts/logging.h> #include <osmo-bts/gsm_data.h> #include <osmo-bts/l1sap.h> +#include <osmo-bts/dtx_dl_amr_fsm.h> #include <osmo-bts/pcu_if.h> #include <osmo-bts/measurement.h> #include <osmo-bts/bts.h> @@ -73,25 +74,32 @@ get_active_lchan_by_chan_nr(struct gsm_bts_trx *trx, unsigned int chan_nr) static int l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap); -static uint32_t fn_ms_adj(uint32_t fn, uint32_t last_fn) +static uint32_t fn_ms_adj(uint32_t fn, const struct gsm_lchan *lchan) { - if (last_fn != 0xFFFFFFFF) { - uint32_t samples_passed = GSM_FN_TO_SAMPLES(fn - last_fn); + uint32_t samples_passed, r; + + /* don't adjust duration: + - when no DTX enabled at all + - for ONSET RTP packet to avoid timestamp gap with subsequent SPEECH + RTP packet*/ + if (lchan->rtp_tx_marker || + lchan->ts->trx->bts->dtxu == GSM48_DTX_SHALL_NOT_BE_USED) + return GSM_RTP_DURATION; + + if (lchan->tch.last_fn != LCHAN_FN_DUMMY) { + /* 12/13 frames usable for audio in TCH, + 160 samples per RTP packet, + 1 RTP packet per 4 frames */ + samples_passed = (fn - lchan->tch.last_fn) * 12 * 160 / (13 * 4); /* round number of samples to the nearest multiple of GSM_RTP_DURATION */ - uint32_t r = samples_passed + GSM_RTP_DURATION / 2; + r = samples_passed + GSM_RTP_DURATION / 2; r -= r % GSM_RTP_DURATION; return r; } return GSM_RTP_DURATION; } -static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { - 0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B -}; - /* allocate a msgb containing a osmo_phsap_prim + optional l2 data * in order to wrap femtobts header arround l2 data, there must be enough space * in front and behind data pointer */ @@ -210,15 +218,14 @@ const struct value_string gsmtap_sapi_names[] = { /* send primitive as gsmtap */ static int gsmtap_ph_data(struct osmo_phsap_prim *l1sap, uint8_t *chan_type, - uint8_t *tn, uint8_t *ss, uint32_t *fn, uint8_t **data, int *len) + uint8_t *ss, uint32_t fn, uint8_t **data, int *len, + uint8_t num_agch) { struct msgb *msg = l1sap->oph.msg; uint8_t chan_nr, link_id; *data = msg->data + sizeof(struct osmo_phsap_prim); *len = msg->len - sizeof(struct osmo_phsap_prim); - *fn = l1sap->u.data.fn; - *tn = L1SAP_CHAN2TS(l1sap->u.data.chan_nr); chan_nr = l1sap->u.data.chan_nr; link_id = l1sap->u.data.link_id; @@ -236,10 +243,9 @@ static int gsmtap_ph_data(struct osmo_phsap_prim *l1sap, uint8_t *chan_type, } else if (L1SAP_IS_CHAN_BCCH(chan_nr)) { *chan_type = GSMTAP_CHANNEL_BCCH; } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { -#warning Set BS_AG_BLKS_RES /* The sapi depends on DSP configuration, not * on the actual SYSTEM INFORMATION 3. */ - if (L1SAP_FN2CCCHBLOCK(*fn) >= 1) + if (L1SAP_FN2CCCHBLOCK(fn) >= num_agch) *chan_type = GSMTAP_CHANNEL_PCH; else *chan_type = GSMTAP_CHANNEL_AGCH; @@ -251,18 +257,16 @@ static int gsmtap_ph_data(struct osmo_phsap_prim *l1sap, uint8_t *chan_type, } static int gsmtap_pdch(struct osmo_phsap_prim *l1sap, uint8_t *chan_type, - uint8_t *tn, uint8_t *ss, uint32_t *fn, uint8_t **data, int *len) + uint8_t *ss, uint32_t fn, uint8_t **data, int *len) { struct msgb *msg = l1sap->oph.msg; *data = msg->data + sizeof(struct osmo_phsap_prim); *len = msg->len - sizeof(struct osmo_phsap_prim); - *fn = l1sap->u.data.fn; - *tn = L1SAP_CHAN2TS(l1sap->u.data.chan_nr); - if (L1SAP_IS_PTCCH(*fn)) { + if (L1SAP_IS_PTCCH(fn)) { *chan_type = GSMTAP_CHANNEL_PTCCH; - *ss = L1SAP_FN2PTCCHBLOCK(*fn); + *ss = L1SAP_FN2PTCCHBLOCK(fn); if (l1sap->oph.primitive == PRIM_OP_INDICATION) { if ((*data[0]) == 7) @@ -314,12 +318,14 @@ static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) uplink = 0; /* fall through */ case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_INDICATION): + fn = l1sap->u.data.fn; + tn = L1SAP_CHAN2TS(l1sap->u.data.chan_nr); if (ts_is_pdch(&trx->ts[tn])) - rc = gsmtap_pdch(l1sap, &chan_type, &tn, &ss, &fn, &data, - &len); + rc = gsmtap_pdch(l1sap, &chan_type, &ss, fn, &data, + &len); else - rc = gsmtap_ph_data(l1sap, &chan_type, &tn, &ss, &fn, - &data, &len); + rc = gsmtap_ph_data(l1sap, &chan_type, &ss, fn, &data, + &len, num_agch(trx, "GSMTAP")); break; case OSMO_PRIM(PRIM_PH_RACH, PRIM_OP_INDICATION): rc = gsmtap_ph_rach(l1sap, &chan_type, &tn, &ss, &fn, &data, @@ -530,6 +536,7 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, uint8_t *p, *si; struct lapdm_entity *le; struct osmo_phsap_prim pp; + bool dtxd_facch = false; int rc; chan_nr = rts_ind->chan_nr; @@ -584,9 +591,11 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, p[0] = lchan->ms_power_ctrl.current; p[1] = lchan->rqd_ta; le = &lchan->lapdm_ch.lapdm_acch; - } else + } else { + if (lchan->ts->trx->bts->dtxd) + dtxd_facch = true; le = &lchan->lapdm_ch.lapdm_dcch; - + } rc = lapdm_phsap_dequeue_prim(le, &pp); if (rc < 0) { if (L1SAP_IS_LINK_SACCH(link_id)) { @@ -612,15 +621,16 @@ static int l1sap_ph_rts_ind(struct gsm_bts_trx *trx, memcpy(p, pp.oph.msg->data, GSM_MACBLOCK_LEN); /* check if it is a RR CIPH MODE CMD. if yes, enable RX ciphering */ check_for_ciph_cmd(pp.oph.msg, lchan, chan_nr); + if (dtxd_facch) + dtx_dispatch(lchan, E_FACCH); } msgb_free(pp.oph.msg); } } else if (L1SAP_IS_CHAN_AGCH_PCH(chan_nr)) { p = msgb_put(msg, GSM_MACBLOCK_LEN); -#warning "TODO: Yet another assumption that BS_AG_BLKS_RES=1" - /* if CCCH block is 0, it is AGCH */ rc = bts_ccch_copy_msg(trx->bts, p, &g_time, - (L1SAP_FN2CCCHBLOCK(fn) < 1)); + (L1SAP_FN2CCCHBLOCK(fn) < + num_agch(trx, "PH-RTS-IND"))); if (rc <= 0) memcpy(p, fill_frame, GSM_MACBLOCK_LEN); } @@ -664,7 +674,8 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx, struct gsm_time g_time; struct gsm_lchan *lchan; uint8_t chan_nr, marker = 0; - uint32_t fn; + uint16_t seq; + uint32_t fn, timestamp; int rc; chan_nr = rts_ind->chan_nr; @@ -698,6 +709,10 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx, } else { /* Obtain RTP header Marker bit from control buffer */ marker = rtpmsg_marker_bit(resp_msg); + /* Obtain RTP header Sequence Number from control buffer */ + seq = rtpmsg_seq(resp_msg); + /* Obtain RTP header Timestamp from control buffer */ + timestamp = rtpmsg_ts(resp_msg); resp_msg->l2h = resp_msg->data; msgb_push(resp_msg, sizeof(*resp_l1sap)); @@ -921,7 +936,7 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, /* hand msg to RTP code for transmission */ if (lchan->abis_ip.rtp_socket) osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket, - msg->data, msg->len, fn_ms_adj(fn, lchan->tch.last_fn), lchan->rtp_tx_marker); + msg->data, msg->len, fn_ms_adj(fn, lchan), lchan->rtp_tx_marker); /* if loopback is enabled, also queue received RTP data */ if (lchan->loopback) { @@ -938,6 +953,9 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, } msgb_enqueue(&lchan->dl_tch_queue, msg); + + /* Return 1 to signal that we're still using msg and it should not be freed */ + return 1; } lchan->rtp_tx_marker = false; @@ -956,7 +974,7 @@ static int l1sap_ph_rach_ind(struct gsm_bts_trx *trx, DEBUGP(DL1P, "Rx PH-RA.ind"); - lc = &trx->ts[0].lchan[4].lapdm_ch; + lc = &trx->ts[0].lchan[CCCH_LCHAN].lapdm_ch; /* check for under/overflow / sign */ if (!check_acc_delay(rach_ind, btsb, &acc_delay)) { @@ -1073,7 +1091,8 @@ int l1sap_pdch_req(struct gsm_bts_trx_ts *ts, int is_ptcch, uint32_t fn, /*! \brief call-back function for incoming RTP */ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, - unsigned int rtp_pl_len, bool marker) + unsigned int rtp_pl_len, uint16_t seq_number, + uint32_t timestamp, bool marker) { struct gsm_lchan *lchan = rs->priv; struct msgb *msg, *tmp; @@ -1088,8 +1107,12 @@ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, /* Store RTP header Marker bit in control buffer */ rtpmsg_marker_bit(msg) = marker; + /* Store RTP header Sequence Number in control buffer */ + rtpmsg_seq(msg) = seq_number; + /* Store RTP header Timestamp in control buffer */ + rtpmsg_ts(msg) = timestamp; - /* make sure the queue doesn't get too long */ + /* make sure the queue doesn't get too long */ llist_for_each_entry(tmp, &lchan->dl_tch_queue, list) count++; while (count >= 2) { @@ -1154,14 +1177,29 @@ int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed * rc = l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_ACTIVATE, 0); if (rc) return -RSL_ERR_EQUIPMENT_FAIL; + + /* Init DTX DL FSM if necessary */ + //FIXME: only do it for AMR TCH/* + if (trx->bts->dtxd) + lchan->tch.dtx.dl_amr_fsm = osmo_fsm_inst_alloc(&dtx_dl_amr_fsm, + tall_bts_ctx, + lchan, + LOGL_DEBUG, + lchan->name); return 0; } int l1sap_chan_rel(struct gsm_bts_trx *trx, uint8_t chan_nr) { + struct gsm_lchan *lchan = get_lchan_by_chan_nr(trx, chan_nr); LOGP(DL1P, LOGL_INFO, "deactivating channel chan_nr=0x%02x trx=%d\n", chan_nr, trx->nr); + if (lchan->tch.dtx.dl_amr_fsm) { + osmo_fsm_inst_free(lchan->tch.dtx.dl_amr_fsm); + lchan->tch.dtx.dl_amr_fsm = NULL; + } + return l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, 0); } diff --git a/src/common/main.c b/src/common/main.c index bdd902b8..780556ab 100644 --- a/src/common/main.c +++ b/src/common/main.c @@ -228,16 +228,15 @@ int bts_main(int argc, char **argv) struct gsm_bts_role_bts *btsb; struct gsm_bts_trx *trx; struct e1inp_line *line; - void *tall_msgb_ctx; int rc, i; printf("((*))\n |\n / \\ OsmoBTS\n"); tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context"); - tall_msgb_ctx = talloc_pool(tall_bts_ctx, 100*1024); - msgb_set_talloc_ctx(tall_msgb_ctx); + msgb_talloc_ctx_init(tall_bts_ctx, 100*1024); bts_log_init(NULL); + vty_init(&bts_vty_info); handle_options(argc, argv); @@ -253,7 +252,6 @@ int bts_main(int argc, char **argv) exit(1); } } - vty_init(&bts_vty_info); e1inp_vty_init(); bts_vty_init(bts, &bts_log_info); diff --git a/src/common/msg_utils.c b/src/common/msg_utils.c index 967b10d9..9de9b6d6 100644 --- a/src/common/msg_utils.c +++ b/src/common/msg_utils.c @@ -17,18 +17,24 @@ * */ +#include <osmo-bts/dtx_dl_amr_fsm.h> #include <osmo-bts/msg_utils.h> #include <osmo-bts/logging.h> #include <osmo-bts/oml.h> +#include <osmo-bts/amr.h> +#include <osmo-bts/rsl.h> #include <osmocom/gsm/protocol/ipaccess.h> #include <osmocom/gsm/protocol/gsm_12_21.h> #include <osmocom/gsm/abis_nm.h> #include <osmocom/core/msgb.h> +#include <osmocom/core/fsm.h> #include <osmocom/trau/osmo_ortp.h> #include <arpa/inet.h> +#include <errno.h> +#define STI_BIT_MASK 16 static int check_fom(struct abis_om_hdr *omh, size_t len) { @@ -91,74 +97,214 @@ static int check_manuf(struct msgb *msg, struct abis_om_hdr *omh, size_t msg_siz void lchan_set_marker(bool t, struct gsm_lchan *lchan) { if (t) - lchan->tch.ul_sid = true; - else if (lchan->tch.ul_sid) { - lchan->tch.ul_sid = false; + lchan->tch.dtx.ul_sid = true; + else if (lchan->tch.dtx.ul_sid) { + lchan->tch.dtx.ul_sid = false; lchan->rtp_tx_marker = true; } } -/* store the last SID frame in lchan context */ -void save_last_sid(struct gsm_lchan *lchan, uint8_t *l1_payload, size_t length, - uint32_t fn, bool update) +/*! \brief Store the last SID frame in lchan context + * \param[in] lchan Logical channel on which we check scheduling + * \param[in] l1_payload buffer with SID data + * \param[in] length length of l1_payload + * \param[in] fn Frame Number for which we check scheduling + * \param[in] update 0 if SID_FIRST, 1 if SID_UPDATE, -1 if not AMR SID + */ +void dtx_cache_payload(struct gsm_lchan *lchan, const uint8_t *l1_payload, + size_t length, uint32_t fn, int update) { - size_t copy_len = OSMO_MIN(length + 1, - ARRAY_SIZE(lchan->tch.last_sid.buf)); - - lchan->tch.last_sid.len = copy_len; - lchan->tch.last_sid.fn = fn; - lchan->tch.last_sid.is_update = update; + size_t amr = (update < 0) ? 0 : 2, + copy_len = OSMO_MIN(length + 1, + ARRAY_SIZE(lchan->tch.dtx.cache) - amr); + + lchan->tch.dtx.len = copy_len + amr; + /* SID FIRST is special because it's both sent and cached: */ + if (update == 0) { + lchan->tch.dtx.is_update = false; /* Mark SID FIRST explicitly */ + /* for non-AMR case - always update FN for incoming SID FIRST */ + if (!amr || + (dtx_dl_amr_enabled(lchan) && + lchan->tch.dtx.dl_amr_fsm->state != ST_SID_U)) + lchan->tch.dtx.fn = fn; + /* for AMR case - do not update FN if SID FIRST arrives in a + middle of silence: this should not be happening according to + the spec */ + } - memcpy(lchan->tch.last_sid.buf, l1_payload, copy_len); + memcpy(lchan->tch.dtx.cache + amr, l1_payload, copy_len); } -/* repeat last SID if possible, returns SID length + 1 or 0 */ -/*! \brief Repeat last SID if possible in case of DTX +/*! \brief Check current state of DTX DL AMR FSM and dispatch necessary events * \param[in] lchan Logical channel on which we check scheduling - * \param[in] dst Buffer to copy last SID into - * \returns Number of bytes copied + 1 (to accommodate for extra byte with - * payload type) or 0 if there's nothing to copy + * \param[in] rtp_pl buffer with RTP data + * \param[in] rtp_pl_len length of rtp_pl + * \param[in] fn Frame Number for which we check scheduling + * \param[in] l1_payload buffer where CMR and CMI prefix should be added + * \param[in] marker RTP Marker bit + * \param[out] len Length of expected L1 payload + * \param[out] ft_out Frame Type to be populated after decoding + * \returns 0 in case of success; negative on error */ -uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn) +int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl, + size_t rtp_pl_len, uint32_t fn, uint8_t *l1_payload, + bool marker, uint8_t *len, uint8_t *ft_out) { - if (lchan->tch.last_sid.len) { - memcpy(dst, lchan->tch.last_sid.buf, lchan->tch.last_sid.len); - lchan->tch.last_sid.fn = fn; - return lchan->tch.last_sid.len + 1; + uint8_t cmr; + enum osmo_amr_type ft; + enum osmo_amr_quality bfi; + int8_t sti, cmi; + int rc; + + if (dtx_dl_amr_enabled(lchan)) { + if (lchan->type == GSM_LCHAN_TCH_H && + lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2 && !rtp_pl) { + *len = 3; /* SID-FIRST P1 -> P2 completion */ + memcpy(l1_payload, lchan->tch.dtx.cache, 2); + dtx_dispatch(lchan, E_SID_U); + return 0; + } } - LOGP(DL1C, LOGL_NOTICE, "Have to send %s frame on TCH but SID buffer " - "is empty - sent nothing\n", - get_value_string(gsm48_chan_mode_names, lchan->tch_mode)); + + if (!rtp_pl_len) + return -EBADMSG; + + rc = osmo_amr_rtp_dec(rtp_pl, rtp_pl_len, &cmr, &cmi, &ft, &bfi, &sti); + if (rc < 0) { + LOGP(DRTP, LOGL_ERROR, "failed to decode AMR RTP (length %zu)\n", + rtp_pl_len); + return rc; + } + + /* only needed for old sysmo firmware: */ + *ft_out = ft; + + /* CMI in downlink tells the L1 encoder which encoding function + * it will use, so we have to use the frame type */ + if (osmo_amr_is_speech(ft)) + cmi = ft; + + /* populate L1 payload with CMR/CMI - might be ignored by caller: */ + amr_set_mode_pref(l1_payload, &lchan->tch.amr_mr, cmi, cmr); + + /* populate DTX cache with CMR/CMI - overwrite cache which will be + either updated or invalidated by caller anyway: */ + amr_set_mode_pref(lchan->tch.dtx.cache, &lchan->tch.amr_mr, cmi, cmr); + *len = 3 + rtp_pl_len; + + /* DTX DL is not enabled, move along */ + if (!lchan->ts->trx->bts->dtxd) + return 0; + + if (osmo_amr_is_speech(ft)) { + /* AMR HR - Inhibition */ + if (lchan->type == GSM_LCHAN_TCH_H && marker && + lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1) + return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, + E_INHIB, (void *)lchan); + /* AMR FR & HR - generic */ + if (marker && (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1 || + lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2 || + lchan->tch.dtx.dl_amr_fsm->state == ST_SID_U )) + return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, + E_ONSET, (void *)lchan); + return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_VOICE, + (void *)lchan); + } + + if (ft == AMR_SID) { + if (lchan->tch.dtx.dl_amr_fsm->state == ST_VOICE) { + /* SID FIRST/UPDATE scheduling logic relies on SID FIRST + being sent first hence we have to force caching of SID + as FIRST regardless of actually decoded type */ + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, false); + return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, + E_SID_F, (void *)lchan); + } else + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, sti); + return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, + sti ? E_SID_U : E_SID_F, + (void *)lchan); + } + + if (ft != AMR_NO_DATA) { + LOGP(DRTP, LOGL_ERROR, "unsupported AMR FT 0x%02x\n", ft); + return -ENOTSUP; + } + + if (marker) + osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_VOICE, + (void *)lchan); + *len = 0; return 0; } +/* STI is located in payload byte 6, cache contains 2 byte prefix (CMR/CMI) + * STI set = SID UPDATE, STI unset = SID FIRST + */ +static inline void dtx_sti_set(struct gsm_lchan *lchan) +{ + lchan->tch.dtx.cache[6 + 2] |= STI_BIT_MASK; +} + +static inline void dtx_sti_unset(struct gsm_lchan *lchan) +{ + lchan->tch.dtx.cache[6 + 2] &= ~STI_BIT_MASK; +} + /*! \brief Check if enough time has passed since last SID (if any) to repeat it * \param[in] lchan Logical channel on which we check scheduling * \param[in] fn Frame Number for which we check scheduling * \returns true if transmission can be omitted, false otherwise */ -bool dtx_amr_sid_optional(const struct gsm_lchan *lchan, uint32_t fn) +static inline bool dtx_amr_sid_optional(struct gsm_lchan *lchan, uint32_t fn) { - /* Compute approx. time delta based on Fn duration */ - uint32_t delta = GSM_FN_TO_MS(fn - lchan->tch.last_sid.fn); + if (!dtx_dl_amr_enabled(lchan)) + return true; - /* according to 3GPP TS 26.093 A.5.1.1: */ - if (lchan->tch.last_sid.is_update) { - /* SID UPDATE should be repeated every 8th RTP frame */ - if (delta < GSM_RTP_FRAME_DURATION_MS * 8) + /* Compute approx. time delta x26 based on Fn duration */ + uint32_t dx26 = 120 * (fn - lchan->tch.dtx.fn); + + /* We're resuming after FACCH interruption */ + if (lchan->tch.dtx.dl_amr_fsm->state == ST_FACCH) { + /* force STI bit to 0 so cache is treated as SID FIRST */ + dtx_sti_unset(lchan); + lchan->tch.dtx.is_update = false; + /* check that this FN has not been used for FACCH message + already: we rely here on the order of RTS arrival from L1 - we + expect that PH-DATA.req ALWAYS comes before PH-TCH.req for the + same FN */ + if (lchan->tch.dtx.fn != LCHAN_FN_DUMMY) { + /* FACCH interruption is over */ + dtx_dispatch(lchan, E_COMPL); + return false; + } else + lchan->tch.dtx.fn = fn; + /* this FN was already used for FACCH or ONSET message so we just + prepare things for next one */ + return true; + } + + if (lchan->tch.dtx.dl_amr_fsm->state == ST_VOICE) + return true; + + /* according to 3GPP TS 26.093 A.5.1.1: + (*26) to avoid float math, add 1 FN tolerance (-120) */ + if (lchan->tch.dtx.is_update) { /* SID UPDATE: every 8th RTP frame */ + if (dx26 < GSM_RTP_FRAME_DURATION_MS * 8 * 26 - 120) return true; return false; } /* 3rd frame after SID FIRST should be SID UPDATE */ - if (delta < GSM_RTP_FRAME_DURATION_MS * 3) + if (dx26 < GSM_RTP_FRAME_DURATION_MS * 3 * 26 - 120) return true; return false; } -static inline bool fn_chk(const uint8_t *t, uint32_t fn) +static inline bool fn_chk(const uint8_t *t, uint32_t fn, uint8_t len) { uint8_t i; - for (i = 0; i < ARRAY_SIZE(t); i++) + for (i = 0; i < len; i++) if (fn % 104 == t[i]) return false; return true; @@ -169,7 +315,7 @@ static inline bool fn_chk(const uint8_t *t, uint32_t fn) * \param[in] fn Frame Number for which we check scheduling * \returns true if transmission can be omitted, false otherwise */ -bool dtx_sched_optional(struct gsm_lchan *lchan, uint32_t fn) +static inline bool dtx_sched_optional(struct gsm_lchan *lchan, uint32_t fn) { /* According to 3GPP TS 45.008 § 8.3: */ static const uint8_t f[] = { 52, 53, 54, 55, 56, 57, 58, 59 }, @@ -177,13 +323,128 @@ bool dtx_sched_optional(struct gsm_lchan *lchan, uint32_t fn) h1[] = { 14, 16, 18, 20, 66, 68, 70, 72 }; if (lchan->tch_mode == GSM48_CMODE_SPEECH_V1) { if (lchan->type == GSM_LCHAN_TCH_F) - return fn_chk(f, fn); + return fn_chk(f, fn, ARRAY_SIZE(f)); else - return fn_chk(lchan->nr ? h1 : h0, fn); + return fn_chk(lchan->nr ? h1 : h0, fn, + lchan->nr ? ARRAY_SIZE(h1) : + ARRAY_SIZE(h0)); } return false; } +/*! \brief Check if DTX DL AMR is enabled for a given lchan (it have proper type, + * FSM is allocated etc.) + * \param[in] lchan Logical channel on which we check scheduling + * \returns true if DTX DL AMR is enabled, false otherwise + */ +bool dtx_dl_amr_enabled(const struct gsm_lchan *lchan) +{ + if (lchan->ts->trx->bts->dtxd && + lchan->tch.dtx.dl_amr_fsm && + lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) + return true; + return false; +} + +/*! \brief Check if DTX DL AMR FSM state is recursive: requires secondary + * response to a single RTS request from L1. + * \param[in] lchan Logical channel on which we check scheduling + * \returns true if DTX DL AMR FSM state is recursive, false otherwise + */ +bool dtx_recursion(const struct gsm_lchan *lchan) +{ + if (!dtx_dl_amr_enabled(lchan)) + return false; + + if (lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH || + lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH || + lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_F || + lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_V || + lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_F_REC || + lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_V_REC) + return true; + + return false; +} + +/*! \brief Send signal to FSM: with proper check if DIX is enabled for this lchan + * \param[in] lchan Logical channel on which we check scheduling + * \param[in] e DTX DL AMR FSM Event + */ +void dtx_dispatch(struct gsm_lchan *lchan, enum dtx_dl_amr_fsm_events e) +{ + if (dtx_dl_amr_enabled(lchan)) + osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, e, + (void *)lchan); +} + +/*! \brief Send internal signal to FSM: check that DTX is enabled for this chan, + * check that current FSM and lchan states are permitting such signal. + * Note: this should be the only way to dispatch E_COMPL to FSM from + * BTS code. + * \param[in] lchan Logical channel on which we check scheduling + */ +void dtx_int_signal(struct gsm_lchan *lchan) +{ + if (!dtx_dl_amr_enabled(lchan)) + return; + + if ((lchan->type == GSM_LCHAN_TCH_H && + lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1) || + dtx_recursion(lchan)) + dtx_dispatch(lchan, E_COMPL); +} + +/*! \brief Repeat last SID if possible in case of DTX + * \param[in] lchan Logical channel on which we check scheduling + * \param[in] dst Buffer to copy last SID into + * \returns Number of bytes copied + 1 (to accommodate for extra byte with + * payload type), 0 if there's nothing to copy + */ +uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn) +{ + /* FIXME: add EFR support */ + if (lchan->tch_mode == GSM48_CMODE_SPEECH_EFR) + return 0; + + if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) { + if (dtx_sched_optional(lchan, fn)) + return 0; + } else + if (dtx_amr_sid_optional(lchan, fn)) + return 0; + + if (lchan->tch.dtx.len) { + if (dtx_dl_amr_enabled(lchan)) { + if ((lchan->type == GSM_LCHAN_TCH_H && + lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2) || + (lchan->type == GSM_LCHAN_TCH_F && + lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1)) { + /* advance FSM in case we've just sent SID FIRST + to restore silence after FACCH interruption */ + osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, + E_SID_U, (void *)lchan); + dtx_sti_unset(lchan); + } else if (lchan->tch.dtx.dl_amr_fsm->state == + ST_SID_U) { + /* enforce SID UPDATE for next repetition: it + might have been altered by FACCH handling */ + dtx_sti_set(lchan); + lchan->tch.dtx.is_update = true; + } + } + memcpy(dst, lchan->tch.dtx.cache, lchan->tch.dtx.len); + lchan->tch.dtx.fn = fn; + return lchan->tch.dtx.len + 1; + } + + LOGP(DL1C, LOGL_DEBUG, "Have to send %s frame on TCH but SID buffer " + "is empty - sent nothing\n", + get_value_string(gsm48_chan_mode_names, lchan->tch_mode)); + + return 0; +} + /** * Return 0 in case the IPA structure is okay and in this * case the l2h will be set to the beginning of the data. diff --git a/src/common/oml.c b/src/common/oml.c index d6468d81..43017fb3 100644 --- a/src/common/oml.c +++ b/src/common/oml.c @@ -843,7 +843,7 @@ int conf_lchans_as_pchan(struct gsm_bts_trx_ts *ts, } /* fallthrough */ case GSM_PCHAN_CCCH: - lchan = &ts->lchan[4]; + lchan = &ts->lchan[CCCH_LCHAN]; lchan->type = GSM_LCHAN_CCCH; break; case GSM_PCHAN_TCH_F: diff --git a/src/common/paging.c b/src/common/paging.c index f75f12dc..957d609b 100644 --- a/src/common/paging.c +++ b/src/common/paging.c @@ -538,12 +538,6 @@ static int paging_signal_cbfn(unsigned int subsys, unsigned int signal, void *hd struct paging_state *ps = btsb->paging_state; struct gsm48_system_information_type_3 *si3 = (void *) bts->si_buf[SYSINFO_TYPE_3]; -#warning "TODO: Remove this when setting u8NbrOfAgch is implemented properly" - if (si3->control_channel_desc.bs_ag_blks_res != 1) - LOGP(DPAG, LOGL_ERROR, - "Paging: BS_AG_BLKS_RES = %d != 1 not fully supported\n", - si3->control_channel_desc.bs_ag_blks_res); - paging_si_update(ps, &si3->control_channel_desc); } return 0; diff --git a/src/common/rsl.c b/src/common/rsl.c index 49b01586..ea6b482a 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -296,6 +296,14 @@ static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg) LOGP(DRSL, LOGL_INFO, " Rx RSL BCCH INFO (SI%s)\n", get_value_string(osmo_sitype_strs, osmo_si)); + if (SYSINFO_TYPE_3 == osmo_si && trx->nr == 0 && + num_agch(trx, "RSL") != 1) { + lchan_deactivate(&trx->bts->c0->ts[0].lchan[CCCH_LCHAN]); + /* will be reactivated by sapi_deactivate_cb() */ + trx->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind = + LCHAN_REL_ACT_REACT; + } + if (SYSINFO_TYPE_2quater == osmo_si) { si2q = (struct gsm48_system_information_type_2quater *) bts->si_buf[SYSINFO_TYPE_2quater]; @@ -1607,21 +1615,34 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg) return tx_ipac_XXcx_nack(lchan, RSL_ERR_MAND_IE_ERROR, 0, dch->c.msg_type); - /* any of these can be NULL!! */ - speech_mode = TLVP_VAL(&tp, RSL_IE_IPAC_SPEECH_MODE); - payload_type = TLVP_VAL(&tp, RSL_IE_IPAC_RTP_PAYLOAD); - payload_type2 = TLVP_VAL(&tp, RSL_IE_IPAC_RTP_PAYLOAD2); - - if (TLVP_PRESENT(&tp, RSL_IE_IPAC_REMOTE_IP)) + if (TLVP_PRESENT(&tp, RSL_IE_IPAC_REMOTE_IP)) { connect_ip = tlvp_val32_unal(&tp, RSL_IE_IPAC_REMOTE_IP); + LOGP(DRSL, LOGL_NOTICE, "connect_ip %d \n", connect_ip ); + } else LOGP(DRSL, LOGL_NOTICE, "CRCX does not specify a remote IP\n"); - if (TLVP_PRESENT(&tp, RSL_IE_IPAC_REMOTE_PORT)) + if (TLVP_PRESENT(&tp, RSL_IE_IPAC_REMOTE_PORT)) { connect_port = tlvp_val16_unal(&tp, RSL_IE_IPAC_REMOTE_PORT); + LOGP(DRSL, LOGL_NOTICE, "connect_port %d \n", connect_port ); + } else LOGP(DRSL, LOGL_NOTICE, "CRCX does not specify a remote port\n"); + speech_mode = TLVP_VAL(&tp, RSL_IE_IPAC_SPEECH_MODE); + if (speech_mode) + LOGP(DRSL, LOGL_NOTICE, "speech mode: %d\n", *speech_mode); + else + LOGP(DRSL, LOGL_NOTICE, "speech mode: none\n"); + + payload_type = TLVP_VAL(&tp, RSL_IE_IPAC_RTP_PAYLOAD); + if (payload_type) + LOGP(DRSL, LOGL_NOTICE, "payload type: %d\n",*payload_type); + else + LOGP(DRSL, LOGL_NOTICE, "payload type: none\n"); + + payload_type2 = TLVP_VAL(&tp, RSL_IE_IPAC_RTP_PAYLOAD2); + if (dch->c.msg_type == RSL_MT_IPAC_CRCX && connect_ip && connect_port) inc_ip_port = 1; @@ -1648,6 +1669,7 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg) /* FIXME: select default value depending on speech_mode */ //if (!payload_type) + lchan->tch.last_fn = LCHAN_FN_DUMMY; lchan->abis_ip.rtp_socket = osmo_rtp_socket_create(lchan->ts->trx, OSMO_RTP_F_POLL); if (!lchan->abis_ip.rtp_socket) { @@ -1662,9 +1684,19 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg) return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL, inc_ip_port, dch->c.msg_type); } - osmo_rtp_socket_set_param(lchan->abis_ip.rtp_socket, - OSMO_RTP_P_JITBUF, - btsb->rtp_jitter_buf_ms); + rc = osmo_rtp_socket_set_param(lchan->abis_ip.rtp_socket, + btsb->rtp_jitter_adaptive ? + OSMO_RTP_P_JIT_ADAP : + OSMO_RTP_P_JITBUF, + btsb->rtp_jitter_buf_ms); + if (rc < 0) + LOGP(DRSL, LOGL_ERROR, + "%s IPAC Failed to set RTP socket parameters: %s\n", + gsm_lchan_name(lchan), strerror(-rc)); + else + LOGP(DRSL, LOGL_INFO, + "%s IPAC set RTP socket parameters: %d\n", + gsm_lchan_name(lchan), rc); lchan->abis_ip.rtp_socket->priv = lchan; lchan->abis_ip.rtp_socket->rx_cb = &l1sap_rtp_rx_cb; @@ -2503,9 +2535,9 @@ static int rsl_tx_meas_res(struct gsm_lchan *lchan, uint8_t *l3, int l3_len) msgb_tv_put(msg, RSL_IE_MEAS_RES_NR, lchan->meas.res_nr++); size_t ie_len = gsm0858_rsl_ul_meas_enc(&lchan->meas.ul_res, - lchan->tch.dtxd_active, + lchan->tch.dtx.dl_active, meas_res); - lchan->tch.dtxd_active = false; + lchan->tch.dtx.dl_active = false; if (ie_len >= 3) { msgb_tlv_put(msg, RSL_IE_UPLINK_MEAS, ie_len, meas_res); lchan->meas.flags &= ~LC_UL_M_F_RES_VALID; @@ -2945,6 +2977,12 @@ static int rsl_rx_ipaccess(struct gsm_bts_trx *trx, struct msgb *msg) return ret; } +int lchan_deactivate(struct gsm_lchan *lchan) +{ + lchan->ciph_state = 0; + return bts_model_lchan_deactivate(lchan); +} + int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg) { struct abis_rsl_common_hdr *rslh = msgb_l2(msg); diff --git a/src/common/scheduler.c b/src/common/scheduler.c index ec66cfc4..fd5c5840 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -116,44 +116,44 @@ const ubit_t _sched_sch_train[64] = { */ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = { - { 0, TRXC_IDLE, 0, 0, "IDLE", NULL, tx_idle_fn, NULL, 1 }, - { 0, TRXC_FCCH, 0, 0, "FCCH", NULL, tx_fcch_fn, NULL, 1 }, - { 0, TRXC_SCH, 0, 0, "SCH", NULL, tx_sch_fn, NULL, 1 }, - { 0, TRXC_BCCH, 0x80, 0x00, "BCCH", rts_data_fn, tx_data_fn, NULL, 1 }, - { 0, TRXC_RACH, 0x88, 0x00, "RACH", NULL, NULL, rx_rach_fn, 1 }, - { 0, TRXC_CCCH, 0x90, 0x00, "CCCH", rts_data_fn, tx_data_fn, NULL, 1 }, - { 0, TRXC_TCHF, 0x08, 0x00, "TCH/F", rts_tchf_fn, tx_tchf_fn, rx_tchf_fn, 0 }, - { 0, TRXC_TCHH_0, 0x10, 0x00, "TCH/H(0)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 }, - { 0, TRXC_TCHH_1, 0x18, 0x00, "TCH/H(1)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 }, - { 0, TRXC_SDCCH4_0, 0x20, 0x00, "SDCCH/4(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH4_1, 0x28, 0x00, "SDCCH/4(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH4_2, 0x30, 0x00, "SDCCH/4(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH4_3, 0x38, 0x00, "SDCCH/4(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_0, 0x40, 0x00, "SDCCH/8(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_1, 0x48, 0x00, "SDCCH/8(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_2, 0x50, 0x00, "SDCCH/8(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_3, 0x58, 0x00, "SDCCH/8(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_4, 0x60, 0x00, "SDCCH/8(4)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_5, 0x68, 0x00, "SDCCH/8(5)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_6, 0x70, 0x00, "SDCCH/8(6)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_7, 0x78, 0x00, "SDCCH/8(7)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCHTF, 0x08, 0x40, "SACCH/TF", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCHTH_0, 0x10, 0x40, "SACCH/TH(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCHTH_1, 0x18, 0x40, "SACCH/TH(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH4_0, 0x20, 0x40, "SACCH/4(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH4_1, 0x28, 0x40, "SACCH/4(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH4_2, 0x30, 0x40, "SACCH/4(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH4_3, 0x38, 0x40, "SACCH/4(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_0, 0x40, 0x40, "SACCH/8(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_1, 0x48, 0x40, "SACCH/8(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_2, 0x50, 0x40, "SACCH/8(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_3, 0x58, 0x40, "SACCH/8(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_4, 0x60, 0x40, "SACCH/8(4)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_5, 0x68, 0x40, "SACCH/8(5)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_6, 0x70, 0x40, "SACCH/8(6)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_7, 0x78, 0x40, "SACCH/8(7)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 1, TRXC_PDTCH, 0x08, 0x00, "PDTCH", rts_data_fn, tx_pdtch_fn, rx_pdtch_fn, 0 }, - { 1, TRXC_PTCCH, 0x08, 0x00, "PTCCH", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_IDLE, 0, LID_DEDIC, "IDLE", NULL, tx_idle_fn, NULL, 1 }, + { 0, TRXC_FCCH, 0, LID_DEDIC, "FCCH", NULL, tx_fcch_fn, NULL, 1 }, + { 0, TRXC_SCH, 0, LID_DEDIC, "SCH", NULL, tx_sch_fn, NULL, 1 }, + { 0, TRXC_BCCH, 0x80, LID_DEDIC, "BCCH", rts_data_fn, tx_data_fn, NULL, 1 }, + { 0, TRXC_RACH, 0x88, LID_DEDIC, "RACH", NULL, NULL, rx_rach_fn, 1 }, + { 0, TRXC_CCCH, 0x90, LID_DEDIC, "CCCH", rts_data_fn, tx_data_fn, NULL, 1 }, + { 0, TRXC_TCHF, 0x08, LID_DEDIC, "TCH/F", rts_tchf_fn, tx_tchf_fn, rx_tchf_fn, 0 }, + { 0, TRXC_TCHH_0, 0x10, LID_DEDIC, "TCH/H(0)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 }, + { 0, TRXC_TCHH_1, 0x18, LID_DEDIC, "TCH/H(1)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 }, + { 0, TRXC_SDCCH4_0, 0x20, LID_DEDIC, "SDCCH/4(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH4_1, 0x28, LID_DEDIC, "SDCCH/4(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH4_2, 0x30, LID_DEDIC, "SDCCH/4(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH4_3, 0x38, LID_DEDIC, "SDCCH/4(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_0, 0x40, LID_DEDIC, "SDCCH/8(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_1, 0x48, LID_DEDIC, "SDCCH/8(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_2, 0x50, LID_DEDIC, "SDCCH/8(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_3, 0x58, LID_DEDIC, "SDCCH/8(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_4, 0x60, LID_DEDIC, "SDCCH/8(4)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_5, 0x68, LID_DEDIC, "SDCCH/8(5)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_6, 0x70, LID_DEDIC, "SDCCH/8(6)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_7, 0x78, LID_DEDIC, "SDCCH/8(7)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCHTF, 0x08, LID_SACCH, "SACCH/TF", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCHTH_0, 0x10, LID_SACCH, "SACCH/TH(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCHTH_1, 0x18, LID_SACCH, "SACCH/TH(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH4_0, 0x20, LID_SACCH, "SACCH/4(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH4_1, 0x28, LID_SACCH, "SACCH/4(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH4_2, 0x30, LID_SACCH, "SACCH/4(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH4_3, 0x38, LID_SACCH, "SACCH/4(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_0, 0x40, LID_SACCH, "SACCH/8(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_1, 0x48, LID_SACCH, "SACCH/8(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_2, 0x50, LID_SACCH, "SACCH/8(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_3, 0x58, LID_SACCH, "SACCH/8(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_4, 0x60, LID_SACCH, "SACCH/8(4)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_5, 0x68, LID_SACCH, "SACCH/8(5)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_6, 0x70, LID_SACCH, "SACCH/8(6)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_7, 0x78, LID_SACCH, "SACCH/8(7)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 1, TRXC_PDTCH, 0x08, LID_DEDIC, "PDTCH", rts_data_fn, tx_pdtch_fn, rx_pdtch_fn, 0 }, + { 1, TRXC_PTCCH, 0x08, LID_DEDIC, "PTCCH", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, }; @@ -166,6 +166,9 @@ int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx) uint8_t tn; unsigned int i; + if (!trx) + return -EINVAL; + l1t->trx = trx; LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr); diff --git a/src/common/sysinfo.c b/src/common/sysinfo.c index ee42da25..d0a476d3 100644 --- a/src/common/sysinfo.c +++ b/src/common/sysinfo.c @@ -22,6 +22,7 @@ #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/sysinfo.h> +#include <osmo-bts/logging.h> #include <osmo-bts/gsm_data.h> #define BTS_HAS_SI(bts, sinum) ((bts)->si_valid & (1 << sinum)) @@ -132,6 +133,19 @@ uint8_t *bts_sysinfo_get(struct gsm_bts *bts, struct gsm_time *g_time) return NULL; } +uint8_t num_agch(struct gsm_bts_trx *trx, const char * arg) +{ + struct gsm_bts *b = trx->bts; + struct gsm48_system_information_type_3 *si3; + if (BTS_HAS_SI(b, SYSINFO_TYPE_3)) { + si3 = GSM_BTS_SI(b, SYSINFO_TYPE_3); + return si3->control_channel_desc.bs_ag_blks_res; + } + LOGP(DL1P, LOGL_ERROR, "%s: Unable to determine actual BS_AG_BLKS_RES " + "value as SI3 is not available yet, fallback to 1\n", arg); + return 1; +} + uint8_t *lchan_sacch_get(struct gsm_lchan *lchan) { uint32_t tmp; diff --git a/src/common/vty.c b/src/common/vty.c index b4aa6166..b48afa43 100644 --- a/src/common/vty.c +++ b/src/common/vty.c @@ -179,13 +179,13 @@ struct gsm_network *gsmnet_from_vty(struct vty *v) static struct cmd_node bts_node = { BTS_NODE, - "%s(bts)#", + "%s(bts)# ", 1, }; static struct cmd_node trx_node = { TRX_NODE, - "%s(trx)#", + "%s(trx)# ", 1, }; @@ -276,8 +276,10 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " ipa unit-id %u %u%s", bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE); vty_out(vty, " oml remote-ip %s%s", btsb->bsc_oml_host, VTY_NEWLINE); - vty_out(vty, " rtp jitter-buffer %u%s", btsb->rtp_jitter_buf_ms, - VTY_NEWLINE); + vty_out(vty, " rtp jitter-buffer %u", btsb->rtp_jitter_buf_ms); + if (btsb->rtp_jitter_adaptive) + vty_out(vty, " adaptive"); + vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, " paging queue-size %u%s", paging_get_queue_max(btsb->paging_state), VTY_NEWLINE); vty_out(vty, " paging lifetime %u%s", paging_get_lifetime(btsb->paging_state), @@ -487,13 +489,15 @@ DEFUN_HIDDEN(cfg_bts_rtp_bind_ip, DEFUN(cfg_bts_rtp_jitbuf, cfg_bts_rtp_jitbuf_cmd, - "rtp jitter-buffer <0-10000>", + "rtp jitter-buffer <0-10000> [adaptive]", RTP_STR "RTP jitter buffer\n" "jitter buffer in ms\n") { struct gsm_bts *bts = vty->index; struct gsm_bts_role_bts *btsb = bts_role_bts(bts); btsb->rtp_jitter_buf_ms = atoi(argv[0]); + if (argc > 1) + btsb->rtp_jitter_adaptive = true; return CMD_SUCCESS; } @@ -869,6 +873,7 @@ DEFUN(cfg_trx_gsmtap_sapi, cfg_trx_gsmtap_sapi_cmd, int sapi; sapi = get_string_value(gsmtap_sapi_names, argv[0]); + OSMO_ASSERT(sapi >= 0); if (sapi == GSMTAP_CHANNEL_ACCH) gsmtap_sapi_acch = 1; @@ -884,6 +889,7 @@ DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd, int sapi; sapi = get_string_value(gsmtap_sapi_names, argv[0]); + OSMO_ASSERT(sapi >= 0); if (sapi == GSMTAP_CHANNEL_ACCH) gsmtap_sapi_acch = 0; @@ -895,13 +901,13 @@ DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd, static struct cmd_node phy_node = { PHY_NODE, - "%s(phy)#", + "%s(phy)# ", 1, }; static struct cmd_node phy_inst_node = { PHY_INST_NODE, - "%s(phy-inst)#", + "%s(phy-inst)# ", 1, }; @@ -1001,7 +1007,8 @@ DEFUN(bts_t_t_l_jitter_buf, { struct gsm_network *net = gsmnet_from_vty(vty); struct gsm_lchan *lchan; - int jitbuf_ms = atoi(argv[4]); + struct gsm_bts_role_bts *btsb; + int jitbuf_ms = atoi(argv[4]), rc; lchan = resolve_lchan(net, argv, 0); if (!lchan) { @@ -1013,8 +1020,16 @@ DEFUN(bts_t_t_l_jitter_buf, VTY_NEWLINE); return CMD_WARNING; } - osmo_rtp_socket_set_param(lchan->abis_ip.rtp_socket, - OSMO_RTP_P_JITBUF, jitbuf_ms); + btsb = bts_role_bts(lchan->ts->trx->bts); + rc = osmo_rtp_socket_set_param(lchan->abis_ip.rtp_socket, + btsb->rtp_jitter_adaptive ? + OSMO_RTP_P_JIT_ADAP : OSMO_RTP_P_JITBUF, + jitbuf_ms); + if (rc < 0) + vty_out(vty, "%% error setting jitter parameters: %s%s", + strerror(-rc), VTY_NEWLINE); + else + vty_out(vty, "%% jitter parameters set: %d%s", rc, VTY_NEWLINE); return CMD_SUCCESS; } @@ -1055,6 +1070,64 @@ DEFUN(no_bts_t_t_l_loopback, return CMD_SUCCESS; } +DEFUN(bts_t_t_l_activate, + bts_t_t_l_activate_cmd, + "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> activate", + BTS_T_T_L_STR "Manually activate a logical channel (FOR TEST USE ONLY! Will disrupt normal operation of the channel)\n") +{ + struct gsm_network *net = gsmnet_from_vty(vty); + struct gsm_lchan *lchan; + int rc; + + lchan = resolve_lchan(net, argv, 0); + if (!lchan) { + vty_out(vty, "%% can't find BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* set channel configuration */ + /* TODO: let user choose speech mode */ + lchan->tch_mode = GSM48_CMODE_SPEECH_V1; + lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH; + /* no encryption */ + memset(&lchan->encr, 0, sizeof(lchan->encr)); + + /* activate the channel */ + lchan->rel_act_kind = LCHAN_REL_ACT_OML; + rc = l1sap_chan_act(lchan->ts->trx, gsm_lchan2chan_nr(lchan), NULL); + if (rc < 0) { + vty_out(vty, "%% can't activate channel%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN(bts_t_t_l_deactivate, + bts_t_t_l_deactivate_cmd, + "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> deactivate", + BTS_T_T_L_STR "Deactivate a manually activated channel (DO NOT apply to channels activated by BSC or NITB)\n") +{ + struct gsm_network *net = gsmnet_from_vty(vty); + struct gsm_lchan *lchan; + int rc; + + lchan = resolve_lchan(net, argv, 0); + if (!lchan) { + vty_out(vty, "%% can't find BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + /* deactivate the channel */ + rc = l1sap_chan_rel(lchan->ts->trx, gsm_lchan2chan_nr(lchan)); + if (rc < 0) { + vty_out(vty, "%% can't deactivate channel%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat) { cfg_trx_gsmtap_sapi_cmd.string = vty_cmd_string_from_valstr(bts, gsmtap_sapi_names, @@ -1113,6 +1186,8 @@ int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat) install_element(ENABLE_NODE, &bts_t_t_l_jitter_buf_cmd); install_element(ENABLE_NODE, &bts_t_t_l_loopback_cmd); install_element(ENABLE_NODE, &no_bts_t_t_l_loopback_cmd); + install_element(ENABLE_NODE, &bts_t_t_l_activate_cmd); + install_element(ENABLE_NODE, &bts_t_t_l_deactivate_cmd); install_element(CONFIG_NODE, &cfg_phy_cmd); install_node(&phy_node, config_write_phy); diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c index 8cb16e18..1f2d7f22 100644 --- a/src/osmo-bts-litecell15/l1_if.c +++ b/src/osmo-bts-litecell15/l1_if.c @@ -53,6 +53,8 @@ #include <osmo-bts/cbch.h> #include <osmo-bts/bts_model.h> #include <osmo-bts/l1sap.h> +#include <osmo-bts/msg_utils.h> +#include <osmo-bts/dtx_dl_amr_fsm.h> #include <nrw/litecell15/litecell15.h> #include <nrw/litecell15/gsml1prim.h> @@ -287,12 +289,6 @@ empty_req_from_rts_ind(GsmL1_Prim_t *l1p, return empty_req; } -static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { - 0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B -}; - /* fill PH-DATA.req from l1sap primitive */ static GsmL1_PhDataReq_t * data_req_from_l1sap(GsmL1_Prim_t *l1p, struct lc15l1_hdl *fl1, @@ -337,10 +333,11 @@ empty_req_from_l1sap(GsmL1_Prim_t *l1p, struct lc15l1_hdl *fl1, } static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, - struct osmo_phsap_prim *l1sap) + struct osmo_phsap_prim *l1sap, bool use_cache) { struct lc15l1_hdl *fl1 = trx_lc15l1_hdl(trx); struct msgb *l1msg = l1p_msgb_alloc(); + struct gsm_lchan *lchan; uint32_t u32Fn; uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi = 0; uint8_t chan_nr, link_id; @@ -359,6 +356,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, u32Fn = l1sap->u.data.fn; u8Tn = L1SAP_CHAN2TS(chan_nr); subCh = 0x1f; + lchan = get_lchan_by_chan_nr(trx, chan_nr); if (L1SAP_IS_LINK_SACCH(link_id)) { sapi = GsmL1_Sapi_Sacch; if (!L1SAP_IS_CHAN_TCHF(chan_nr)) @@ -400,6 +398,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, LOGP(DL1C, LOGL_NOTICE, "unknown prim %d op %d " "chan_nr %d link_id %d\n", l1sap->oph.primitive, l1sap->oph.operation, chan_nr, link_id); + msgb_free(l1msg); return -EINVAL; } @@ -407,14 +406,50 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, if (len) { /* data request */ GsmL1_Prim_t *l1p = msgb_l1prim(l1msg); - data_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr, len); - - OSMO_ASSERT(msgb_l2len(msg) <= sizeof(l1p->u.phDataReq.msgUnitParam.u8Buffer)); - memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h, msgb_l2len(msg)); + if (use_cache) + memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, + lchan->tch.dtx.facch, msgb_l2len(msg)); + else if (dtx_dl_amr_enabled(lchan) && + lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_F) { + if (sapi == GsmL1_Sapi_FacchF) { + sapi = GsmL1_Sapi_TchF; + } + if (sapi == GsmL1_Sapi_FacchH) { + sapi = GsmL1_Sapi_TchH; + } + if (sapi == GsmL1_Sapi_TchH || sapi == GsmL1_Sapi_TchF) { + /* FACCH interruption of DTX silence */ + /* cache FACCH data */ + memcpy(lchan->tch.dtx.facch, msg->l2h, + msgb_l2len(msg)); + /* prepare ONSET message */ + l1p->u.phDataReq.msgUnitParam.u8Buffer[0] = + GsmL1_TchPlType_Amr_Onset; + /* ignored CMR/CMI pair */ + l1p->u.phDataReq.msgUnitParam.u8Buffer[1] = 0; + l1p->u.phDataReq.msgUnitParam.u8Buffer[2] = 0; + /* update length */ + data_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, + subCh, u8BlockNbr, 3); + /* update FN so it can be checked by TCH silence + resume handler */ + lchan->tch.dtx.fn = LCHAN_FN_DUMMY; + } + } else if (dtx_dl_amr_enabled(lchan) && + lchan->tch.dtx.dl_amr_fsm->state == ST_FACCH) { + /* update FN so it can be checked by TCH silence + resume handler */ + lchan->tch.dtx.fn = LCHAN_FN_DUMMY; + } + else { + OSMO_ASSERT(msgb_l2len(msg) <= sizeof(l1p->u.phDataReq.msgUnitParam.u8Buffer)); + memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h, + msgb_l2len(msg)); + } LOGP(DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n", - osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, - l1p->u.phDataReq.msgUnitParam.u8Size)); + osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, + l1p->u.phDataReq.msgUnitParam.u8Size)); } else { /* empty frame */ GsmL1_Prim_t *l1p = msgb_l1prim(l1msg); @@ -422,20 +457,20 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, empty_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr); } - /* free the msgb holding the L1SAP primitive */ - msgb_free(msg); - /* send message to DSP's queue */ if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], l1msg) != 0) { LOGP(DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n"); - msgb_free(msg); - } + msgb_free(l1msg); + } else + dtx_int_signal(lchan); + if (dtx_recursion(lchan)) + ph_data_req(trx, msg, l1sap, true); return 0; } static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, - struct osmo_phsap_prim *l1sap) + struct osmo_phsap_prim *l1sap, bool use_cache, bool marker) { struct lc15l1_hdl *fl1 = trx_lc15l1_hdl(trx); struct gsm_lchan *lchan; @@ -444,6 +479,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, uint8_t chan_nr; GsmL1_Prim_t *l1p; struct msgb *nmsg = NULL; + int rc = -1; chan_nr = l1sap->u.tch.chan_nr; u32Fn = l1sap->u.tch.fn; @@ -467,17 +503,20 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, if (!nmsg) return -ENOMEM; l1p = msgb_l1prim(nmsg); - if (!l1if_tch_encode(lchan, + rc = l1if_tch_encode(lchan, l1p->u.phDataReq.msgUnitParam.u8Buffer, &l1p->u.phDataReq.msgUnitParam.u8Size, - msg->data, msg->len, u32Fn, - l1sap->u.tch.marker)) { + msg->data, msg->len, u32Fn, use_cache, + l1sap->u.tch.marker); + if (rc < 0) { + /* no data encoded for L1: smth will be generated below */ msgb_free(nmsg); nmsg = NULL; } } - /* no message/data, we generate an empty traffic msg */ + /* no message/data, we might generate an empty traffic msg or re-send + cached SID in case of DTX */ if (!nmsg) nmsg = gen_empty_tch_msg(lchan, u32Fn); @@ -499,19 +538,16 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, } else { /* empty frame */ if (trx->bts->dtxd && trx != trx->bts->c0) - lchan->tch.dtxd_active = true; + lchan->tch.dtx.dl_active = true; empty_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr); } /* send message to DSP's queue */ osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg); + dtx_int_signal(lchan); - if (l1sap->u.tch.marker) { /* Send voice after ONSET was sent */ - l1sap->u.tch.marker = 0; - return ph_tch_req(trx, l1sap->oph.msg, l1sap); - } + if (dtx_recursion(lchan)) /* DTX: send voice after ONSET was sent */ + return ph_tch_req(trx, l1sap->oph.msg, l1sap, true, false); - if (msg) - msgb_free(msg); return 0; } @@ -555,7 +591,6 @@ static int mph_info_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_rsl_deact_sacch(lchan); else l1if_rsl_chan_rel(lchan); - msgb_free(msg); break; default: LOGP(DL1C, LOGL_NOTICE, "unknown MPH-INFO.req %d\n", @@ -575,12 +610,14 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) struct msgb *msg = l1sap->oph.msg; int rc = 0; + /* called functions MUST NOT take ownership of msgb, as it is + * free()d below */ switch (OSMO_PRIM_HDR(&l1sap->oph)) { case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST): - rc = ph_data_req(trx, msg, l1sap); + rc = ph_data_req(trx, msg, l1sap, false); break; case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST): - rc = ph_tch_req(trx, msg, l1sap); + rc = ph_tch_req(trx, msg, l1sap, false, l1sap->u.tch.marker); break; case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST): rc = mph_info_req(trx, msg, l1sap); @@ -595,13 +632,14 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) rc = -EINVAL; } - if (rc) - msgb_free(msg); + msgb_free(msg); + return rc; } static int handle_mph_time_ind(struct lc15l1_hdl *fl1, - GsmL1_MphTimeInd_t *time_ind) + GsmL1_MphTimeInd_t *time_ind, + struct msgb *msg) { struct gsm_bts_trx *trx = lc15l1_hdl_trx(fl1); struct gsm_bts *bts = trx->bts; @@ -624,6 +662,8 @@ static int handle_mph_time_ind(struct lc15l1_hdl *fl1, l1sap.u.info.type = PRIM_INFO_TIME; l1sap.u.info.u.time_ind.fn = fn; + msgb_free(msg); + return l1sap_up(trx, &l1sap); } @@ -763,9 +803,11 @@ static int handle_ph_readytosend_ind(struct lc15l1_hdl *fl1, if (chan_nr) { fn = rts_ind->u32Fn; if (rts_ind->sapi == GsmL1_Sapi_Sacch) - link_id = 0x40; + link_id = LID_SACCH; else - link_id = 0; + link_id = LID_DEDIC; + /* recycle the msgb and use it for the L1 primitive, + * which means that we (or our caller) must not free it */ rc = msgb_trim(l1p_msg, sizeof(*l1sap)); if (rc < 0) MSGB_ABORT(l1p_msg, "No room for primitive\n"); @@ -832,6 +874,8 @@ tx: msgb_free(resp_msg); } + /* free the msgb, as we have not handed it to l1sap and thus + * need to release its memory */ msgb_free(l1p_msg); return 0; @@ -862,6 +906,8 @@ static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr, l1sap.u.info.u.meas_ind.ber10k = (unsigned int) (m->fBer * 100); l1sap.u.info.u.meas_ind.inv_rssi = (uint8_t) (m->fRssi * -1); + /* l1sap wants to take msgb ownership. However, as there is no + * msg, it will msgb_free(l1sap.oph.msg == NULL) */ return l1sap_up(trx, &l1sap); } @@ -886,7 +932,7 @@ static int handle_ph_data_ind(struct lc15l1_hdl *fl1, GsmL1_PhDataInd_t *data_in return ENOTSUP; } fn = data_ind->u32Fn; - link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? 0x40 : 0x00; + link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? LID_SACCH : LID_DEDIC; process_meas_res(trx, chan_nr, &data_ind->measParam); @@ -1008,7 +1054,8 @@ static int handle_ph_ra_ind(struct lc15l1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind, l1sap->u.rach_ind.fn = fn; l1sap->u.rach_ind.is_11bit = is_11bit; /* no of bits in 11 bit RACH */ - /*mapping of the burst type, the values are specific to osmo-bts-litecell15*/ + /* mapping of the burst type, the values are specific to + * osmo-bts-litecell15 */ switch (burst_type) { case GsmL1_BurstType_Access_0: l1sap->u.rach_ind.burst_type = @@ -1043,30 +1090,29 @@ static int l1if_handle_ind(struct lc15l1_hdl *fl1, struct msgb *msg) GsmL1_Prim_t *l1p = msgb_l1prim(msg); int rc = 0; + /* all the below called functions must take ownership of the msgb */ switch (l1p->id) { case GsmL1_PrimId_MphTimeInd: - rc = handle_mph_time_ind(fl1, &l1p->u.mphTimeInd); + rc = handle_mph_time_ind(fl1, &l1p->u.mphTimeInd, msg); break; case GsmL1_PrimId_MphSyncInd: break; case GsmL1_PrimId_PhConnectInd: break; case GsmL1_PrimId_PhReadyToSendInd: - return handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd, + rc = handle_ph_readytosend_ind(fl1, &l1p->u.phReadyToSendInd, msg); + break; case GsmL1_PrimId_PhDataInd: - return handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); + rc = handle_ph_data_ind(fl1, &l1p->u.phDataInd, msg); + break; case GsmL1_PrimId_PhRaInd: - return handle_ph_ra_ind(fl1, &l1p->u.phRaInd, msg); + rc = handle_ph_ra_ind(fl1, &l1p->u.phRaInd, msg); break; default: break; } - /* Special return value '1' means: do not free */ - if (rc != 1) - msgb_free(msg); - return rc; } @@ -1100,10 +1146,12 @@ int l1if_handle_l1prim(int wq, struct lc15l1_hdl *fl1h, struct msgb *msg) llist_for_each_entry(wlc, &fl1h->wlc_list, list) { if (is_prim_compat(l1p, wlc)) { llist_del(&wlc->list); - if (wlc->cb) + if (wlc->cb) { + /* call-back function must take + * ownership of msgb */ rc = wlc->cb(lc15l1_hdl_trx(fl1h), msg, wlc->cb_data); - else { + } else { rc = 0; msgb_free(msg); } @@ -1131,10 +1179,12 @@ int l1if_handle_sysprim(struct lc15l1_hdl *fl1h, struct msgb *msg) * sending the same primitive */ if (wlc->is_sys_prim && sysp->id == wlc->conf_prim_id) { llist_del(&wlc->list); - if (wlc->cb) + if (wlc->cb) { + /* call-back function must take + * ownership of msgb */ rc = wlc->cb(lc15l1_hdl_trx(fl1h), msg, wlc->cb_data); - else { + } else { rc = 0; msgb_free(msg); } @@ -1146,22 +1196,6 @@ int l1if_handle_sysprim(struct lc15l1_hdl *fl1h, struct msgb *msg) return l1if_handle_ind(fl1h, msg); } -#if 0 -/* called by RSL if the BCCH SI has been modified */ -int sysinfo_has_changed(struct gsm_bts *bts, int si) -{ - /* FIXME: Determine BS_AG_BLKS_RES and - * * set cfgParams.u.agch.u8NbrOfAgch - * * determine implications on paging - */ - /* FIXME: Check for Extended BCCH presence */ - /* FIXME: Check for CCCH_CONF */ - /* FIXME: Check for BS_PA_MFRMS: update paging */ - - return 0; -} -#endif - static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) { diff --git a/src/osmo-bts-litecell15/l1_if.h b/src/osmo-bts-litecell15/l1_if.h index c8ab872f..6c7b6eda 100644 --- a/src/osmo-bts-litecell15/l1_if.h +++ b/src/osmo-bts-litecell15/l1_if.h @@ -96,9 +96,9 @@ uint32_t l1if_lchan_to_hLayer(struct gsm_lchan *lchan); struct gsm_lchan *l1if_hLayer_to_lchan(struct gsm_bts_trx *trx, uint32_t hLayer); /* tch.c */ -bool l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, - const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn, - bool marker); +int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, + const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn, + bool use_cache, bool marker); int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg); int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer); struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn); diff --git a/src/osmo-bts-litecell15/lc15bts_vty.c b/src/osmo-bts-litecell15/lc15bts_vty.c index 9a0b1217..b9076a27 100644 --- a/src/osmo-bts-litecell15/lc15bts_vty.c +++ b/src/osmo-bts-litecell15/lc15bts_vty.c @@ -46,15 +46,14 @@ #include <osmo-bts/gsm_data.h> #include <osmo-bts/phy_link.h> #include <osmo-bts/logging.h> +#include <osmo-bts/bts_model.h> #include <osmo-bts/vty.h> #include "lc15bts.h" #include "l1_if.h" #include "utils.h" - extern int lchan_activate(struct gsm_lchan *lchan); -extern int lchan_deactivate(struct gsm_lchan *lchan); #define TRX_STR "Transceiver related commands\n" "TRX number\n" diff --git a/src/osmo-bts-litecell15/misc/lc15bts_mgr.c b/src/osmo-bts-litecell15/misc/lc15bts_mgr.c index c97525c8..3a7d3a1f 100644 --- a/src/osmo-bts-litecell15/misc/lc15bts_mgr.c +++ b/src/osmo-bts-litecell15/misc/lc15bts_mgr.c @@ -222,13 +222,11 @@ static int mgr_log_init(void) int main(int argc, char **argv) { - void *tall_msgb_ctx; int rc; tall_mgr_ctx = talloc_named_const(NULL, 1, "bts manager"); - tall_msgb_ctx = talloc_named_const(tall_mgr_ctx, 1, "msgb"); - msgb_set_talloc_ctx(tall_msgb_ctx); + msgb_talloc_ctx_init(tall_mgr_ctx, 0); mgr_log_init(); diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-litecell15/oml.c index 4a3cafe3..d6267b29 100644 --- a/src/osmo-bts-litecell15/oml.c +++ b/src/osmo-bts-litecell15/oml.c @@ -287,8 +287,9 @@ static int opstart_compl(struct gsm_abis_mo *mo, struct msgb *l1_msg) mo->obj_inst.ts_nr == 0) { struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts); DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n"); - mo->bts->c0->ts[0].lchan[4].rel_act_kind = LCHAN_REL_ACT_OML; - lchan_activate(&mo->bts->c0->ts[0].lchan[4]); + mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind = + LCHAN_REL_ACT_OML; + lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]); if (cbch) { cbch->rel_act_kind = LCHAN_REL_ACT_OML; lchan_activate(cbch); @@ -1027,8 +1028,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) lch_par->rach.u8Bsic = lchan->ts->trx->bts->bsic; break; case GsmL1_Sapi_Agch: -#warning Set BS_AG_BLKS_RES - lch_par->agch.u8NbrOfAgch = 1; + lch_par->agch.u8NbrOfAgch = num_agch(lchan->ts->trx, lchan->name); break; case GsmL1_Sapi_TchH: case GsmL1_Sapi_TchF: @@ -1568,6 +1568,12 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status) lchan_set_state(lchan, LCHAN_S_NONE); mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0); + + /* Reactivate CCCH due to SI3 update in RSL */ + if (lchan->rel_act_kind == LCHAN_REL_ACT_REACT) { + lchan->rel_act_kind = LCHAN_REL_ACT_RSL; + lchan_activate(lchan); + } return 0; } @@ -1658,10 +1664,9 @@ static void enqueue_rel_marker(struct gsm_lchan *lchan) queue_sapi_command(lchan, cmd); } -int lchan_deactivate(struct gsm_lchan *lchan) +int bts_model_lchan_deactivate(struct gsm_lchan *lchan) { lchan_set_state(lchan, LCHAN_S_REL_REQ); - lchan->ciph_state = 0; /* FIXME: do this in common/\*.c */ enqueue_rel_marker(lchan); return 0; } @@ -1676,7 +1681,7 @@ static void enqueue_sacch_rel_marker(struct gsm_lchan *lchan) queue_sapi_command(lchan, cmd); } -static int lchan_deactivate_sacch(struct gsm_lchan *lchan) +int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan) { enqueue_sacch_rel_marker(lchan); return 0; @@ -1860,7 +1865,7 @@ int l1if_rsl_deact_sacch(struct gsm_lchan *lchan) /* Only de-activate the SACCH if the lchan is active */ if (lchan->state != LCHAN_S_ACTIVE) return 0; - return lchan_deactivate_sacch(lchan); + return bts_model_lchan_deactivate_sacch(lchan); } int bts_model_trx_deact_rf(struct gsm_bts_trx *trx) diff --git a/src/osmo-bts-litecell15/tch.c b/src/osmo-bts-litecell15/tch.c index 5020f63c..de3c7e35 100644 --- a/src/osmo-bts-litecell15/tch.c +++ b/src/osmo-bts-litecell15/tch.c @@ -35,7 +35,6 @@ #include <osmocom/core/select.h> #include <osmocom/core/timer.h> #include <osmocom/core/bits.h> -#include <osmocom/codec/codec.h> #include <osmocom/gsm/gsm_utils.h> #include <osmocom/trau/osmo_ortp.h> @@ -46,6 +45,7 @@ #include <osmo-bts/measurement.h> #include <osmo-bts/amr.h> #include <osmo-bts/l1sap.h> +#include <osmo-bts/dtx_dl_amr_fsm.h> #include <nrw/litecell15/litecell15.h> #include <nrw/litecell15/gsml1prim.h> @@ -199,86 +199,10 @@ static struct msgb *l1_to_rtppayload_amr(uint8_t *l1_payload, uint8_t payload_le * \returns number of \a l1_payload bytes filled */ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, - uint8_t payload_len, - struct gsm_lchan *lchan, uint32_t fn) + uint8_t payload_len, uint8_t ft) { - struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr; - enum osmo_amr_type ft; - enum osmo_amr_quality bfi; - uint8_t cmr; - int8_t sti, cmi; - uint8_t *l1_cmi_idx = l1_payload; - uint8_t *l1_cmr_idx = l1_payload+1; - int rc; - - osmo_amr_rtp_dec(rtp_payload, payload_len, &cmr, &cmi, &ft, &bfi, &sti); - memcpy(l1_payload+2, rtp_payload, payload_len); - - /* CMI in downlink tells the L1 encoder which encoding function - * it will use, so we have to use the frame type */ - switch (ft) { - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - cmi = ft; - LOGP(DRTP, LOGL_DEBUG, "SPEECH frame with CMI %u\n", cmi); - break; - case AMR_NO_DATA: - LOGP(DRTP, LOGL_DEBUG, "SPEECH frame AMR NO_DATA\n"); - break; - case AMR_SID: - LOGP(DRTP, LOGL_DEBUG, "SID %s frame with CMI %u\n", - sti ? "UPDATE" : "FIRST", cmi); - break; - default: - LOGP(DRTP, LOGL_ERROR, "unsupported AMR FT 0x%02x\n", ft); - return -EINVAL; - break; - } - - rc = get_amr_mode_idx(amr_mrc, cmi); - if (rc < 0) { - LOGP(DRTP, LOGL_ERROR, "AMR CMI %u not part of AMR MR set\n", - cmi); - *l1_cmi_idx = 0; - } else - *l1_cmi_idx = rc; - - /* Codec Mode Request is in upper 4 bits of RTP payload header, - * and we simply copy the CMR into the CMC */ - if (cmr == 0xF) { - /* FIXME: we need some state about the last codec mode */ - *l1_cmr_idx = 0; - } else { - rc = get_amr_mode_idx(amr_mrc, cmr); - if (rc < 0) { - /* FIXME: we need some state about the last codec mode */ - LOGP(DRTP, LOGL_INFO, "RTP->L1: overriding CMR %u\n", cmr); - *l1_cmr_idx = 0; - } else - *l1_cmr_idx = rc; - } -#if 0 - /* check for bad quality indication */ - if (bfi == AMR_GOOD) { - /* obtain frame type from AMR FT */ - l1_payload[2] = ft; - } else { - /* bad quality, we should indicate that... */ - if (ft == AMR_SID) { - /* FIXME: Should we do GsmL1_TchPlType_Amr_SidBad? */ - l1_payload[2] = ft; - } else { - l1_payload[2] = ft; - } - } -#endif - - if (ft == AMR_SID) { - save_last_sid(lchan, l1_payload, payload_len, fn, sti); - return -EALREADY; - } - - return payload_len+2; + memcpy(l1_payload, rtp_payload, payload_len); + return payload_len; } #define RTP_MSGB_ALLOC_SIZE 512 @@ -286,8 +210,11 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, /*! \brief function for incoming RTP via TCH.req * \param[in] rtp_pl buffer containing RTP payload * \param[in] rtp_pl_len length of \a rtp_pl + * \param[in] use_cache Use cached payload instead of parsing RTP * \param[in] marker RTP header Marker bit (indicates speech onset) - * \returns true if encoding result can be sent further to L1, false otherwise + * \returns 0 if encoding result can be sent further to L1 without extra actions + * positive value if data is ready AND extra actions are required + * negative value otherwise (no data for L1 encoded) * * This function prepares a msgb with a L1 PH-DATA.req primitive and * queues it into lchan->dl_tch_queue. @@ -296,15 +223,14 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, * yet, as things like the frame number, etc. are unknown at the time we * pre-fill the primtive. */ -bool l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, - const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn, bool marker) +int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, + const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn, + bool use_cache, bool marker) { uint8_t *payload_type; - uint8_t *l1_payload, cmr; - enum osmo_amr_type ft; - enum osmo_amr_quality bfi; - int8_t sti, cmi; - int rc; + uint8_t *l1_payload, ft; + int rc = 0; + bool is_sid = false; DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan), osmo_hexdump(rtp_pl, rtp_pl_len)); @@ -318,32 +244,91 @@ bool l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, *payload_type = GsmL1_TchPlType_Fr; rc = rtppayload_to_l1_fr(l1_payload, rtp_pl, rtp_pl_len); + if (rc && lchan->ts->trx->bts->dtxd) + is_sid = osmo_fr_check_sid(rtp_pl, rtp_pl_len); } else{ *payload_type = GsmL1_TchPlType_Hr; rc = rtppayload_to_l1_hr(l1_payload, rtp_pl, rtp_pl_len); + if (rc && lchan->ts->trx->bts->dtxd) + is_sid = osmo_hr_check_sid(rtp_pl, rtp_pl_len); } + if (is_sid) + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, -1); break; case GSM48_CMODE_SPEECH_EFR: *payload_type = GsmL1_TchPlType_Efr; rc = rtppayload_to_l1_efr(l1_payload, rtp_pl, rtp_pl_len); + /* FIXME: detect and save EFR SID */ break; case GSM48_CMODE_SPEECH_AMR: - if (marker) { - *payload_type = GsmL1_TchPlType_Amr_Onset; - rc = 0; - osmo_amr_rtp_dec(rtp_pl, rtp_pl_len, &cmr, &cmi, &ft, - &bfi, &sti); - LOGP(DRTP, LOGL_ERROR, "Marker SPEECH frame AMR %s\n", - get_value_string(osmo_amr_type_names, ft)); + if (use_cache) { + *payload_type = GsmL1_TchPlType_Amr; + rtppayload_to_l1_amr(l1_payload, lchan->tch.dtx.cache, + lchan->tch.dtx.len, ft); + *len = lchan->tch.dtx.len + 1; + return 0; } - else { + + rc = dtx_dl_amr_fsm_step(lchan, rtp_pl, rtp_pl_len, fn, + l1_payload, marker, len, &ft); + if (rc < 0) + return rc; + if (!dtx_dl_amr_enabled(lchan)) { *payload_type = GsmL1_TchPlType_Amr; - rc = rtppayload_to_l1_amr(l1_payload, rtp_pl, - rtp_pl_len, lchan, fn); - if (-EALREADY == rc) - return false; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len, + ft); + return 0; + } + + /* DTX DL-specific logic below: */ + switch (lchan->tch.dtx.dl_amr_fsm->state) { + case ST_ONSET_V: + *payload_type = GsmL1_TchPlType_Amr_Onset; + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0); + *len = 3; + return 1; + case ST_VOICE: + *payload_type = GsmL1_TchPlType_Amr; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len, + ft); + return 0; + case ST_SID_F1: + if (lchan->type == GSM_LCHAN_TCH_H) { /* AMR HR */ + *payload_type = GsmL1_TchPlType_Amr_SidFirstP1; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, + rtp_pl_len, ft); + return 0; + } + /* AMR FR */ + *payload_type = GsmL1_TchPlType_Amr; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len, + ft); + return 0; + case ST_SID_F2: + *payload_type = GsmL1_TchPlType_Amr; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len, + ft); + return 0; + case ST_F1_INH: + *payload_type = GsmL1_TchPlType_Amr_SidFirstInH; + *len = 3; + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0); + return 1; + case ST_U_INH: + *payload_type = GsmL1_TchPlType_Amr_SidUpdateInH; + *len = 3; + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0); + return 1; + case ST_SID_U: + return -EAGAIN; + case ST_FACCH: + return -EBADMSG; + default: + LOGP(DRTP, LOGL_ERROR, "Unhandled DTX DL AMR FSM state " + "%d\n", lchan->tch.dtx.dl_amr_fsm->state); + return -EINVAL; } break; default: @@ -355,14 +340,14 @@ bool l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, if (rc < 0) { LOGP(DRTP, LOGL_ERROR, "%s unable to parse RTP payload\n", gsm_lchan_name(lchan)); - return false; + return -EBADMSG; } *len = rc + 1; DEBUGP(DRTP, "%s RTP->L1: %s\n", gsm_lchan_name(lchan), osmo_hexdump(data, *len)); - return true; + return 0; } static int is_recv_only(uint8_t speech_mode) @@ -412,7 +397,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg) goto err_payload_match; /* according to 3GPP TS 26.093 ONSET frames precede the first speech frame of a speech burst - set the marker for next RTP - frame and drop last SID */ + frame */ lchan->rtp_tx_marker = true; break; case GsmL1_TchPlType_Amr_SidFirstP1: @@ -492,6 +477,7 @@ struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn) GsmL1_MsgUnitParam_t *msu_param; uint8_t *payload_type; uint8_t *l1_payload; + int rc; msg = l1p_msgb_alloc(); if (!msg) @@ -505,44 +491,39 @@ struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn) switch (lchan->tch_mode) { case GSM48_CMODE_SPEECH_AMR: - *payload_type = GsmL1_TchPlType_Amr; - if (dtx_amr_sid_optional(lchan, fn)) { - msgb_free(msg); - return NULL; + if (lchan->type == GSM_LCHAN_TCH_H && + dtx_dl_amr_enabled(lchan)) { + /* we have to explicitly handle sending SID FIRST P2 for + AMR HR in here */ + *payload_type = GsmL1_TchPlType_Amr_SidFirstP2; + rc = dtx_dl_amr_fsm_step(lchan, NULL, 0, fn, l1_payload, + false, &(msu_param->u8Size), + NULL); + if (rc == 0) + return msg; } - msu_param->u8Size = repeat_last_sid(lchan, l1_payload, fn); - if (!msu_param->u8Size) - osmo_amr_rtp_enc(l1_payload, 0, AMR_NO_DATA, AMR_GOOD); + *payload_type = GsmL1_TchPlType_Amr; break; case GSM48_CMODE_SPEECH_V1: if (lchan->type == GSM_LCHAN_TCH_F) *payload_type = GsmL1_TchPlType_Fr; else *payload_type = GsmL1_TchPlType_Hr; - /* unlike AMR, FR & HR schedued based on absolute FN value */ - if (dtx_sched_optional(lchan, fn)) { - msgb_free(msg); - return NULL; - } - msu_param->u8Size = repeat_last_sid(lchan, l1_payload, fn); - if (!msu_param->u8Size) - return NULL; break; case GSM48_CMODE_SPEECH_EFR: *payload_type = GsmL1_TchPlType_Efr; - if (dtx_sched_optional(lchan, fn)) { - msgb_free(msg); - return NULL; - } - msu_param->u8Size = repeat_last_sid(lchan, l1_payload, fn); - if (!msu_param->u8Size) - return NULL; break; default: msgb_free(msg); - msg = NULL; - break; + return NULL; + } + + rc = repeat_last_sid(lchan, l1_payload, fn); + if (!rc) { + msgb_free(msg); + return NULL; } + msu_param->u8Size = rc; return msg; } diff --git a/src/osmo-bts-octphy/Makefile.am b/src/osmo-bts-octphy/Makefile.am index e0df9afc..ac6a83ea 100644 --- a/src/osmo-bts-octphy/Makefile.am +++ b/src/osmo-bts-octphy/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) -I$(OCTSDR2G_INCDIR) -AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(ORTP_CFLAGS) -COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS) $(ORTP_LIBS) +AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(ORTP_CFLAGS) +COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS) $(ORTP_LIBS) EXTRA_DIST = l1_if.h l1_oml.h l1_utils.h octphy_hw_api.h octpkt.h diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c index c4105ac6..0fc51fcc 100644 --- a/src/osmo-bts-octphy/l1_if.c +++ b/src/osmo-bts-octphy/l1_if.c @@ -862,9 +862,9 @@ static int handle_ph_readytosend_ind(struct octphy_hdl *fl1, chan_nr = chan_nr_by_sapi(trx->ts[ts_num].pchan, sapi, sc, ts_num, fn); if (chan_nr) { if (sapi == cOCTVC1_GSM_SAPI_ENUM_SACCH) - link_id = 0x40; + link_id = LID_SACCH; else - link_id = 0; + link_id = LID_DEDIC; rc = msgb_trim(l1p_msg, sizeof(*l1sap)); if (rc < 0) @@ -985,9 +985,9 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1, } if (sapi == cOCTVC1_GSM_SAPI_ENUM_SACCH) - link_id = 0x40; + link_id = LID_SACCH; else - link_id = 0; + link_id = LID_DEDIC; memset(&l1sap, 0, sizeof(l1sap)); diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c index 77352612..58656256 100644 --- a/src/osmo-bts-octphy/l1_oml.c +++ b/src/osmo-bts-octphy/l1_oml.c @@ -43,12 +43,14 @@ #include "l1_oml.h" #include "l1_utils.h" #include "octphy_hw_api.h" +#include "btsconfig.h" #include <octphy/octvc1/octvc1_rc2string.h> #include <octphy/octvc1/gsm/octvc1_gsm_api_swap.h> #include <octphy/octvc1/gsm/octvc1_gsm_default.h> #include <octphy/octvc1/gsm/octvc1_gsm_id.h> #include <octphy/octvc1/main/octvc1_main_default.h> +#include <octphy/octvc1/main/octvc1_main_version.h> /* Map OSMOCOM logical channel type to OctPHY Logical channel type */ static tOCTVC1_GSM_LOGICAL_CHANNEL_COMBINATION_ENUM pchan_to_logChComb[_GSM_PCHAN_MAX] = @@ -181,8 +183,9 @@ static int opstart_compl(struct gsm_abis_mo *mo) if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 && mo->obj_inst.ts_nr == 0) { struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts); - mo->bts->c0->ts[0].lchan[4].rel_act_kind = LCHAN_REL_ACT_OML; - lchan_activate(&mo->bts->c0->ts[0].lchan[4]); + mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind = + LCHAN_REL_ACT_OML; + lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]); if (cbch) { cbch->rel_act_kind = LCHAN_REL_ACT_OML; lchan_activate(cbch); @@ -881,7 +884,7 @@ static void enqueue_sacch_rel_marker(struct gsm_lchan *lchan) queue_sapi_command(lchan, cmd); } -static int lchan_deactivate_sacch(struct gsm_lchan *lchan) +int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan) { enqueue_sacch_rel_marker(lchan); return 0; @@ -892,7 +895,7 @@ int l1if_rsl_deact_sacch(struct gsm_lchan *lchan) /* Only de-activate the SACCH if the lchan is active */ if (lchan->state != LCHAN_S_ACTIVE) return 0; - return lchan_deactivate_sacch(lchan); + return bts_model_lchan_deactivate_sacch(lchan); } @@ -910,10 +913,9 @@ static void enqueue_rel_marker(struct gsm_lchan *lchan) queue_sapi_command(lchan, cmd); } -static int lchan_deactivate(struct gsm_lchan *lchan) +int bts_model_lchan_deactivate(struct gsm_lchan *lchan) { lchan_set_state(lchan, LCHAN_S_REL_REQ); - lchan->ciph_state = 0; /* FIXME: do this in common *.c */ enqueue_rel_marker(lchan); return 0; } @@ -1206,29 +1208,42 @@ int l1if_check_app_sys_version(struct gsm_bts_trx *trx) return l1if_req_compl(fl1h, msg, app_info_sys_compl_cb, 0); } -static int app_info_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) +static int app_info_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, + void *data) { + char ver_hdr[32]; + tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *air = (tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *) resp->l2h; - /* in a completion call-back, we take msgb ownership and must - * release it before returning */ + sprintf(ver_hdr, "%02i.%02i.%02i-B%i", cOCTVC1_MAIN_VERSION_MAJOR, + cOCTVC1_MAIN_VERSION_MINOR, cOCTVC1_MAIN_VERSION_MAINTENANCE, + cOCTVC1_MAIN_VERSION_BUILD); mOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP_SWAP(air); - LOGP(DL1C, LOGL_INFO, "Rx APP-INFO.resp (name='%s', desc='%s', ver='%s')\n", - air->szName, air->szDescription, air->szVersion); + LOGP(DL1C, LOGL_INFO, + "Rx APP-INFO.resp (name='%s', desc='%s', ver='%s', ver_hdr='%s')\n", + air->szName, air->szDescription, air->szVersion, ver_hdr); + + /* Bail if dsp firmware does not match up the header version info */ + if (strcmp(air->szVersion, ver_hdr) != 0) { + LOGP(DL1C, LOGL_ERROR, + "Invalid header-file / dsp-firmware combination, exiting...\n"); + exit(1); + } talloc_replace(fl1h->info.app.name, fl1h, air->szName); talloc_replace(fl1h->info.app.description, fl1h, air->szDescription); talloc_replace(fl1h->info.app.version, fl1h, air->szVersion); + /* in a completion call-back, we take msgb ownership and must + * release it before returning */ msgb_free(resp); return 0; } - int l1if_check_app_version(struct gsm_bts_trx *trx) { struct phy_instance *pinst = trx_phy_instance(trx); @@ -1345,17 +1360,34 @@ int l1if_trx_open(struct gsm_bts_trx *trx) oc->TrxId.byTrxId = pinst->u.octphy.trx_id; oc->Config.ulBand = osmocom_to_octphy_band(trx->bts->band, trx->arfcn); oc->Config.usArfcn = trx->arfcn; - oc->Config.usTsc = trx->bts->bsic & 0x7; + +#if OCTPHY_MULTI_TRX == 1 + if (pinst->u.octphy.trx_id) + oc->Config.usCentreArfcn = plink->u.octphy.center_arfcn; + else { + oc->Config.usCentreArfcn = trx->arfcn; + plink->u.octphy.center_arfcn = trx->arfcn; + } oc->Config.usBcchArfcn = trx->bts->c0->arfcn; +#endif + oc->Config.usTsc = trx->bts->bsic & 0x7; oc->RfConfig.ulRxGainDb = plink->u.octphy.rx_gain_db; /* FIXME: compute this based on nominal transmit power, etc. */ oc->RfConfig.ulTxAttndB = plink->u.octphy.tx_atten_db; +#if OCTPHY_MULTI_TRX == 1 + LOGP(DL1C, LOGL_INFO, "Tx TRX-OPEN.req(trx=%u, rf_port=%u, arfcn=%u, " + "center=%u, tsc=%u, rx_gain=%u, tx_atten=%u)\n", + oc->TrxId.byTrxId, oc->ulRfPortIndex, oc->Config.usArfcn, + oc->Config.usCentreArfcn, oc->Config.usTsc, oc->RfConfig.ulRxGainDb, + oc->RfConfig.ulTxAttndB); +#else LOGP(DL1C, LOGL_INFO, "Tx TRX-OPEN.req(trx=%u, rf_port=%u, arfcn=%u, " "tsc=%u, rx_gain=%u, tx_atten=%u)\n", oc->TrxId.byTrxId, oc->ulRfPortIndex, oc->Config.usArfcn, oc->Config.usTsc, oc->RfConfig.ulRxGainDb, oc->RfConfig.ulTxAttndB); +#endif mOCTVC1_GSM_MSG_TRX_OPEN_CMD_SWAP(oc); diff --git a/src/osmo-bts-octphy/l1_utils.c b/src/osmo-bts-octphy/l1_utils.c index 682865bb..ac5e217d 100644 --- a/src/osmo-bts-octphy/l1_utils.c +++ b/src/osmo-bts-octphy/l1_utils.c @@ -62,7 +62,15 @@ const struct value_string octphy_dir_names[5] = const struct value_string octphy_clkmgr_state_vals[8] = { { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNINITIALIZE, "UNINITIALIZED" }, + +/* Note: Octasic renamed cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNUSED to + * cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_IDLE. The following ifdef + * statement ensures that older headers still work. */ +#ifdef cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNUSED { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNUSED, "UNUSED" }, +#else + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_IDLE, "IDLE" }, +#endif { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_NO_EXT_CLOCK, "NO_EXT_CLOCK" }, { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_LOCKED, "LOCKED" }, { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNLOCKED, "UNLOCKED" }, diff --git a/src/osmo-bts-octphy/octphy_hw_api.c b/src/osmo-bts-octphy/octphy_hw_api.c index d0d5ec74..dc23676c 100644 --- a/src/osmo-bts-octphy/octphy_hw_api.c +++ b/src/osmo-bts-octphy/octphy_hw_api.c @@ -279,7 +279,14 @@ static const struct value_string clocksync_source_state_vals[] = { static const struct value_string clocksync_state_vals[] = { { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNINITIALIZE, "Uninitialized" }, +/* Note: Octasic renamed cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNUSED to + * cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_IDLE. The following ifdef + * statement ensures that older headers still work. */ +#ifdef cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNUSED { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_UNUSED, "Unused" }, +#else + { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_IDLE, "Idle" }, +#endif { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_NO_EXT_CLOCK, "No External Clock" }, { cOCTVC1_HW_CLOCK_SYNC_MGR_STATE_ENUM_LOCKED, "Locked" }, diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am index 34f4bb0d..8e39a3a2 100644 --- a/src/osmo-bts-sysmo/Makefile.am +++ b/src/osmo-bts-sysmo/Makefile.am @@ -29,7 +29,7 @@ sysmobts_mgr_SOURCES = \ misc/sysmobts_mgr_temp.c \ misc/sysmobts_mgr_calib.c \ eeprom.c -sysmobts_mgr_LDADD = $(LIBGPS_LIBS) $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCTRL_LIBS) $(top_builddir)/src/common/libbts.a +sysmobts_mgr_LDADD = $(LIBGPS_LIBS) $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCTRL_LIBS) $(top_builddir)/src/common/libbts.a $(COMMON_LDADD) sysmobts_util_SOURCES = misc/sysmobts_util.c misc/sysmobts_par.c eeprom.c sysmobts_util_LDADD = $(LIBOSMOCORE_LIBS) diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 3c6db43d..2a3caf95 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -49,6 +49,8 @@ #include <osmo-bts/cbch.h> #include <osmo-bts/bts_model.h> #include <osmo-bts/l1sap.h> +#include <osmo-bts/msg_utils.h> +#include <osmo-bts/dtx_dl_amr_fsm.h> #include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -281,12 +283,6 @@ empty_req_from_rts_ind(GsmL1_Prim_t *l1p, return empty_req; } -static const uint8_t fill_frame[GSM_MACBLOCK_LEN] = { - 0x03, 0x03, 0x01, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, - 0x2B, 0x2B, 0x2B -}; - /* fill PH-DATA.req from l1sap primitive */ static GsmL1_PhDataReq_t * data_req_from_l1sap(GsmL1_Prim_t *l1p, struct femtol1_hdl *fl1, @@ -331,10 +327,11 @@ empty_req_from_l1sap(GsmL1_Prim_t *l1p, struct femtol1_hdl *fl1, } static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, - struct osmo_phsap_prim *l1sap) + struct osmo_phsap_prim *l1sap, bool use_cache) { struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx); struct msgb *l1msg = l1p_msgb_alloc(); + struct gsm_lchan *lchan; uint32_t u32Fn; uint8_t u8Tn, subCh, u8BlockNbr = 0, sapi = 0; uint8_t chan_nr, link_id; @@ -353,6 +350,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, u32Fn = l1sap->u.data.fn; u8Tn = L1SAP_CHAN2TS(chan_nr); subCh = 0x1f; + lchan = get_lchan_by_chan_nr(trx, chan_nr); if (L1SAP_IS_LINK_SACCH(link_id)) { sapi = GsmL1_Sapi_Sacch; if (!L1SAP_IS_CHAN_TCHF(chan_nr)) @@ -402,14 +400,50 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, if (len) { /* data request */ GsmL1_Prim_t *l1p = msgb_l1prim(l1msg); - data_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr, len); - - OSMO_ASSERT(msgb_l2len(msg) <= sizeof(l1p->u.phDataReq.msgUnitParam.u8Buffer)); - memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h, msgb_l2len(msg)); + if (use_cache) + memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, + lchan->tch.dtx.facch, msgb_l2len(msg)); + else if (dtx_dl_amr_enabled(lchan) && + lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_F) { + if (sapi == GsmL1_Sapi_FacchF) { + sapi = GsmL1_Sapi_TchF; + } + if (sapi == GsmL1_Sapi_FacchH) { + sapi = GsmL1_Sapi_TchH; + } + if (sapi == GsmL1_Sapi_TchH || sapi == GsmL1_Sapi_TchF) { + /* FACCH interruption of DTX silence */ + /* cache FACCH data */ + memcpy(lchan->tch.dtx.facch, msg->l2h, + msgb_l2len(msg)); + /* prepare ONSET message */ + l1p->u.phDataReq.msgUnitParam.u8Buffer[0] = + GsmL1_TchPlType_Amr_Onset; + /* ignored CMR/CMI pair */ + l1p->u.phDataReq.msgUnitParam.u8Buffer[1] = 0; + l1p->u.phDataReq.msgUnitParam.u8Buffer[2] = 0; + /* update length */ + data_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, + subCh, u8BlockNbr, 3); + /* update FN so it can be checked by TCH silence + resume handler */ + lchan->tch.dtx.fn = LCHAN_FN_DUMMY; + } + } else if (dtx_dl_amr_enabled(lchan) && + lchan->tch.dtx.dl_amr_fsm->state == ST_FACCH) { + /* update FN so it can be checked by TCH silence + resume handler */ + lchan->tch.dtx.fn = LCHAN_FN_DUMMY; + } + else { + OSMO_ASSERT(msgb_l2len(msg) <= sizeof(l1p->u.phDataReq.msgUnitParam.u8Buffer)); + memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h, + msgb_l2len(msg)); + } LOGP(DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n", - osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, - l1p->u.phDataReq.msgUnitParam.u8Size)); + osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, + l1p->u.phDataReq.msgUnitParam.u8Size)); } else { /* empty frame */ GsmL1_Prim_t *l1p = msgb_l1prim(l1msg); @@ -421,13 +455,16 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], l1msg) != 0) { LOGP(DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n"); msgb_free(l1msg); - } + } else + dtx_int_signal(lchan); + if (dtx_recursion(lchan)) + ph_data_req(trx, msg, l1sap, true); return 0; } static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, - struct osmo_phsap_prim *l1sap) + struct osmo_phsap_prim *l1sap, bool use_cache, bool marker) { struct femtol1_hdl *fl1 = trx_femtol1_hdl(trx); struct gsm_lchan *lchan; @@ -436,6 +473,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, uint8_t chan_nr; GsmL1_Prim_t *l1p; struct msgb *nmsg = NULL; + int rc = -1; chan_nr = l1sap->u.tch.chan_nr; u32Fn = l1sap->u.tch.fn; @@ -459,17 +497,20 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, if (!nmsg) return -ENOMEM; l1p = msgb_l1prim(nmsg); - if (!l1if_tch_encode(lchan, + rc = l1if_tch_encode(lchan, l1p->u.phDataReq.msgUnitParam.u8Buffer, &l1p->u.phDataReq.msgUnitParam.u8Size, - msg->data, msg->len, u32Fn, - l1sap->u.tch.marker)) { + msg->data, msg->len, u32Fn, use_cache, + l1sap->u.tch.marker); + if (rc < 0) { + /* no data encoded for L1: smth will be generated below */ msgb_free(nmsg); nmsg = NULL; } } - /* no message/data, we generate an empty traffic msg */ + /* no message/data, we might generate an empty traffic msg or re-send + cached SID in case of DTX */ if (!nmsg) nmsg = gen_empty_tch_msg(lchan, u32Fn); @@ -491,16 +532,15 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, } else { /* empty frame */ if (trx->bts->dtxd && trx != trx->bts->c0) - lchan->tch.dtxd_active = true; + lchan->tch.dtx.dl_active = true; empty_req_from_l1sap(l1p, fl1, u8Tn, u32Fn, sapi, subCh, u8BlockNbr); } /* send message to DSP's queue */ osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg); + dtx_int_signal(lchan); - if (l1sap->u.tch.marker) { /* Send voice after ONSET was sent */ - l1sap->u.tch.marker = 0; - return ph_tch_req(trx, l1sap->oph.msg, l1sap); - } + if (dtx_recursion(lchan)) /* DTX: send voice after ONSET was sent */ + return ph_tch_req(trx, l1sap->oph.msg, l1sap, true, false); return 0; } @@ -565,10 +605,10 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) * free()d below */ switch (OSMO_PRIM_HDR(&l1sap->oph)) { case OSMO_PRIM(PRIM_PH_DATA, PRIM_OP_REQUEST): - rc = ph_data_req(trx, msg, l1sap); + rc = ph_data_req(trx, msg, l1sap, false); break; case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST): - rc = ph_tch_req(trx, msg, l1sap); + rc = ph_tch_req(trx, msg, l1sap, false, l1sap->u.tch.marker); break; case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST): rc = mph_info_req(trx, msg, l1sap); @@ -750,9 +790,9 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, if (chan_nr) { fn = rts_ind->u32Fn; if (rts_ind->sapi == GsmL1_Sapi_Sacch) - link_id = 0x40; + link_id = LID_SACCH; else - link_id = 0; + link_id = LID_DEDIC; /* recycle the msgb and use it for the L1 primitive, * which means that we (or our caller) must not free it */ rc = msgb_trim(l1p_msg, sizeof(*l1sap)); @@ -878,7 +918,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i return ENOTSUP; } fn = data_ind->u32Fn; - link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? 0x40 : 0x00; + link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? LID_SACCH : LID_DEDIC; process_meas_res(trx, chan_nr, &data_ind->measParam); @@ -1136,22 +1176,6 @@ int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg) return l1if_handle_ind(fl1h, msg); } -#if 0 -/* called by RSL if the BCCH SI has been modified */ -int sysinfo_has_changed(struct gsm_bts *bts, int si) -{ - /* FIXME: Determine BS_AG_BLKS_RES and - * * set cfgParams.u.agch.u8NbrOfAgch - * * determine implications on paging - */ - /* FIXME: Check for Extended BCCH presence */ - /* FIXME: Check for CCCH_CONF */ - /* FIXME: Check for BS_PA_MFRMS: update paging */ - - return 0; -} -#endif - static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) { diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index a90c39b2..0dc919bd 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -109,9 +109,9 @@ uint32_t l1if_lchan_to_hLayer(struct gsm_lchan *lchan); struct gsm_lchan *l1if_hLayer_to_lchan(struct gsm_bts_trx *trx, uint32_t hLayer); /* tch.c */ -bool l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, - const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn, - bool marker); +int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, + const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn, + bool use_cache, bool marker); int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg); int l1if_tch_fill(struct gsm_lchan *lchan, uint8_t *l1_buffer); struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn); diff --git a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c index ccb84d8a..f126db2d 100644 --- a/src/osmo-bts-sysmo/misc/sysmobts_mgr.c +++ b/src/osmo-bts-sysmo/misc/sysmobts_mgr.c @@ -245,13 +245,11 @@ static int mgr_log_init(void) int main(int argc, char **argv) { - void *tall_msgb_ctx; int rc; tall_mgr_ctx = talloc_named_const(NULL, 1, "bts manager"); - tall_msgb_ctx = talloc_named_const(tall_mgr_ctx, 1, "msgb"); - msgb_set_talloc_ctx(tall_msgb_ctx); + msgb_talloc_ctx_init(tall_mgr_ctx, 0); mgr_log_init(); if (classify_bts() != 0) diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index c1f1e0b2..01752d18 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -286,8 +286,9 @@ static int opstart_compl(struct gsm_abis_mo *mo, struct msgb *l1_msg) mo->obj_inst.ts_nr == 0) { struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts); DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n"); - mo->bts->c0->ts[0].lchan[4].rel_act_kind = LCHAN_REL_ACT_OML; - lchan_activate(&mo->bts->c0->ts[0].lchan[4]); + mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind = + LCHAN_REL_ACT_OML; + lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]); if (cbch) { cbch->rel_act_kind = LCHAN_REL_ACT_OML; lchan_activate(cbch); @@ -1039,8 +1040,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) lch_par->rach.u8Bsic = lchan->ts->trx->bts->bsic; break; case GsmL1_Sapi_Agch: -#warning Set BS_AG_BLKS_RES - lch_par->agch.u8NbrOfAgch = 1; + lch_par->agch.u8NbrOfAgch = num_agch(lchan->ts->trx, lchan->name); break; case GsmL1_Sapi_TchH: case GsmL1_Sapi_TchF: @@ -1585,6 +1585,12 @@ static int sapi_deactivate_cb(struct gsm_lchan *lchan, int status) lchan_set_state(lchan, LCHAN_S_NONE); mph_info_chan_confirm(lchan, PRIM_INFO_DEACTIVATE, 0); + + /* Reactivate CCCH due to SI3 update in RSL */ + if (lchan->rel_act_kind == LCHAN_REL_ACT_REACT) { + lchan->rel_act_kind = LCHAN_REL_ACT_RSL; + lchan_activate(lchan); + } return 0; } @@ -1675,10 +1681,9 @@ static void enqueue_rel_marker(struct gsm_lchan *lchan) queue_sapi_command(lchan, cmd); } -int lchan_deactivate(struct gsm_lchan *lchan) +int bts_model_lchan_deactivate(struct gsm_lchan *lchan) { lchan_set_state(lchan, LCHAN_S_REL_REQ); - lchan->ciph_state = 0; /* FIXME: do this in common/\*.c */ enqueue_rel_marker(lchan); return 0; } @@ -1693,7 +1698,7 @@ static void enqueue_sacch_rel_marker(struct gsm_lchan *lchan) queue_sapi_command(lchan, cmd); } -static int lchan_deactivate_sacch(struct gsm_lchan *lchan) +int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan) { enqueue_sacch_rel_marker(lchan); return 0; @@ -1877,7 +1882,7 @@ int l1if_rsl_deact_sacch(struct gsm_lchan *lchan) /* Only de-activate the SACCH if the lchan is active */ if (lchan->state != LCHAN_S_ACTIVE) return 0; - return lchan_deactivate_sacch(lchan); + return bts_model_lchan_deactivate_sacch(lchan); } int bts_model_trx_deact_rf(struct gsm_bts_trx *trx) diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c index c829c497..e67d8be0 100644 --- a/src/osmo-bts-sysmo/sysmobts_vty.c +++ b/src/osmo-bts-sysmo/sysmobts_vty.c @@ -42,15 +42,14 @@ #include <osmo-bts/gsm_data.h> #include <osmo-bts/phy_link.h> #include <osmo-bts/logging.h> +#include <osmo-bts/bts_model.h> #include <osmo-bts/vty.h> #include "femtobts.h" #include "l1_if.h" #include "utils.h" - extern int lchan_activate(struct gsm_lchan *lchan); -extern int lchan_deactivate(struct gsm_lchan *lchan); #define TRX_STR "Transceiver related commands\n" "TRX number\n" diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c index b1ab0866..16c2cf3a 100644 --- a/src/osmo-bts-sysmo/tch.c +++ b/src/osmo-bts-sysmo/tch.c @@ -32,7 +32,6 @@ #include <osmocom/core/select.h> #include <osmocom/core/timer.h> #include <osmocom/core/bits.h> -#include <osmocom/codec/codec.h> #include <osmocom/gsm/gsm_utils.h> #include <osmocom/trau/osmo_ortp.h> @@ -43,6 +42,7 @@ #include <osmo-bts/measurement.h> #include <osmo-bts/amr.h> #include <osmo-bts/l1sap.h> +#include <osmo-bts/dtx_dl_amr_fsm.h> #include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -282,22 +282,10 @@ static struct msgb *l1_to_rtppayload_amr(uint8_t *l1_payload, uint8_t payload_le * \returns number of \a l1_payload bytes filled */ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, - uint8_t payload_len, - struct gsm_lchan *lchan, uint32_t fn) + uint8_t payload_len, uint8_t ft) { - struct amr_multirate_conf *amr_mrc = &lchan->tch.amr_mr; - enum osmo_amr_type ft; - enum osmo_amr_quality bfi; - uint8_t cmr; - int8_t sti, cmi; - uint8_t *l1_cmi_idx = l1_payload; - uint8_t *l1_cmr_idx = l1_payload+1; - int rc; - - osmo_amr_rtp_dec(rtp_payload, payload_len, &cmr, &cmi, &ft, &bfi, &sti); - #ifdef USE_L1_RTP_MODE - memcpy(l1_payload+2, rtp_payload, payload_len); + memcpy(l1_payload, rtp_payload, payload_len); #else uint8_t amr_if2_core_len = payload_len - 2; @@ -310,72 +298,7 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, /* lower 4 bit of first FR2 byte contains FT */ l1_payload[2] |= ft; #endif /* USE_L1_RTP_MODE */ - - /* CMI in downlink tells the L1 encoder which encoding function - * it will use, so we have to use the frame type */ - switch (ft) { - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 7: - cmi = ft; - LOGP(DRTP, LOGL_DEBUG, "SPEECH frame with CMI %u\n", cmi); - break; - case AMR_NO_DATA: - LOGP(DRTP, LOGL_DEBUG, "SPEECH frame AMR NO_DATA\n"); - break; - case AMR_SID: - LOGP(DRTP, LOGL_DEBUG, "SID %s frame with CMI %u\n", - sti ? "UPDATE" : "FIRST", cmi); - break; - default: - LOGP(DRTP, LOGL_ERROR, "unsupported AMR FT 0x%02x\n", ft); - return -EINVAL; - break; - } - - rc = get_amr_mode_idx(amr_mrc, cmi); - if (rc < 0) { - LOGP(DRTP, LOGL_ERROR, "AMR CMI %u not part of AMR MR set\n", - cmi); - *l1_cmi_idx = 0; - } else - *l1_cmi_idx = rc; - - /* Codec Mode Request is in upper 4 bits of RTP payload header, - * and we simply copy the CMR into the CMC */ - if (cmr == 0xF) { - /* FIXME: we need some state about the last codec mode */ - *l1_cmr_idx = 0; - } else { - rc = get_amr_mode_idx(amr_mrc, cmr); - if (rc < 0) { - /* FIXME: we need some state about the last codec mode */ - LOGP(DRTP, LOGL_INFO, "RTP->L1: overriding CMR %u\n", cmr); - *l1_cmr_idx = 0; - } else - *l1_cmr_idx = rc; - } -#if 0 - /* check for bad quality indication */ - if (bfi == AMR_GOOD) { - /* obtain frame type from AMR FT */ - l1_payload[2] = ft; - } else { - /* bad quality, we should indicate that... */ - if (ft == AMR_SID) { - /* FIXME: Should we do GsmL1_TchPlType_Amr_SidBad? */ - l1_payload[2] = ft; - } else { - l1_payload[2] = ft; - } - } -#endif - - if (ft == AMR_SID) { - save_last_sid(lchan, l1_payload, payload_len, fn, sti); - return -EALREADY; - } - - return payload_len+1; + return payload_len; } #define RTP_MSGB_ALLOC_SIZE 512 @@ -383,8 +306,11 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, /*! \brief function for incoming RTP via TCH.req * \param[in] rtp_pl buffer containing RTP payload * \param[in] rtp_pl_len length of \a rtp_pl + * \param[in] use_cache Use cached payload instead of parsing RTP * \param[in] marker RTP header Marker bit (indicates speech onset) - * \returns true if encoding result can be sent further to L1, false otherwise + * \returns 0 if encoding result can be sent further to L1 without extra actions + * positive value if data is ready AND extra actions are required + * negative value otherwise (no data for L1 encoded) * * This function prepares a msgb with a L1 PH-DATA.req primitive and * queues it into lchan->dl_tch_queue. @@ -393,15 +319,14 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, const uint8_t *rtp_payload, * yet, as things like the frame number, etc. are unknown at the time we * pre-fill the primtive. */ -bool l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, - const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn, bool marker) +int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, + const uint8_t *rtp_pl, unsigned int rtp_pl_len, uint32_t fn, + bool use_cache, bool marker) { uint8_t *payload_type; - uint8_t *l1_payload, cmr; - enum osmo_amr_type ft; - enum osmo_amr_quality bfi; - int8_t sti, cmi; - int rc; + uint8_t *l1_payload, ft; + int rc = 0; + bool is_sid = false; DEBUGP(DRTP, "%s RTP IN: %s\n", gsm_lchan_name(lchan), osmo_hexdump(rtp_pl, rtp_pl_len)); @@ -415,34 +340,93 @@ bool l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, *payload_type = GsmL1_TchPlType_Fr; rc = rtppayload_to_l1_fr(l1_payload, rtp_pl, rtp_pl_len); + if (rc && lchan->ts->trx->bts->dtxd) + is_sid = osmo_fr_check_sid(rtp_pl, rtp_pl_len); } else{ *payload_type = GsmL1_TchPlType_Hr; rc = rtppayload_to_l1_hr(l1_payload, rtp_pl, rtp_pl_len); + if (rc && lchan->ts->trx->bts->dtxd) + is_sid = osmo_hr_check_sid(rtp_pl, rtp_pl_len); } + if (is_sid) + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, -1); break; #if defined(L1_HAS_EFR) && defined(USE_L1_RTP_MODE) case GSM48_CMODE_SPEECH_EFR: *payload_type = GsmL1_TchPlType_Efr; rc = rtppayload_to_l1_efr(l1_payload, rtp_pl, rtp_pl_len); + /* FIXME: detect and save EFR SID */ break; #endif case GSM48_CMODE_SPEECH_AMR: - if (marker) { - *payload_type = GsmL1_TchPlType_Amr_Onset; - rc = 0; - osmo_amr_rtp_dec(rtp_pl, rtp_pl_len, &cmr, &cmi, &ft, - &bfi, &sti); - LOGP(DRTP, LOGL_ERROR, "Marker SPEECH frame AMR %s\n", - get_value_string(osmo_amr_type_names, ft)); + if (use_cache) { + *payload_type = GsmL1_TchPlType_Amr; + rtppayload_to_l1_amr(l1_payload, lchan->tch.dtx.cache, + lchan->tch.dtx.len, ft); + *len = lchan->tch.dtx.len + 1; + return 0; } - else { + + rc = dtx_dl_amr_fsm_step(lchan, rtp_pl, rtp_pl_len, fn, + l1_payload, marker, len, &ft); + if (rc < 0) + return rc; + if (!dtx_dl_amr_enabled(lchan)) { *payload_type = GsmL1_TchPlType_Amr; - rc = rtppayload_to_l1_amr(l1_payload, rtp_pl, - rtp_pl_len, lchan, fn); - if (-EALREADY == rc) - return false; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len, + ft); + return 0; + } + + /* DTX DL-specific logic below: */ + switch (lchan->tch.dtx.dl_amr_fsm->state) { + case ST_ONSET_V: + *payload_type = GsmL1_TchPlType_Amr_Onset; + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0); + *len = 3; + return 1; + case ST_VOICE: + *payload_type = GsmL1_TchPlType_Amr; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len, + ft); + return 0; + case ST_SID_F1: + if (lchan->type == GSM_LCHAN_TCH_H) { /* AMR HR */ + *payload_type = GsmL1_TchPlType_Amr_SidFirstP1; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, + rtp_pl_len, ft); + return 0; + } + /* AMR FR */ + *payload_type = GsmL1_TchPlType_Amr; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len, + ft); + return 0; + case ST_SID_F2: + *payload_type = GsmL1_TchPlType_Amr; + rtppayload_to_l1_amr(l1_payload + 2, rtp_pl, rtp_pl_len, + ft); + return 0; + case ST_F1_INH: + *payload_type = GsmL1_TchPlType_Amr_SidFirstInH; + *len = 3; + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0); + return 1; + case ST_U_INH: + *payload_type = GsmL1_TchPlType_Amr_SidUpdateInH; + *len = 3; + dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0); + return 1; + case ST_SID_U: + return -EAGAIN; + case ST_FACCH: + return -EBADMSG; + default: + LOGP(DRTP, LOGL_ERROR, "Unhandled DTX DL AMR FSM state " + "%d\n", lchan->tch.dtx.dl_amr_fsm->state); + return -EINVAL; } break; default: @@ -454,14 +438,14 @@ bool l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len, if (rc < 0) { LOGP(DRTP, LOGL_ERROR, "%s unable to parse RTP payload\n", gsm_lchan_name(lchan)); - return false; + return -EBADMSG; } *len = rc + 1; DEBUGP(DRTP, "%s RTP->L1: %s\n", gsm_lchan_name(lchan), osmo_hexdump(data, *len)); - return true; + return 0; } static int is_recv_only(uint8_t speech_mode) @@ -513,7 +497,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg) goto err_payload_match; /* according to 3GPP TS 26.093 ONSET frames precede the first speech frame of a speech burst - set the marker for next RTP - frame and drop last SID */ + frame */ lchan->rtp_tx_marker = true; break; case GsmL1_TchPlType_Amr_SidFirstP1: @@ -595,6 +579,7 @@ struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn) GsmL1_MsgUnitParam_t *msu_param; uint8_t *payload_type; uint8_t *l1_payload; + int rc; msg = l1p_msgb_alloc(); if (!msg) @@ -608,44 +593,39 @@ struct msgb *gen_empty_tch_msg(struct gsm_lchan *lchan, uint32_t fn) switch (lchan->tch_mode) { case GSM48_CMODE_SPEECH_AMR: - *payload_type = GsmL1_TchPlType_Amr; - if (dtx_amr_sid_optional(lchan, fn)) { - msgb_free(msg); - return NULL; + if (lchan->type == GSM_LCHAN_TCH_H && + dtx_dl_amr_enabled(lchan)) { + /* we have to explicitly handle sending SID FIRST P2 for + AMR HR in here */ + *payload_type = GsmL1_TchPlType_Amr_SidFirstP2; + rc = dtx_dl_amr_fsm_step(lchan, NULL, 0, fn, l1_payload, + false, &(msu_param->u8Size), + NULL); + if (rc == 0) + return msg; } - msu_param->u8Size = repeat_last_sid(lchan, l1_payload, fn); - if (!msu_param->u8Size) - osmo_amr_rtp_enc(l1_payload, 0, AMR_NO_DATA, AMR_GOOD); + *payload_type = GsmL1_TchPlType_Amr; break; case GSM48_CMODE_SPEECH_V1: if (lchan->type == GSM_LCHAN_TCH_F) *payload_type = GsmL1_TchPlType_Fr; else *payload_type = GsmL1_TchPlType_Hr; - /* unlike AMR, FR & HR schedued based on absolute FN value */ - if (dtx_sched_optional(lchan, fn)) { - msgb_free(msg); - return NULL; - } - msu_param->u8Size = repeat_last_sid(lchan, l1_payload, fn); - if (!msu_param->u8Size) - return NULL; break; case GSM48_CMODE_SPEECH_EFR: *payload_type = GsmL1_TchPlType_Efr; - if (dtx_sched_optional(lchan, fn)) { - msgb_free(msg); - return NULL; - } - msu_param->u8Size = repeat_last_sid(lchan, l1_payload, fn); - if (!msu_param->u8Size) - return NULL; break; default: msgb_free(msg); - msg = NULL; - break; + return NULL; + } + + rc = repeat_last_sid(lchan, l1_payload, fn); + if (!rc) { + msgb_free(msg); + return NULL; } + msu_param->u8Size = rc; return msg; } diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c index b89a3594..a42d39a0 100644 --- a/src/osmo-bts-trx/l1_if.c +++ b/src/osmo-bts-trx/l1_if.c @@ -71,19 +71,22 @@ struct trx_l1h *l1if_open(struct phy_instance *pinst) return NULL; l1h->phy_inst = pinst; - trx_sched_init(&l1h->l1s, pinst->trx); + rc = trx_sched_init(&l1h->l1s, pinst->trx); + if (rc < 0) { + LOGP(DL1C, LOGL_FATAL, "Cannot initialize scheduler for phy " + "instance %d\n", pinst->num); + return NULL; + } rc = trx_if_open(l1h); if (rc < 0) { - LOGP(DL1C, LOGL_FATAL, "Cannot initialize scheduler\n"); - goto err; + LOGP(DL1C, LOGL_FATAL, "Cannot open TRX interface for phy " + "instance %d\n", pinst->num); + l1if_close(l1h); + return NULL; } return l1h; - -err: - l1if_close(l1h); - return NULL; } void l1if_close(struct trx_l1h *l1h) @@ -144,6 +147,25 @@ int check_transceiver_availability(struct gsm_bts *bts, int avail) return 0; } +int bts_model_lchan_deactivate(struct gsm_lchan *lchan) +{ + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + + /* set lchan inactive */ + lchan_set_state(lchan, LCHAN_S_NONE); + + return trx_sched_set_lchan(&l1h->l1s, gsm_lchan2chan_nr(lchan), + LID_DEDIC, 0); +} + +int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan) +{ + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + return trx_sched_set_lchan(&l1h->l1s, gsm_lchan2chan_nr(lchan), + LID_SACCH, 0); +} /* * transceiver provisioning @@ -197,6 +219,10 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) trx_if_cmd_setmaxdly(l1h, l1h->config.maxdly); l1h->config.maxdly_sent = 1; } + if (l1h->config.maxdlynb_valid && !l1h->config.maxdlynb_sent) { + trx_if_cmd_setmaxdlynb(l1h, l1h->config.maxdlynb); + l1h->config.maxdlynb_sent = 1; + } for (tn = 0; tn < TRX_NR_TS; tn++) { if (l1h->config.slottype_valid[tn] @@ -217,6 +243,7 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) plink->u.osmotrx.power_sent = 0; } l1h->config.maxdly_sent = 0; + l1h->config.maxdlynb_sent = 0; for (tn = 0; tn < TRX_NR_TS; tn++) l1h->config.slottype_sent[tn] = 0; } @@ -267,7 +294,7 @@ static int trx_init(struct gsm_bts_trx *trx) } if (trx == trx->bts->c0) - lchan_init_lapdm(&trx->ts[0].lchan[4]); + lchan_init_lapdm(&trx->ts[0].lchan[CCCH_LCHAN]); /* Set to Operational State: Enabled */ oml_mo_state_chg(&trx->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK); @@ -288,7 +315,7 @@ int bts_model_trx_close(struct gsm_bts_trx *trx) /* deactivate lchan for CCCH */ if (pchan == GSM_PCHAN_CCCH || pchan == GSM_PCHAN_CCCH_SDCCH4) { - lchan_set_state(&trx->ts[0].lchan[4], LCHAN_S_INACTIVE); + lchan_set_state(&trx->ts[0].lchan[CCCH_LCHAN], LCHAN_S_INACTIVE); } /* power off transceiver, if not already */ @@ -408,8 +435,8 @@ static uint8_t trx_set_ts_as_pchan(struct gsm_bts_trx_ts *ts, /* activate lchan for CCCH */ if (pchan == GSM_PCHAN_CCCH || pchan == GSM_PCHAN_CCCH_SDCCH4) { - ts->lchan[4].rel_act_kind = LCHAN_REL_ACT_OML; - lchan_set_state(&ts->lchan[4], LCHAN_S_ACTIVE); + ts->lchan[CCCH_LCHAN].rel_act_kind = LCHAN_REL_ACT_OML; + lchan_set_state(&ts->lchan[CCCH_LCHAN], LCHAN_S_ACTIVE); } slottype = transceiver_chan_types[pchan]; @@ -591,9 +618,9 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) break; } /* activate dedicated channel */ - trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x00, 1); + trx_sched_set_lchan(&l1h->l1s, chan_nr, LID_DEDIC, 1); /* activate associated channel */ - trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x40, 1); + trx_sched_set_lchan(&l1h->l1s, chan_nr, LID_SACCH, 1); /* set mode */ trx_sched_set_mode(&l1h->l1s, chan_nr, lchan->rsl_cmode, lchan->tch_mode, @@ -641,16 +668,13 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) break; } /* deactivate associated channel */ - trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x40, 0); + bts_model_lchan_deactivate_sacch(lchan); if (!l1sap->u.info.u.act_req.sacch_only) { - /* set lchan inactive */ - lchan_set_state(lchan, LCHAN_S_NONE); /* deactivate dedicated channel */ - trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x00, 0); + lchan_deactivate(lchan); /* confirm only on dedicated channel */ mph_info_chan_confirm(l1h, chan_nr, PRIM_INFO_DEACTIVATE, 0); - lchan->ciph_state = 0; /* FIXME: do this in common/\*.c */ } break; default: diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h index 187303c6..f0b2e67a 100644 --- a/src/osmo-bts-trx/l1_if.h +++ b/src/osmo-bts-trx/l1_if.h @@ -24,6 +24,10 @@ struct trx_config { int maxdly; int maxdly_sent; + int maxdlynb_valid; + int maxdlynb; + int maxdlynb_sent; + uint8_t slotmask; int slottype_valid[TRX_NR_TS]; diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index 02e7aba8..d946ad5f 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -32,8 +32,6 @@ #include <osmocom/core/bits.h> #include <osmocom/gsm/a5.h> -#include <osmocom/netif/rtp.h> - #include <osmo-bts/gsm_data.h> #include <osmo-bts/logging.h> #include <osmo-bts/rsl.h> @@ -788,6 +786,10 @@ int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, l1sap.u.rach_ind.acc_delay = (toa >= 0) ? toa : 0; l1sap.u.rach_ind.fn = fn; + /* 11bit RACH is not supported for osmo-trx */ + l1sap.u.rach_ind.is_11bit = 0; + l1sap.u.rach_ind.burst_type = GSM_L1_BURST_TYPE_ACCESS_0; + /* forward primitive */ l1sap_up(l1t->trx, &l1sap); @@ -1123,7 +1125,7 @@ bfi: /* indicate bad frame */ switch (tch_mode) { case GSM48_CMODE_SPEECH_V1: /* FR */ - if (lchan->tch.ul_sid) + if (lchan->tch.dtx.ul_sid) return 0; /* DTXu: pause in progress */ memset(tch_data, 0, GSM_FR_BYTES); rc = GSM_FR_BYTES; @@ -1297,7 +1299,7 @@ bfi: /* indicate bad frame */ switch (tch_mode) { case GSM48_CMODE_SPEECH_V1: /* HR */ - if (lchan->tch.ul_sid) + if (lchan->tch.dtx.ul_sid) return 0; /* DTXu: pause in progress */ tch_data[0] = 0x70; /* F = 0, FT = 111 */ memset(tch_data + 1, 0, 14); diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index 42d383c3..989e77a7 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -281,6 +281,11 @@ int trx_if_cmd_setmaxdly(struct trx_l1h *l1h, int dly) return trx_ctrl_cmd(l1h, 0, "SETMAXDLY", "%d", dly); } +int trx_if_cmd_setmaxdlynb(struct trx_l1h *l1h, int dly) +{ + return trx_ctrl_cmd(l1h, 0, "SETMAXDLYNB", "%d", dly); +} + int trx_if_cmd_setslot(struct trx_l1h *l1h, uint8_t tn, uint8_t type) { return trx_ctrl_cmd(l1h, 1, "SETSLOT", "%d %d", tn, type); diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h index 8659c4a8..fdc8a8d3 100644 --- a/src/osmo-bts-trx/trx_if.h +++ b/src/osmo-bts-trx/trx_if.h @@ -22,6 +22,7 @@ int trx_if_cmd_setbsic(struct trx_l1h *l1h, uint8_t bsic); int trx_if_cmd_setrxgain(struct trx_l1h *l1h, int db); int trx_if_cmd_setpower(struct trx_l1h *l1h, int db); int trx_if_cmd_setmaxdly(struct trx_l1h *l1h, int dly); +int trx_if_cmd_setmaxdlynb(struct trx_l1h *l1h, int dly); int trx_if_cmd_setslot(struct trx_l1h *l1h, uint8_t tn, uint8_t type); int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn); int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn); diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c index 3aec8bae..ca347e8d 100644 --- a/src/osmo-bts-trx/trx_vty.c +++ b/src/osmo-bts-trx/trx_vty.c @@ -105,6 +105,11 @@ static void show_phy_inst_single(struct vty *vty, struct phy_instance *pinst) VTY_NEWLINE); else vty_out(vty, " maxdly : undefined%s", VTY_NEWLINE); + if (l1h->config.maxdlynb_valid) + vty_out(vty, " maxdlynb : %d%s", l1h->config.maxdlynb, + VTY_NEWLINE); + else + vty_out(vty, " maxdlynb : undefined%s", VTY_NEWLINE); for (tn = 0; tn < TRX_NR_TS; tn++) { if (!((1 << tn) & l1h->config.slotmask)) vty_out(vty, " slot #%d: unsupported%s", tn, @@ -239,7 +244,13 @@ DEFUN(cfg_bts_no_setbsic, cfg_bts_no_setbsic_cmd, DEFUN(cfg_phyinst_maxdly, cfg_phyinst_maxdly_cmd, "osmotrx maxdly <0-31>", - "Set the maximum delay of GSM symbols\n" + "Set the maximum acceptable delay of an Access Burst (in GSM symbols)." + " Access Burst is the first burst a mobile transmits in order to establish" + " a connection and it is used to estimate Timing Advance (TA) which is" + " then applied to Normal Bursts to compensate for signal delay due to" + " distance. So changing this setting effectively changes maximum range of" + " the cell, because if we receive an Access Burst with a delay higher than" + " this value, it will be ignored and connection is dropped.\n" "GSM symbols (approx. 1.1km per symbol)\n") { struct phy_instance *pinst = vty->index; @@ -253,6 +264,31 @@ DEFUN(cfg_phyinst_maxdly, cfg_phyinst_maxdly_cmd, return CMD_SUCCESS; } + +DEFUN(cfg_phyinst_maxdlynb, cfg_phyinst_maxdlynb_cmd, + "osmotrx maxdlynb <0-31>", + "Set the maximum acceptable delay of a Normal Burst (in GSM symbols)." + " USE FOR TESTING ONLY, DON'T CHANGE IN PRODUCTION USE!" + " During normal operation, Normal Bursts delay are controled by a Timing" + " Advance control loop and thus Normal Bursts arrive to a BTS with no more" + " than a couple GSM symbols, which is already taken into account in osmo-trx." + " So changing this setting will have no effect in production installations" + " except increasing osmo-trx CPU load. This setting is only useful when" + " testing with a transmitter which can't precisely synchronize to the BTS" + " downlink signal, like e.g. R&S CMD57.\n" + "GSM symbols (approx. 1.1km per symbol)\n") +{ + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + + l1h->config.maxdlynb = atoi(argv[0]); + l1h->config.maxdlynb_valid = 1; + l1h->config.maxdlynb_sent = 0; + l1if_provision_transceiver_trx(l1h); + + return CMD_SUCCESS; +} + DEFUN(cfg_phyinst_slotmask, cfg_phyinst_slotmask_cmd, "slotmask (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0)", "Set the supported slots\n" @@ -400,6 +436,18 @@ DEFUN(cfg_phyinst_no_maxdly, cfg_phyinst_no_maxdly_cmd, return CMD_SUCCESS; } +DEFUN(cfg_phyinst_no_maxdlynb, cfg_phyinst_no_maxdlynb_cmd, + "no osmotrx maxdlynb", + NO_STR "Unset the maximum delay of GSM symbols\n") +{ + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + + l1h->config.maxdlynb_valid = 0; + + return CMD_SUCCESS; +} + DEFUN(cfg_phy_transc_ip, cfg_phy_transc_ip_cmd, "osmotrx ip HOST", OSMOTRX_STR @@ -458,6 +506,8 @@ void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst if (l1h->config.maxdly_valid) vty_out(vty, " maxdly %d%s", l1h->config.maxdly, VTY_NEWLINE); + if (l1h->config.maxdlynb_valid) + vty_out(vty, " maxdlynb %d%s", l1h->config.maxdlynb, VTY_NEWLINE); if (l1h->config.slotmask != 0xff) vty_out(vty, " slotmask %d %d %d %d %d %d %d %d%s", l1h->config.slotmask & 1, @@ -520,6 +570,8 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(PHY_INST_NODE, &cfg_phy_power_on_cmd); install_element(PHY_INST_NODE, &cfg_phyinst_maxdly_cmd); install_element(PHY_INST_NODE, &cfg_phyinst_no_maxdly_cmd); + install_element(PHY_INST_NODE, &cfg_phyinst_maxdlynb_cmd); + install_element(PHY_INST_NODE, &cfg_phyinst_no_maxdlynb_cmd); return 0; } diff --git a/tests/agch/Makefile.am b/tests/agch/Makefile.am index 39cb83b8..46b55e9f 100644 --- a/tests/agch/Makefile.am +++ b/tests/agch/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) -AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(ORTP_CFLAGS) -LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(ORTP_LIBS) +AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(ORTP_CFLAGS) +LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCODEC_LIBS) $(ORTP_LIBS) noinst_PROGRAMS = agch_test EXTRA_DIST = agch_test.ok diff --git a/tests/agch/agch_test.c b/tests/agch/agch_test.c index 4175bdd6..e275c644 100644 --- a/tests/agch/agch_test.c +++ b/tests/agch/agch_test.c @@ -224,11 +224,8 @@ static void test_agch_queue_length_computation(void) int main(int argc, char **argv) { - void *tall_msgb_ctx; - tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context"); - tall_msgb_ctx = talloc_named_const(tall_bts_ctx, 1, "msgb"); - msgb_set_talloc_ctx(tall_msgb_ctx); + msgb_talloc_ctx_init(tall_bts_ctx, 0); bts_log_init(NULL); diff --git a/tests/bursts/bursts_test.c b/tests/bursts/bursts_test.c index 43764ab3..d4bb3e0b 100644 --- a/tests/bursts/bursts_test.c +++ b/tests/bursts/bursts_test.c @@ -349,6 +349,8 @@ static void test_pdtch(uint8_t *l2, int len) int n_errors, n_bits_total; int rc; + memset(result, 0xff, len); + /* zero the not coded tail bits */ switch (len) { case 34: diff --git a/tests/cipher/Makefile.am b/tests/cipher/Makefile.am index b80713ac..d76dcd57 100644 --- a/tests/cipher/Makefile.am +++ b/tests/cipher/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) -AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(ORTP_CFLAGS) -LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(ORTP_LIBS) +AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(ORTP_CFLAGS) +LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCODEC_LIBS) $(ORTP_LIBS) noinst_PROGRAMS = cipher_test EXTRA_DIST = cipher_test.ok diff --git a/tests/cipher/cipher_test.c b/tests/cipher/cipher_test.c index a175012f..c913925e 100644 --- a/tests/cipher/cipher_test.c +++ b/tests/cipher/cipher_test.c @@ -66,11 +66,8 @@ static void test_cipher_parsing(void) int main(int argc, char **argv) { - void *tall_msgb_ctx; - tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context"); - tall_msgb_ctx = talloc_named_const(tall_bts_ctx, 1, "msgb"); - msgb_set_talloc_ctx(tall_msgb_ctx); + msgb_talloc_ctx_init(tall_bts_ctx, 0); bts_log_init(NULL); diff --git a/tests/handover/handover_test.c b/tests/handover/handover_test.c index e1f4d86d..a7a66d06 100644 --- a/tests/handover/handover_test.c +++ b/tests/handover/handover_test.c @@ -58,7 +58,6 @@ int main(int argc, char **argv) { struct gsm_bts_role_bts *btsb; void *tall_bts_ctx; - void *tall_msgb_ctx; struct e1inp_line *line; struct gsm_lchan *lchan; struct osmo_phsap_prim nl1sap; @@ -67,8 +66,7 @@ int main(int argc, char **argv) int i; tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context"); - tall_msgb_ctx = talloc_named_const(tall_bts_ctx, 1, "msgb"); - msgb_set_talloc_ctx(tall_msgb_ctx); + msgb_talloc_ctx_init(tall_bts_ctx, 0); bts_log_init(NULL); osmo_stderr_target->categories[DHO].loglevel = LOGL_DEBUG; @@ -277,3 +275,5 @@ void trx_get_hlayer1(void) {} int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan) { return 0; } int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts) { return 0; } int bts_model_ts_connect(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_pchan) { return 0; } +int bts_model_lchan_deactivate(struct gsm_lchan *lchan) { return 0; } +int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan) { return 0; } diff --git a/tests/misc/Makefile.am b/tests/misc/Makefile.am index f60325b0..d5acb18a 100644 --- a/tests/misc/Makefile.am +++ b/tests/misc/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) -AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) -LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) +AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) +LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) noinst_PROGRAMS = misc_test EXTRA_DIST = misc_test.ok diff --git a/tests/paging/Makefile.am b/tests/paging/Makefile.am index b6d6d78e..be9de745 100644 --- a/tests/paging/Makefile.am +++ b/tests/paging/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) -AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(ORTP_CFLAGS) -LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(ORTP_LIBS) +AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(ORTP_CFLAGS) +LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCODEC_LIBS) $(ORTP_LIBS) noinst_PROGRAMS = paging_test EXTRA_DIST = paging_test.ok diff --git a/tests/paging/paging_test.c b/tests/paging/paging_test.c index de839e47..1d5f2162 100644 --- a/tests/paging/paging_test.c +++ b/tests/paging/paging_test.c @@ -112,11 +112,8 @@ static void test_paging_sleep(void) int main(int argc, char **argv) { - void *tall_msgb_ctx; - tall_bts_ctx = talloc_named_const(NULL, 1, "OsmoBTS context"); - tall_msgb_ctx = talloc_named_const(tall_bts_ctx, 1, "msgb"); - msgb_set_talloc_ctx(tall_msgb_ctx); + msgb_talloc_ctx_init(tall_bts_ctx, 0); bts_log_init(NULL); diff --git a/tests/stubs.c b/tests/stubs.c index c680db04..f969cb3c 100644 --- a/tests/stubs.c +++ b/tests/stubs.c @@ -40,6 +40,8 @@ int bts_model_oml_estab(struct gsm_bts *bts) int l1if_set_txpower(struct femtol1_hdl *fl1h, float tx_power) { return 0; } +int bts_model_lchan_deactivate(struct gsm_lchan *lchan) { return 0; } +int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan) { return 0; } int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan) { return 0; } |