forked from cellular-infrastructure/osmo-pcu
Compare commits
64 Commits
master
...
radisys/eg
Author | SHA1 | Date |
---|---|---|
Aravind Sirsikar | 3157c337e9 | |
Aravind Sirsikar | 41ba74c669 | |
Aravind Sirsikar | 6d520405df | |
Aravind Sirsikar | a2b3215000 | |
Aravind Sirsikar | 998f3aae47 | |
Aravind Sirsikar | 604d55e050 | |
Aravind Sirsikar | 0f29b91aff | |
Aravind Sirsikar | e855e1cdac | |
Aravind Sirsikar | e0386e3948 | |
Aravind Sirsikar | 7631182563 | |
Aravind Sirsikar | 7b800323a5 | |
Aravind Sirsikar | a36b5d7896 | |
Alexander Couzens | cb846ecbbc | |
Alexander Couzens | b82bd92e57 | |
Aravind Sirsikar | 93ef548a43 | |
Aravind Sirsikar | 6c0ff27cb5 | |
Aravind Sirsikar | 7c70740484 | |
Aravind Sirsikar | b7cc6a4743 | |
Alexander Couzens | 2fcfc29020 | |
Alexander Couzens | ce936f3cd4 | |
Alexander Couzens | c1c9d6a9d8 | |
Alexander Couzens | c8fd4b7c42 | |
Alexander Couzens | f929e62525 | |
Alexander Couzens | 4acb6b7251 | |
Alexander Couzens | 95e379241a | |
Alexander Couzens | 543756adbe | |
Alexander Couzens | 2cb1547993 | |
Alexander Couzens | 9736d00b12 | |
Yves Godin | 660709dc7c | |
Aravind Sirsikar | b3c85bac48 | |
Aravind Sirsikar | 7106c361d6 | |
Aravind Sirsikar | db39e6cb72 | |
Aravind Sirsikar | 2da0dbc7e5 | |
Aravind Sirsikar | 14099d7b1b | |
Aravind Sirsikar | 459e856b70 | |
Aravind Sirsikar | ebebf5d175 | |
Aravind Sirsikar | ef12a45d46 | |
Aravind Sirsikar | be3dc223f1 | |
Aravind Sirsikar | d14add5c2e | |
Aravind Sirsikar | f666f9585d | |
Aravind Sirsikar | 7b01c15b6c | |
Aravind Sirsikar | 5974ec7609 | |
Max | 58b6646750 | |
Alexander Couzens | ed3ae4a392 | |
Yves Godin | f0bb25450c | |
Max | de810f2005 | |
Max | cad867ec8d | |
Max | 280448ba7b | |
Holger Hans Peter Freyther | 1aa7527302 | |
Holger Hans Peter Freyther | ca025c02ef | |
Holger Hans Peter Freyther | 97e48a3252 | |
Harald Welte | 63d33ad2d7 | |
Aravind Sirsikar | 7952282b78 | |
Aravind Sirsikar | a859a21800 | |
Aravind Sirsikar | 7a05b039c8 | |
Bhargava Abhyankar | e44383baa4 | |
Aravind Sirsikar | 5a5d2b7a27 | |
Saurabh Sharan | 2b09c39c9c | |
Saurabh Sharan | bacb65b48b | |
Saurabh Sharan | 656eed5975 | |
Holger Hans Peter Freyther | 173ef90a53 | |
Holger Hans Peter Freyther | fd263b0dfd | |
Holger Hans Peter Freyther | 99db40ad2d | |
Max | 22d7e75e1f |
|
@ -14,10 +14,11 @@ config.guess
|
|||
config.sub
|
||||
config.status
|
||||
configure
|
||||
compile
|
||||
depcomp
|
||||
install-sh
|
||||
missing
|
||||
libtool
|
||||
*libtool
|
||||
ltmain.sh
|
||||
|
||||
core
|
||||
|
@ -43,3 +44,17 @@ tests/codel/codel_test
|
|||
tests/emu/pcu_emu
|
||||
tests/testsuite
|
||||
tests/testsuite.log
|
||||
tests/edge/EdgeTest
|
||||
tests/llc/LlcTest
|
||||
|
||||
# ignore debian files
|
||||
.tarball-version
|
||||
debian/autoreconf.after
|
||||
debian/autoreconf.before
|
||||
debian/files
|
||||
debian/*.debhelper*
|
||||
debian/*.substvars
|
||||
debian/osmo-pcu-dbg/
|
||||
debian/osmo-pcu.substvars
|
||||
debian/osmo-pcu/
|
||||
debian/tmp/
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[gerrit]
|
||||
host=gerrit.osmocom.org
|
||||
project=osmo-pcu
|
10
README
10
README
|
@ -2,6 +2,15 @@ This is an implementation of Packet Control Unit (PCU) according to TS 04.60
|
|||
|
||||
The PCU is part of BSS, so it connects directly to SGSN.
|
||||
|
||||
The performance tests are done with following commit versions of osmo
|
||||
components
|
||||
|
||||
libosmocore: b897c4299329688bb0aba6e32cd10b361bda1dee
|
||||
osmo-bts: 99642656a067c2e16a1b2f1e5eb34529564c584d
|
||||
libosmo-abis: 085ab0bb9ce99693e8b06acf721cf415abc08cf0
|
||||
openbsc : 2ebacce4fa5ab8f3be42967033644739d78c80bf
|
||||
Ggsn : 86540de7f37d841b9a45cc6c67a68f714c1866dc
|
||||
Libosmo-netif : 3583bc4f030b1b4bb637d17e4ca8a61b19bcfb58
|
||||
|
||||
== Current limitations ==
|
||||
|
||||
|
@ -17,4 +26,3 @@ The PCU is part of BSS, so it connects directly to SGSN.
|
|||
* No TA loop
|
||||
* No power loop
|
||||
* No CS loop
|
||||
* No EGPRS
|
||||
|
|
19
configure.ac
19
configure.ac
|
@ -35,6 +35,25 @@ AC_ARG_ENABLE(sysmocom-dsp,
|
|||
AC_MSG_RESULT([$enable_sysmocom_dsp])
|
||||
AM_CONDITIONAL(ENABLE_SYSMODSP, test "x$enable_sysmocom_dsp" = "xyes")
|
||||
|
||||
AC_MSG_CHECKING([whether to enable direct PHY access for PDCH of NuRAN Wireless Litecell 1.5 BTS])
|
||||
AC_ARG_ENABLE(lc15bts-phy,
|
||||
AC_HELP_STRING([--enable-lc15bts-phy],
|
||||
[enable code for Litecell 1.5 PHY [default=no]]),
|
||||
[enable_lc15bts_phy="$enableval"],[enable_lc15bts_phy="no"])
|
||||
AC_ARG_WITH([litecell15], [AS_HELP_STRING([--with-litecell15=INCLUDE_DIR], [Location of the litecell 1.5 API header files])],
|
||||
[litecell15_incdir="$withval"],[litecell15_incdir="$incdir"])
|
||||
AC_SUBST([LITECELL15_INCDIR], $litecell15_incdir)
|
||||
AC_MSG_RESULT([$enable_lc15bts_phy])
|
||||
AM_CONDITIONAL(ENABLE_LC15BTS_PHY, test "x$enable_lc15bts_phy" = "xyes")
|
||||
if test "$enable_litecell15" = "yes"; then
|
||||
oldCPPFLAGS=$CPPFLAGS
|
||||
CPPFLAGS="$CPPFLAGS -I$LITECELL15_INCDIR -I$srcdir/include $LIBOSMOCORE_CFLAGS"
|
||||
AC_CHECK_HEADER([nrw/litecell15/litecell15.h],[],
|
||||
[AC_MSG_ERROR([nrw/litecell15/litecell15.h can not be found in $litecell15_incdir])],
|
||||
[#include <nrw/litecell15/litecell15.h>])
|
||||
CPPFLAGS=$oldCPPFLAGS
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE([vty_tests],
|
||||
AC_HELP_STRING([--enable-vty-tests],
|
||||
[Include the VTY tests in make check [default=no]]),
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
if [ $sysmobts = "no" -a $sysmodsp = "yes" ]; then
|
||||
echo "This config does not make sense."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -rf deps/install
|
||||
mkdir deps || true
|
||||
cd deps
|
||||
osmo-deps.sh libosmocore
|
||||
|
||||
cd libosmocore
|
||||
autoreconf --install --force
|
||||
./configure --prefix=$PWD/../install
|
||||
$MAKE $PARALLEL_MAKE install
|
||||
|
||||
# Install the API
|
||||
cd ../
|
||||
if ! test -d layer1-api;
|
||||
then
|
||||
git clone git://git.sysmocom.de/sysmo-bts/layer1-api.git layer1-api
|
||||
fi
|
||||
|
||||
cd layer1-api
|
||||
git fetch origin
|
||||
git reset --hard origin/master
|
||||
mkdir -p $PWD/../install/include/sysmocom/femtobts/
|
||||
cp include/*.h ../install/include/sysmocom/femtobts/
|
||||
|
||||
cd ../../
|
||||
autoreconf --install --force
|
||||
BTS_CONFIG="--enable-sysmocom-bts=$sysmobts --enable-sysmocom-dsp=$sysmodsp"
|
||||
if [ $sysmobts = "no" ]; then
|
||||
BTS_CONFIG="$BTS_CONFIG --enable-vty-tests"
|
||||
fi
|
||||
|
||||
PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig ./configure $BTS_CONFIG
|
||||
PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE
|
||||
DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" AM_DISTCHECK_CONFIGURE_FLAGS="$BTS_CONFIG" PKG_CONFIG_PATH=$PWD/deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/deps/install/lib $MAKE distcheck
|
|
@ -0,0 +1,5 @@
|
|||
osmo-pcu (0.3) UNRELEASED; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- Holger Hans Peter Freyther <holger@moiji-mobile.com> Fri, 01 Apr 2016 18:59:00 +0200
|
|
@ -0,0 +1 @@
|
|||
7
|
|
@ -0,0 +1,24 @@
|
|||
Source: osmo-pcu
|
||||
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
|
||||
Standards-Version: 3.8.4
|
||||
Homepage: http://osmocom.org/projects/osmopcu
|
||||
Vcs-Git: git://git.osmocom.org/osmo-pcu
|
||||
Vcs-Browser: http://git.osmocom.org/osmo-pcu/
|
||||
|
||||
Package: osmo-pcu
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: osmo-pcu GSM PCU for GPRS and EDGE
|
||||
osmo-pcu for GPRS and EDGE support in the network
|
||||
|
||||
Package: osmo-pcu-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: osmo-pcu (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debug symbols for the osmo-pcu
|
||||
Make debugging possible
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
etc/osmocom/osmo-pcu.cfg
|
||||
usr/bin/osmo-pcu
|
|
@ -0,0 +1,15 @@
|
|||
[Unit]
|
||||
Description=Osmocom osmo-pcu
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/osmo-pcu -c /etc/osmocom/osmo-pcu.cfg
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
|
||||
# Read quickly enough
|
||||
CPUSchedulingPolicy=rr
|
||||
CPUSchedulingPriority=1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
DEBIAN := $(shell dpkg-parsechangelog | grep ^Version: | cut -d' ' -f2)
|
||||
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
|
||||
|
||||
|
||||
%:
|
||||
dh $@ --with=systemd --with autoreconf --fail-missing
|
||||
|
||||
override_dh_strip:
|
||||
dh_strip --dbg-package=osmo-pcu-dbg
|
||||
|
||||
override_dh_autoreconf:
|
||||
echo $(VERSION) > .tarball-version
|
||||
dh_autoreconf
|
|
@ -0,0 +1 @@
|
|||
3.0 (native)
|
|
@ -1,6 +1,23 @@
|
|||
pcu
|
||||
egprs only
|
||||
flow-control-interval 10
|
||||
cs 2
|
||||
alloc-algorithm dynamic
|
||||
flow-control force-bvc-bucket-size 596000
|
||||
flow-control force-bvc-leak-rate 59600
|
||||
flow-control force-ms-bucket-size 596000
|
||||
flow-control force-ms-leak-rate 59600
|
||||
cs 4
|
||||
cs max 4
|
||||
no cs threshold
|
||||
no cs downgrade-threshold
|
||||
cs link-quality-ranges cs1 6 cs2 5 8 cs3 7 13 cs4 12
|
||||
mcs 9 4
|
||||
mcs max 9 4
|
||||
window-size 64 104
|
||||
queue lifetime infinite
|
||||
queue idle-ack-delay 10
|
||||
no queue codel
|
||||
alloc-algorithm b
|
||||
two-phase-access
|
||||
alpha 0
|
||||
gamma 0
|
||||
dl-tbf-idle-time 2000
|
||||
|
|
|
@ -18,10 +18,15 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = subdir-objects
|
||||
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS)
|
||||
|
||||
if ENABLE_SYSMODSP
|
||||
AM_CPPFLAGS += -DENABLE_SYSMODSP
|
||||
AM_CPPFLAGS += -DENABLE_DIRECT_PHY
|
||||
endif
|
||||
|
||||
if ENABLE_LC15BTS_PHY
|
||||
AM_CPPFLAGS += -DENABLE_DIRECT_PHY
|
||||
endif
|
||||
|
||||
AM_CXXFLAGS = -Wall -ldl -pthread
|
||||
|
@ -64,11 +69,6 @@ bin_PROGRAMS = \
|
|||
|
||||
noinst_PROGRAMS =
|
||||
|
||||
if ENABLE_SYSMODSP
|
||||
noinst_PROGRAMS += \
|
||||
osmo-pcu-remote
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
gprs_debug.h \
|
||||
csn1.h \
|
||||
|
@ -83,8 +83,6 @@ noinst_HEADERS = \
|
|||
bitvector.h \
|
||||
pcu_vty.h \
|
||||
pcu_vty_functions.h \
|
||||
sysmo_l1_if.h \
|
||||
femtobts.h \
|
||||
tbf.h \
|
||||
bts.h \
|
||||
poll_controller.h \
|
||||
|
@ -101,14 +99,59 @@ noinst_HEADERS = \
|
|||
osmo_pcu_SOURCES = pcu_main.cpp
|
||||
|
||||
if ENABLE_SYSMODSP
|
||||
osmo_pcu_SOURCES += sysmo_l1_if.c \
|
||||
sysmo_l1_hw.c \
|
||||
femtobts.c
|
||||
AM_CPPFLAGS += -I$(srcdir)/osmo-bts-sysmo
|
||||
|
||||
osmo_pcu_remote_SOURCES = pcu_main.cpp \
|
||||
sysmo_l1_if.c \
|
||||
sysmo_l1_fwd.c \
|
||||
femtobts.c
|
||||
EXTRA_DIST = \
|
||||
osmo-bts-sysmo/sysmo_l1_if.c \
|
||||
osmo-bts-sysmo/sysmo_l1_if.h \
|
||||
osmo-bts-sysmo/sysmo_l1_hw.c \
|
||||
osmo-bts-sysmo/femtobts.c \
|
||||
osmo-bts-sysmo/femtobts.h
|
||||
|
||||
noinst_HEADERS += \
|
||||
osmo-bts-sysmo/sysmo_l1_if.h \
|
||||
osmo-bts-sysmo/femtobts.h
|
||||
|
||||
noinst_PROGRAMS += \
|
||||
osmo-pcu-remote
|
||||
|
||||
osmo_pcu_SOURCES += \
|
||||
osmo-bts-sysmo/sysmo_l1_if.c \
|
||||
osmo-bts-sysmo/sysmo_l1_hw.c \
|
||||
osmo-bts-sysmo/femtobts.c
|
||||
|
||||
osmo_pcu_remote_SOURCES = \
|
||||
pcu_main.cpp \
|
||||
osmo-bts-sysmo/sysmo_l1_if.c \
|
||||
osmo-bts-sysmo/sysmo_l1_fwd.c \
|
||||
osmo-bts-sysmo/femtobts.c
|
||||
|
||||
osmo_pcu_remote_LDADD = \
|
||||
libgprs.la \
|
||||
$(LIBOSMOGB_LIBS) \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(COMMON_LA)
|
||||
endif
|
||||
|
||||
if ENABLE_LC15BTS_PHY
|
||||
AM_CPPFLAGS += -I$(LITECELL15_INCDIR) -I$(srcdir)/osmo-bts-litecell15
|
||||
|
||||
EXTRA_DIST = \
|
||||
osmo-bts-litecell15/lc15_l1_if.c \
|
||||
osmo-bts-litecell15/lc15_l1_if.h \
|
||||
osmo-bts-litecell15/lc15_l1_hw.c \
|
||||
osmo-bts-litecell15/lc15bts.c \
|
||||
osmo-bts-litecell15/lc15bts.h
|
||||
|
||||
noinst_HEADERS += \
|
||||
osmo-bts-litecell15/lc15_l1_if.h \
|
||||
osmo-bts-litecell15/lc15bts.h
|
||||
|
||||
osmo_pcu_SOURCES += \
|
||||
osmo-bts-litecell15/lc15_l1_if.c \
|
||||
osmo-bts-litecell15/lc15_l1_hw.c \
|
||||
osmo-bts-litecell15/lc15bts.c
|
||||
endif
|
||||
|
||||
osmo_pcu_LDADD = \
|
||||
|
@ -118,13 +161,4 @@ osmo_pcu_LDADD = \
|
|||
$(LIBOSMOGSM_LIBS) \
|
||||
$(COMMON_LA)
|
||||
|
||||
if ENABLE_SYSMODSP
|
||||
osmo_pcu_remote_LDADD = \
|
||||
libgprs.la \
|
||||
$(LIBOSMOGB_LIBS) \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(COMMON_LA)
|
||||
endif
|
||||
|
||||
#MOSTLYCLEANFILES += testSource testDestination
|
||||
|
|
65
src/bts.cpp
65
src/bts.cpp
|
@ -44,6 +44,9 @@ extern void *tall_pcu_ctx;
|
|||
|
||||
static BTS s_bts;
|
||||
|
||||
char log_xx[8000][500];
|
||||
uint32_t log_ptr = 0;
|
||||
extern bool error_hit ;
|
||||
/**
|
||||
* For gcc-4.4 compat do not use extended initializer list but keep the
|
||||
* order from the enum here. Once we support GCC4.7 and up we can change
|
||||
|
@ -64,6 +67,7 @@ static const struct rate_ctr_desc bts_ctr_description[] = {
|
|||
{ "rlc.resent", "RLC Resent "},
|
||||
{ "rlc.restarted", "RLC Restarted "},
|
||||
{ "rlc.stalled", "RLC Stalled "},
|
||||
{ "rlc.ulstalled", "RLC UlStalled "},
|
||||
{ "rlc.nacked", "RLC Nacked "},
|
||||
{ "rlc.ass.timedout", "RLC Assign Timeout "},
|
||||
{ "rlc.ass.failed", "RLC Assign Failed "},
|
||||
|
@ -71,13 +75,22 @@ static const struct rate_ctr_desc bts_ctr_description[] = {
|
|||
{ "rlc.ack.failed", "RLC Ack Failed "},
|
||||
{ "rlc.rel.timedout", "RLC Release Timeout "},
|
||||
{ "rlc.late-block", "RLC Late Block "},
|
||||
{ "rlc.sent-dummy", "RLC Sent Dummy "},
|
||||
{ "rlc.sent-control", "RLC Sent Control "},
|
||||
{ "rlc.dl_bytes", "RLC DL Bytes "},
|
||||
{ "rlc.dl_payload_bytes", "RLC DL Payload Bytes "},
|
||||
{ "rlc.ul_bytes", "RLC UL Bytes "},
|
||||
{ "rlc.ul_payload_bytes", "RLC UL Payload Bytes "},
|
||||
{ "decode.errors", "Decode Errors "},
|
||||
{ "llc_decode.err", "llc Decode Errors "},
|
||||
{ "sba.allocated", "SBA Allocated "},
|
||||
{ "sba.freed", "SBA Freed "},
|
||||
{ "sba.timedout", "SBA Timeout "},
|
||||
{ "llc.timeout", "Timedout Frames "},
|
||||
{ "llc.dropped", "Dropped Frames "},
|
||||
{ "llc.scheduled", "Scheduled Frames "},
|
||||
{ "llc.dl_bytes", "RLC encapsulated PDUs"},
|
||||
{ "llc.ul_bytes", "full PDUs received "},
|
||||
{ "rach.requests", "RACH requests "},
|
||||
};
|
||||
|
||||
|
@ -475,6 +488,10 @@ int BTS::rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta)
|
|||
|
||||
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF on RACH, so we provide "
|
||||
"one:\n");
|
||||
#if 1
|
||||
sprintf(log_xx[log_ptr++ % 8000],"MS req UTBF on RACH,provide "
|
||||
"one:\n");
|
||||
#endif
|
||||
if ((ra & 0xf8) == 0x70) {
|
||||
LOGP(DRLCMAC, LOGL_DEBUG, "MS requests single block "
|
||||
"allocation\n");
|
||||
|
@ -1041,6 +1058,12 @@ void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nac
|
|||
LOGP(DRLCMAC, LOGL_DEBUG,
|
||||
"RX: [PCU <- BTS] %s EGPRS Packet Downlink Ack/Nack\n",
|
||||
tbf_name(tbf));
|
||||
|
||||
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf);
|
||||
#if 1
|
||||
sprintf(log_xx[log_ptr++ % 8000],"RX: [PCU <- BTS] %s EGPRS Packet Downlink Ack/Nack rx_fn(%d) ts(%d), poll_fn(%d) curr_fn(%d), va(%d) vs(%d)\n",
|
||||
tbf_name(tbf), fn, ts_no, tbf->poll_fn, bts()->current_frame_number(), dl_tbf->m_window.v_a(), dl_tbf->m_window.v_s());
|
||||
#endif
|
||||
tbf->poll_state = GPRS_RLCMAC_POLL_NONE;
|
||||
|
||||
LOGP(DRLCMAC, LOGL_DEBUG, "EGPRS ACK/NACK: "
|
||||
|
@ -1061,7 +1084,26 @@ void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nac
|
|||
tbf->m_window.v_s(),
|
||||
osmo_hexdump((const uint8_t *)&ack_nack->EGPRS_AckNack.Desc.URBB,
|
||||
sizeof(ack_nack->EGPRS_AckNack.Desc.URBB)));
|
||||
|
||||
#if 1
|
||||
sprintf(log_xx[log_ptr++ % 8000],"EGPRS ACK/NACK: "
|
||||
"ut: %d, final: %d, bow: %d, eow: %d, ssn: %d, have_crbb: %d, "
|
||||
"urbb_len:%d, %p, %p, %d, %d, win: %d-%d, urbb: %s\n",
|
||||
(int)ack_nack->EGPRS_AckNack.UnionType,
|
||||
(int)ack_nack->EGPRS_AckNack.Desc.FINAL_ACK_INDICATION,
|
||||
(int)ack_nack->EGPRS_AckNack.Desc.BEGINNING_OF_WINDOW,
|
||||
(int)ack_nack->EGPRS_AckNack.Desc.END_OF_WINDOW,
|
||||
(int)ack_nack->EGPRS_AckNack.Desc.STARTING_SEQUENCE_NUMBER,
|
||||
(int)ack_nack->EGPRS_AckNack.Desc.Exist_CRBB,
|
||||
(int)ack_nack->EGPRS_AckNack.Desc.URBB_LENGTH,
|
||||
(void *)&ack_nack->EGPRS_AckNack.UnionType,
|
||||
(void *)&ack_nack->EGPRS_AckNack.Desc,
|
||||
(int)offsetof(EGPRS_AckNack_t, Desc),
|
||||
(int)offsetof(EGPRS_AckNack_w_len_t, Desc),
|
||||
tbf->m_window.v_a(),
|
||||
tbf->m_window.v_s(),
|
||||
osmo_hexdump((const uint8_t *)&ack_nack->EGPRS_AckNack.Desc.URBB,
|
||||
sizeof(ack_nack->EGPRS_AckNack.Desc.URBB)));
|
||||
#endif
|
||||
bits.data = bits_data;
|
||||
bits.data_len = sizeof(bits_data);
|
||||
bits.cur_bit = 0;
|
||||
|
@ -1145,10 +1187,16 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
|
|||
}
|
||||
|
||||
if (dl_tbf) {
|
||||
uint32_t log_ptrx = log_ptr;
|
||||
sprintf(log_xx[log_ptr++ % 8000],"Got RACH from "
|
||||
"TLLI=0x%08x while %s still exists. "
|
||||
"Release pending DL TBF=%d llc_size(%d) llc_octets(%d) log_ptr(%d)\n", tlli,
|
||||
tbf_name(dl_tbf), dl_tbf->tfi(), dl_tbf->llc_queue()->size(), dl_tbf->llc_queue()->octets(), log_ptrx);
|
||||
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
|
||||
"TLLI=0x%08x while %s still exists. "
|
||||
"Release pending DL TBF\n", tlli,
|
||||
tbf_name(dl_tbf));
|
||||
error_hit = true;
|
||||
tbf_free(dl_tbf);
|
||||
dl_tbf = NULL;
|
||||
}
|
||||
|
@ -1300,6 +1348,8 @@ int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
bts()->rlc_ul_bytes(len);
|
||||
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG, "Got RLC block, coding scheme: %s, "
|
||||
"length: %d (%d))\n", cs.name(), len, cs.usedSizeUL());
|
||||
|
||||
|
@ -1315,6 +1365,7 @@ int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*! \brief process egprs and gprs data blocks */
|
||||
int gprs_rlcmac_pdch::rcv_data_block(uint8_t *data, uint32_t fn,
|
||||
struct pcu_l1_meas *meas, GprsCodingScheme cs)
|
||||
{
|
||||
|
@ -1333,15 +1384,6 @@ int gprs_rlcmac_pdch::rcv_data_block(uint8_t *data, uint32_t fn,
|
|||
cs.name());
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!cs.isEgprsGmsk()) {
|
||||
LOGP(DRLCMACUL, LOGL_ERROR,
|
||||
"Got %s RLC block but EGPRS is not implemented "
|
||||
"for 8PSK yet\n",
|
||||
cs.name());
|
||||
bts()->decode_error();
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG, " UL data: %s\n", osmo_hexdump(data, len));
|
||||
|
@ -1388,6 +1430,9 @@ int gprs_rlcmac_pdch::rcv_block_gprs(uint8_t *data, uint32_t fn,
|
|||
break;
|
||||
case GPRS_RLCMAC_CONTROL_BLOCK:
|
||||
block = bitvec_alloc(len);
|
||||
|
||||
sprintf(log_xx[log_ptr++ % 8000],"%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x \n",data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22]);
|
||||
|
||||
if (!block)
|
||||
return -ENOMEM;
|
||||
bitvec_unpack(block, data);
|
||||
|
|
40
src/bts.h
40
src/bts.h
|
@ -183,12 +183,15 @@ struct gprs_rlcmac_bts {
|
|||
uint8_t force_two_phase;
|
||||
uint8_t alpha, gamma;
|
||||
uint8_t egprs_enabled;
|
||||
|
||||
/* Value 0 to support resegmentation enabled in DL, 1 for no reseg */
|
||||
uint8_t arq_type;
|
||||
uint32_t dl_tbf_idle_msec; /* hold time for idle DL TBFs */
|
||||
uint32_t ms_idle_sec;
|
||||
uint8_t cs_adj_enabled;
|
||||
uint8_t cs_adj_upper_limit;
|
||||
uint8_t cs_adj_lower_limit;
|
||||
struct {int16_t low; int16_t high;} cs_lqual_ranges[4];
|
||||
struct {int16_t low; int16_t high; } cs_lqual_ranges[9];
|
||||
uint16_t cs_downgrade_threshold; /* downgrade if less packets left (DL) */
|
||||
uint16_t ws_base;
|
||||
uint16_t ws_pdch; /* increase WS by this value per PDCH */
|
||||
|
@ -226,6 +229,7 @@ public:
|
|||
CTR_RLC_RESENT,
|
||||
CTR_RLC_RESTARTED,
|
||||
CTR_RLC_STALLED,
|
||||
CTR_RLC_UL_STALLED,
|
||||
CTR_RLC_NACKED,
|
||||
CTR_RLC_ASS_TIMEDOUT,
|
||||
CTR_RLC_ASS_FAILED,
|
||||
|
@ -233,13 +237,22 @@ public:
|
|||
CTR_RLC_ACK_FAILED,
|
||||
CTR_RLC_REL_TIMEDOUT,
|
||||
CTR_RLC_LATE_BLOCK,
|
||||
CTR_RLC_SENT_DUMMY,
|
||||
CTR_RLC_SENT_CONTROL,
|
||||
CTR_RLC_DL_BYTES,
|
||||
CTR_RLC_DL_PAYLOAD_BYTES,
|
||||
CTR_RLC_UL_BYTES,
|
||||
CTR_RLC_UL_PAYLOAD_BYTES,
|
||||
CTR_DECODE_ERRORS,
|
||||
CTR_LLC_DECODE_ERRORS,
|
||||
CTR_SBA_ALLOCATED,
|
||||
CTR_SBA_FREED,
|
||||
CTR_SBA_TIMEDOUT,
|
||||
CTR_LLC_FRAME_TIMEDOUT,
|
||||
CTR_LLC_FRAME_DROPPED,
|
||||
CTR_LLC_FRAME_SCHED,
|
||||
CTR_LLC_DL_BYTES,
|
||||
CTR_LLC_UL_BYTES,
|
||||
CTR_RACH_REQUESTS,
|
||||
};
|
||||
|
||||
|
@ -302,6 +315,7 @@ public:
|
|||
void rlc_resent();
|
||||
void rlc_restarted();
|
||||
void rlc_stalled();
|
||||
void rlc_ul_stalled();
|
||||
void rlc_nacked();
|
||||
void rlc_ass_timedout();
|
||||
void rlc_ass_failed();
|
||||
|
@ -309,13 +323,22 @@ public:
|
|||
void rlc_ack_failed();
|
||||
void rlc_rel_timedout();
|
||||
void rlc_late_block();
|
||||
void rlc_sent_dummy();
|
||||
void rlc_sent_control();
|
||||
void rlc_dl_bytes(int bytes);
|
||||
void rlc_dl_payload_bytes(int bytes);
|
||||
void rlc_ul_bytes(int bytes);
|
||||
void rlc_ul_payload_bytes(int bytes);
|
||||
void decode_error();
|
||||
void llc_decode_err();
|
||||
void sba_allocated();
|
||||
void sba_freed();
|
||||
void sba_timedout();
|
||||
void llc_timedout_frame();
|
||||
void llc_dropped_frame();
|
||||
void llc_frame_sched();
|
||||
void llc_dl_bytes(int bytes);
|
||||
void llc_ul_bytes(int bytes);
|
||||
void rach_frame();
|
||||
|
||||
void ms_present(int32_t n);
|
||||
|
@ -423,6 +446,11 @@ inline struct osmo_stat_item_group *BTS::stat_items() const
|
|||
return m_statg;
|
||||
}
|
||||
|
||||
#define CREATE_COUNT_ADD_INLINE(func_name, ctr_name) \
|
||||
inline void BTS::func_name(int inc) {\
|
||||
rate_ctr_add(&m_ratectrs->ctr[ctr_name], inc); \
|
||||
}
|
||||
|
||||
#define CREATE_COUNT_INLINE(func_name, ctr_name) \
|
||||
inline void BTS::func_name() {\
|
||||
rate_ctr_inc(&m_ratectrs->ctr[ctr_name]); \
|
||||
|
@ -442,6 +470,7 @@ CREATE_COUNT_INLINE(rlc_sent, CTR_RLC_SENT)
|
|||
CREATE_COUNT_INLINE(rlc_resent, CTR_RLC_RESENT)
|
||||
CREATE_COUNT_INLINE(rlc_restarted, CTR_RLC_RESTARTED)
|
||||
CREATE_COUNT_INLINE(rlc_stalled, CTR_RLC_STALLED)
|
||||
CREATE_COUNT_INLINE(rlc_ul_stalled, CTR_RLC_UL_STALLED)
|
||||
CREATE_COUNT_INLINE(rlc_nacked, CTR_RLC_NACKED)
|
||||
CREATE_COUNT_INLINE(rlc_ass_timedout, CTR_RLC_ASS_TIMEDOUT);
|
||||
CREATE_COUNT_INLINE(rlc_ass_failed, CTR_RLC_ASS_FAILED);
|
||||
|
@ -449,13 +478,22 @@ CREATE_COUNT_INLINE(rlc_ack_timedout, CTR_RLC_ACK_TIMEDOUT);
|
|||
CREATE_COUNT_INLINE(rlc_ack_failed, CTR_RLC_ACK_FAILED);
|
||||
CREATE_COUNT_INLINE(rlc_rel_timedout, CTR_RLC_REL_TIMEDOUT);
|
||||
CREATE_COUNT_INLINE(rlc_late_block, CTR_RLC_LATE_BLOCK);
|
||||
CREATE_COUNT_INLINE(rlc_sent_dummy, CTR_RLC_SENT_DUMMY);
|
||||
CREATE_COUNT_INLINE(rlc_sent_control, CTR_RLC_SENT_CONTROL);
|
||||
CREATE_COUNT_ADD_INLINE(rlc_dl_bytes, CTR_RLC_DL_BYTES);
|
||||
CREATE_COUNT_ADD_INLINE(rlc_dl_payload_bytes, CTR_RLC_DL_PAYLOAD_BYTES);
|
||||
CREATE_COUNT_ADD_INLINE(rlc_ul_bytes, CTR_RLC_UL_BYTES);
|
||||
CREATE_COUNT_ADD_INLINE(rlc_ul_payload_bytes, CTR_RLC_UL_PAYLOAD_BYTES);
|
||||
CREATE_COUNT_INLINE(decode_error, CTR_DECODE_ERRORS)
|
||||
CREATE_COUNT_INLINE(llc_decode_err, CTR_DECODE_ERRORS)
|
||||
CREATE_COUNT_INLINE(sba_allocated, CTR_SBA_ALLOCATED)
|
||||
CREATE_COUNT_INLINE(sba_freed, CTR_SBA_FREED)
|
||||
CREATE_COUNT_INLINE(sba_timedout, CTR_SBA_TIMEDOUT)
|
||||
CREATE_COUNT_INLINE(llc_timedout_frame, CTR_LLC_FRAME_TIMEDOUT);
|
||||
CREATE_COUNT_INLINE(llc_dropped_frame, CTR_LLC_FRAME_DROPPED);
|
||||
CREATE_COUNT_INLINE(llc_frame_sched, CTR_LLC_FRAME_SCHED);
|
||||
CREATE_COUNT_ADD_INLINE(llc_dl_bytes, CTR_LLC_DL_BYTES);
|
||||
CREATE_COUNT_ADD_INLINE(llc_ul_bytes, CTR_LLC_UL_BYTES);
|
||||
CREATE_COUNT_INLINE(rach_frame, CTR_RACH_REQUESTS);
|
||||
|
||||
#undef CREATE_COUNT_INLINE
|
||||
|
|
10
src/csn1.cpp
10
src/csn1.cpp
|
@ -1112,6 +1112,8 @@ csnStreamDecoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector, unsig
|
|||
guint8* pui8 = pui8DATA(data, pDescr->offset);
|
||||
gint16 nB1 = no_of_bits & 0x07;/* no_of_bits Mod 8 */
|
||||
|
||||
no_of_bits -= nB1;
|
||||
|
||||
while (no_of_bits > 0)
|
||||
{
|
||||
*pui8 = bitvec_read_field(vector, readIndex, 8);
|
||||
|
@ -2400,7 +2402,12 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
|
|||
guint8 bits_to_handle = remaining_bits_len%8;
|
||||
if (bits_to_handle > 0)
|
||||
{
|
||||
guint8 fl = filler&(0xff>>(8-bits_to_handle));
|
||||
/* section 11 of 44.060
|
||||
* The padding bits may be the 'null' string. Otherwise, the
|
||||
* padding bits starts with bit '0', followed by 'spare padding'
|
||||
* < padding bits > ::= { null | 0 < spare padding > ! < Ignore : 1 bit** = < no string > > } ;
|
||||
*/
|
||||
guint8 fl = filler&(0xff>>(8-bits_to_handle + 1));
|
||||
bitvec_write_field(vector, writeIndex, fl, bits_to_handle);
|
||||
LOGPC(DCSN1, LOGL_NOTICE, "%u|", fl);
|
||||
remaining_bits_len -= bits_to_handle;
|
||||
|
@ -2499,6 +2506,7 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector
|
|||
bitvec_write_field(vector, writeIndex, !Tag, 1);
|
||||
LOGPC(DCSN1, LOGL_NOTICE, "%s = %u | ", pDescr->sz , (unsigned)(!Tag));
|
||||
bit_offset++;
|
||||
remaining_bits_len--;
|
||||
|
||||
pDescr++;
|
||||
break;
|
||||
|
|
256
src/decoding.cpp
256
src/decoding.cpp
|
@ -32,7 +32,7 @@ extern "C" {
|
|||
#include <string.h>
|
||||
|
||||
#define LENGTH_TO_END 255
|
||||
/*
|
||||
/*!
|
||||
* \returns num extensions fields (num frames == offset) on success,
|
||||
* -errno otherwise.
|
||||
*/
|
||||
|
@ -197,6 +197,7 @@ int Decoding::rlc_data_from_ul_data(
|
|||
e = rdbi->e;
|
||||
if (e) {
|
||||
if (chunks_size > 0) {
|
||||
/* Block without LI means it only contains data of one LLC PDU */
|
||||
chunks[num_chunks].offset = offs;
|
||||
chunks[num_chunks].length = LENGTH_TO_END;
|
||||
chunks[num_chunks].is_complete = is_last_block;
|
||||
|
@ -344,78 +345,20 @@ void Decoding::extract_rbb(const struct bitvec *rbb, char *show_rbb)
|
|||
int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data, GprsCodingScheme cs)
|
||||
{
|
||||
const struct gprs_rlc_ul_header_egprs_3 *egprs3;
|
||||
const struct rlc_ul_header *gprs;
|
||||
unsigned int e_ti_header;
|
||||
unsigned int cur_bit = 0;
|
||||
int punct, punct2, with_padding, cps;
|
||||
unsigned int offs;
|
||||
|
||||
switch(cs.headerTypeData()) {
|
||||
case GprsCodingScheme::HEADER_GPRS_DATA:
|
||||
gprs = static_cast<struct rlc_ul_header *>
|
||||
((void *)data);
|
||||
|
||||
gprs_rlc_data_info_init_ul(rlc, cs, false);
|
||||
|
||||
rlc->r = gprs->r;
|
||||
rlc->si = gprs->si;
|
||||
rlc->tfi = gprs->tfi;
|
||||
rlc->cps = 0;
|
||||
rlc->rsb = 0;
|
||||
|
||||
rlc->num_data_blocks = 1;
|
||||
rlc->block_info[0].cv = gprs->cv;
|
||||
rlc->block_info[0].pi = gprs->pi;
|
||||
rlc->block_info[0].bsn = gprs->bsn;
|
||||
rlc->block_info[0].e = gprs->e;
|
||||
rlc->block_info[0].ti = gprs->ti;
|
||||
rlc->block_info[0].spb = 0;
|
||||
|
||||
cur_bit += rlc->data_offs_bits[0];
|
||||
|
||||
/* skip data area */
|
||||
cur_bit += cs.maxDataBlockBytes() * 8;
|
||||
case GprsCodingScheme::HEADER_GPRS_DATA :
|
||||
cur_bit = rlc_parse_ul_data_header_gprs(rlc, data, cs);
|
||||
break;
|
||||
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3:
|
||||
egprs3 = static_cast<struct gprs_rlc_ul_header_egprs_3 *>
|
||||
((void *)data);
|
||||
|
||||
cps = (egprs3->cps_a << 0) | (egprs3->cps_b << 2);
|
||||
gprs_rlc_mcs_cps_decode(cps, cs, &punct, &punct2, &with_padding);
|
||||
gprs_rlc_data_info_init_ul(rlc, cs, with_padding);
|
||||
|
||||
rlc->r = egprs3->r;
|
||||
rlc->si = egprs3->si;
|
||||
rlc->tfi = (egprs3->tfi_a << 0) | (egprs3->tfi_b << 2);
|
||||
rlc->cps = cps;
|
||||
rlc->rsb = egprs3->rsb;
|
||||
|
||||
rlc->num_data_blocks = 1;
|
||||
rlc->block_info[0].cv = egprs3->cv;
|
||||
rlc->block_info[0].pi = egprs3->pi;
|
||||
rlc->block_info[0].spb = egprs3->spb;
|
||||
rlc->block_info[0].bsn =
|
||||
(egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5);
|
||||
|
||||
cur_bit += rlc->data_offs_bits[0] - 2;
|
||||
|
||||
offs = rlc->data_offs_bits[0] / 8;
|
||||
OSMO_ASSERT(rlc->data_offs_bits[0] % 8 == 1);
|
||||
|
||||
e_ti_header = (data[offs-1] + (data[offs] << 8)) >> 7;
|
||||
rlc->block_info[0].e = !!(e_ti_header & 0x01);
|
||||
rlc->block_info[0].ti = !!(e_ti_header & 0x02);
|
||||
cur_bit += 2;
|
||||
|
||||
/* skip data area */
|
||||
cur_bit += cs.maxDataBlockBytes() * 8;
|
||||
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3 :
|
||||
cur_bit = rlc_parse_ul_data_header_egprs_type_3(rlc, data, cs);
|
||||
break;
|
||||
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2 :
|
||||
cur_bit = rlc_parse_ul_data_header_egprs_type_2(rlc, data, cs);
|
||||
break;
|
||||
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1 :
|
||||
cur_bit = rlc_parse_ul_data_header_egprs_type_1(rlc, data, cs);
|
||||
break;
|
||||
|
||||
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1:
|
||||
case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2:
|
||||
/* TODO: Support both header types */
|
||||
/* fall through */
|
||||
default:
|
||||
LOGP(DRLCMACDL, LOGL_ERROR,
|
||||
"Decoding of uplink %s data blocks not yet supported.\n",
|
||||
|
@ -426,6 +369,181 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
|
|||
return cur_bit;
|
||||
}
|
||||
|
||||
int Decoding::rlc_parse_ul_data_header_egprs_type_3(
|
||||
struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data,
|
||||
const GprsCodingScheme &cs)
|
||||
{
|
||||
int punct, punct2, with_padding, cps;
|
||||
unsigned int e_ti_header, offs, cur_bit = 0;
|
||||
const struct gprs_rlc_ul_header_egprs_3 *egprs3;
|
||||
|
||||
egprs3 = static_cast < struct gprs_rlc_ul_header_egprs_3 * >
|
||||
((void *)data);
|
||||
|
||||
cps = (egprs3->cps_a << 0) | (egprs3->cps_b << 2);
|
||||
gprs_rlc_mcs_cps_decode(cps, cs, &punct, &punct2, &with_padding);
|
||||
gprs_rlc_data_info_init_ul(rlc, cs, with_padding);
|
||||
|
||||
rlc->r = egprs3->r;
|
||||
rlc->si = egprs3->si;
|
||||
rlc->tfi = (egprs3->tfi_a << 0) | (egprs3->tfi_b << 2);
|
||||
rlc->cps = cps;
|
||||
rlc->rsb = egprs3->rsb;
|
||||
|
||||
rlc->num_data_blocks = 1;
|
||||
rlc->block_info[0].cv = egprs3->cv;
|
||||
rlc->block_info[0].pi = egprs3->pi;
|
||||
rlc->block_info[0].spb = egprs3->spb;
|
||||
rlc->block_info[0].bsn =
|
||||
(egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5);
|
||||
|
||||
cur_bit += rlc->data_offs_bits[0] - 2;
|
||||
offs = rlc->data_offs_bits[0] / 8;
|
||||
OSMO_ASSERT(rlc->data_offs_bits[0] % 8 == 1);
|
||||
e_ti_header = (data[offs-1] + (data[offs] << 8)) >> 7;
|
||||
rlc->block_info[0].e = !!(e_ti_header & 0x01);
|
||||
rlc->block_info[0].ti = !!(e_ti_header & 0x02);
|
||||
cur_bit += 2;
|
||||
/* skip data area */
|
||||
cur_bit += cs.maxDataBlockBytes() * 8;
|
||||
|
||||
return cur_bit;
|
||||
}
|
||||
|
||||
int Decoding::rlc_parse_ul_data_header_egprs_type_2(
|
||||
struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data,
|
||||
const GprsCodingScheme &cs)
|
||||
{
|
||||
const struct gprs_rlc_ul_header_egprs_2 *egprs2;
|
||||
unsigned int e_ti_header, offs, cur_bit = 0;
|
||||
int punct, punct2, with_padding, cps;
|
||||
|
||||
egprs2 = static_cast < struct gprs_rlc_ul_header_egprs_2 * >
|
||||
((void *)data);
|
||||
|
||||
cps = (egprs2->cps_a << 0) | (egprs2->cps_b << 2);
|
||||
gprs_rlc_mcs_cps_decode(cps, cs, &punct, &punct2, &with_padding);
|
||||
gprs_rlc_data_info_init_ul(rlc, cs, with_padding);
|
||||
|
||||
rlc->r = egprs2->r;
|
||||
rlc->si = egprs2->si;
|
||||
rlc->tfi = (egprs2->tfi_a << 0) | (egprs2->tfi_b << 2);
|
||||
rlc->cps = cps;
|
||||
rlc->rsb = egprs2->rsb;
|
||||
|
||||
rlc->num_data_blocks = 1;
|
||||
rlc->block_info[0].cv = egprs2->cv;
|
||||
rlc->block_info[0].pi = egprs2->pi;
|
||||
rlc->block_info[0].bsn =
|
||||
(egprs2->bsn1_a << 0) | (egprs2->bsn1_b << 5);
|
||||
|
||||
cur_bit += rlc->data_offs_bits[0] - 2;
|
||||
|
||||
offs = rlc->data_offs_bits[0] / 8;
|
||||
OSMO_ASSERT(rlc->data_offs_bits[0] % 8 == 7);
|
||||
|
||||
e_ti_header = (data[offs] & 0x60) >> 5;
|
||||
rlc->block_info[0].e = !!(e_ti_header & 0x01);
|
||||
rlc->block_info[0].ti = !!(e_ti_header & 0x02);
|
||||
cur_bit += 2;
|
||||
|
||||
/* skip data area */
|
||||
cur_bit += cs.maxDataBlockBytes() * 8;
|
||||
|
||||
return cur_bit;
|
||||
}
|
||||
|
||||
int Decoding::rlc_parse_ul_data_header_egprs_type_1(
|
||||
struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data, const GprsCodingScheme &cs)
|
||||
{
|
||||
struct gprs_rlc_ul_header_egprs_1 *egprs1;
|
||||
unsigned int e_ti_header, cur_bit = 0, offs;
|
||||
int punct, punct2, with_padding;
|
||||
|
||||
egprs1 = static_cast < struct gprs_rlc_ul_header_egprs_1 * >
|
||||
((void *)data);
|
||||
gprs_rlc_mcs_cps_decode(egprs1->cps, cs, &punct, &punct2,
|
||||
&with_padding);
|
||||
gprs_rlc_data_info_init_ul(rlc, cs, with_padding);
|
||||
|
||||
rlc->r = egprs1->r;
|
||||
rlc->si = egprs1->si;
|
||||
rlc->tfi = (egprs1->tfi_a << 0) | (egprs1->tfi_b << 2);
|
||||
rlc->cps = egprs1->cps;
|
||||
rlc->rsb = egprs1->rsb;
|
||||
rlc->num_data_blocks = 2;
|
||||
rlc->block_info[0].cv = egprs1->cv;
|
||||
rlc->block_info[0].pi = egprs1->pi;
|
||||
rlc->block_info[0].bsn =
|
||||
(egprs1->bsn1_a << 0) | (egprs1->bsn1_b << 5);
|
||||
|
||||
cur_bit += rlc->data_offs_bits[0] - 2;
|
||||
offs = rlc->data_offs_bits[0] / 8;
|
||||
OSMO_ASSERT(rlc->data_offs_bits[0] % 8 == 0);
|
||||
|
||||
e_ti_header = data[offs - 1] >> 6;
|
||||
rlc->block_info[0].e = (e_ti_header & 0x01);
|
||||
rlc->block_info[0].ti = !!(e_ti_header & 0x02);
|
||||
cur_bit += 2;
|
||||
|
||||
rlc->block_info[1].cv = egprs1->cv;
|
||||
rlc->block_info[1].pi = egprs1->pi;
|
||||
rlc->block_info[1].bsn = rlc->block_info[0].bsn +
|
||||
((egprs1->bsn2_a << 0) | (egprs1->bsn2_b << 2));
|
||||
rlc->block_info[1].bsn = rlc->block_info[1].bsn & (RLC_EGPRS_SNS - 1);
|
||||
|
||||
if ((rlc->block_info[1].bsn != rlc->block_info[0].bsn) &&
|
||||
(rlc->block_info[0].cv == 0))
|
||||
rlc->block_info[0].cv = 1;
|
||||
|
||||
cur_bit = rlc->data_offs_bits[1] - 2;
|
||||
|
||||
offs = rlc->data_offs_bits[1] / 8;
|
||||
OSMO_ASSERT(rlc->data_offs_bits[1] % 8 == 2);
|
||||
|
||||
e_ti_header = (data[offs] & (0x03));
|
||||
rlc->block_info[1].e = (e_ti_header & 0x01);
|
||||
rlc->block_info[1].ti = !!(e_ti_header & 0x02);
|
||||
cur_bit += 2;
|
||||
/* skip data area */
|
||||
cur_bit += cs.maxDataBlockBytes() * 8;
|
||||
|
||||
return cur_bit;
|
||||
}
|
||||
|
||||
int Decoding::rlc_parse_ul_data_header_gprs(struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data, const GprsCodingScheme &cs)
|
||||
{
|
||||
const struct rlc_ul_header *gprs;
|
||||
unsigned int cur_bit = 0;
|
||||
|
||||
gprs = static_cast < struct rlc_ul_header * >
|
||||
((void *)data);
|
||||
|
||||
gprs_rlc_data_info_init_ul(rlc, cs, false);
|
||||
|
||||
rlc->r = gprs->r;
|
||||
rlc->si = gprs->si;
|
||||
rlc->tfi = gprs->tfi;
|
||||
rlc->cps = 0;
|
||||
rlc->rsb = 0;
|
||||
rlc->num_data_blocks = 1;
|
||||
rlc->block_info[0].cv = gprs->cv;
|
||||
rlc->block_info[0].pi = gprs->pi;
|
||||
rlc->block_info[0].bsn = gprs->bsn;
|
||||
rlc->block_info[0].e = gprs->e;
|
||||
rlc->block_info[0].ti = gprs->ti;
|
||||
rlc->block_info[0].spb = 0;
|
||||
cur_bit += rlc->data_offs_bits[0];
|
||||
/* skip data area */
|
||||
cur_bit += cs.maxDataBlockBytes() * 8;
|
||||
|
||||
return cur_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Copy LSB bitstream RLC data block to byte aligned buffer.
|
||||
*
|
||||
|
|
|
@ -28,10 +28,11 @@ struct bitvec;
|
|||
|
||||
class Decoding {
|
||||
public:
|
||||
/* represents (parts) LLC PDUs within one RLC Data block */
|
||||
struct RlcData {
|
||||
uint8_t offset;
|
||||
uint8_t length;
|
||||
bool is_complete;
|
||||
bool is_complete; /* if this PDU ends in this block */
|
||||
};
|
||||
|
||||
static int rlc_data_from_ul_data(
|
||||
|
@ -43,7 +44,22 @@ public:
|
|||
|
||||
static void extract_rbb(const uint8_t *rbb, char *extracted_rbb);
|
||||
static void extract_rbb(const struct bitvec *rbb, char *show_rbb);
|
||||
|
||||
static int rlc_parse_ul_data_header_egprs_type_3(
|
||||
struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data,
|
||||
const GprsCodingScheme &cs);
|
||||
static int rlc_parse_ul_data_header_egprs_type_2(
|
||||
struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data,
|
||||
const GprsCodingScheme &cs);
|
||||
static int rlc_parse_ul_data_header_egprs_type_1(
|
||||
struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data,
|
||||
const GprsCodingScheme &cs);
|
||||
static int rlc_parse_ul_data_header_gprs(
|
||||
struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data,
|
||||
const GprsCodingScheme &cs);
|
||||
static int rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
|
||||
const uint8_t *data, GprsCodingScheme cs);
|
||||
static unsigned int rlc_copy_to_aligned_buffer(
|
||||
|
|
|
@ -276,7 +276,8 @@ void Encoding::write_packet_uplink_assignment(
|
|||
bitvec_write_field(dest, wp,0x0,1); // No CONTENTION_RESOLUTION_TLLI
|
||||
bitvec_write_field(dest, wp,0x0,1); // No COMPACT reduced MA
|
||||
bitvec_write_field(dest, wp,tbf->current_cs().to_num()-1, 4); // EGPRS Modulation and Coding IE
|
||||
bitvec_write_field(dest, wp,0x0,1); // No RESEGMENT
|
||||
/* No RESEGMENT */
|
||||
bitvec_write_field(dest, wp, 0x1, 1);
|
||||
bitvec_write_field(dest, wp,ws_enc,5); // EGPRS Window Size
|
||||
bitvec_write_field(dest, wp,0x0,1); // No Access Technologies Request
|
||||
bitvec_write_field(dest, wp,0x0,1); // No ARAC RETRANSMISSION REQUEST
|
||||
|
@ -567,6 +568,9 @@ static void write_packet_ack_nack_desc_egprs(
|
|||
eow = false;
|
||||
urbb_len = rest_bits - 9;
|
||||
/* TODO: use compression (see above) */
|
||||
} else {
|
||||
eow = true;
|
||||
urbb_len = num_blocks;
|
||||
}
|
||||
|
||||
if (urbb_len + crbb_len == rest_bits)
|
||||
|
@ -610,9 +614,11 @@ static void write_packet_uplink_ack_egprs(
|
|||
struct gprs_rlcmac_ul_tbf *tbf, bool is_final)
|
||||
{
|
||||
bitvec_write_field(dest, wp, 0, 2); // fixed 00
|
||||
bitvec_write_field(dest, wp, 2, 4); // CHANNEL_CODING_COMMAND: MCS-3
|
||||
// bitvec_write_field(dest, wp, tbf->current_cs() - 1, 4); // CHANNEL_CODING_COMMAND
|
||||
bitvec_write_field(dest, wp, 0, 1); // 0: no RESEGMENT (nyi)
|
||||
/* CHANNEL_CODING_COMMAND */
|
||||
bitvec_write_field(dest, wp,
|
||||
tbf->current_cs().to_num() - 1, 4);
|
||||
/* 0: no RESEGMENT (nyi) */
|
||||
bitvec_write_field(dest, wp, 1, 1);
|
||||
bitvec_write_field(dest, wp, 1, 1); // PRE_EMPTIVE_TRANSMISSION, TODO: This resembles GPRS, change it?
|
||||
bitvec_write_field(dest, wp, 0, 1); // 0: no PRR_RETRANSMISSION_REQUEST, TODO: clarify
|
||||
bitvec_write_field(dest, wp, 0, 1); // 0: no ARAC_RETRANSMISSION_REQUEST, TODO: clarify
|
||||
|
@ -891,6 +897,16 @@ unsigned int Encoding::rlc_copy_from_aligned_buffer(
|
|||
return rdbi->data_len;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief (GPRS) put llc pdu into an rlc/mac block. fragment the llc pdu if needed
|
||||
* \param rdbi rlc/mac block info
|
||||
* \param llc llc pdu
|
||||
* \param offset given offset within the rlc/mac block
|
||||
* \param num_chunks count the chunks (llc pdu data) within rlc/mac
|
||||
* \param data_block buffer holds rlc/mac data
|
||||
* \param is_final if this is the last rlc/mac within a TBF
|
||||
* \return the state of the rlc/mac like if there is more space for another chunk
|
||||
*/
|
||||
static Encoding::AppendResult rlc_data_to_dl_append_gprs(
|
||||
struct gprs_rlc_data_block_info *rdbi,
|
||||
gprs_llc *llc, int *offset, int *num_chunks,
|
||||
|
@ -1012,6 +1028,16 @@ static Encoding::AppendResult rlc_data_to_dl_append_gprs(
|
|||
return Encoding::AR_COMPLETED_BLOCK_FILLED;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief (EGPRS) put llc pdu into an rlc/mac block. fragment the llc pdu if needed
|
||||
* \param rdbi rlc/mac block info
|
||||
* \param llc llc pdu
|
||||
* \param offset given offset within the rlc/mac block
|
||||
* \param num_chunks count the chunks (llc pdu data) within rlc/mac
|
||||
* \param data_block buffer holds rlc/mac data
|
||||
* \param is_final if this is the last rlc/mac within a TBF
|
||||
* \return the state of the rlc/mac like if there is more space for another chunk
|
||||
*/
|
||||
static Encoding::AppendResult rlc_data_to_dl_append_egprs(
|
||||
struct gprs_rlc_data_block_info *rdbi,
|
||||
gprs_llc *llc, int *offset, int *num_chunks,
|
||||
|
@ -1154,6 +1180,17 @@ static Encoding::AppendResult rlc_data_to_dl_append_egprs(
|
|||
return Encoding::AR_COMPLETED_BLOCK_FILLED;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Encoding::rlc_data_to_dl_append
|
||||
* \param rdbi rlc/mac block info
|
||||
* \param cs the coding scheme to use
|
||||
* \param llc llc pdu
|
||||
* \param offset given offset within the rlc/mac block
|
||||
* \param num_chunks count the chunks (llc pdu data) within rlc/mac
|
||||
* \param data_block buffer holds rlc/mac data
|
||||
* \param is_final if this is the last rlc/mac within a TBF
|
||||
* \return the state of the rlc/mac like if there is more space for another chunk
|
||||
*/
|
||||
Encoding::AppendResult Encoding::rlc_data_to_dl_append(
|
||||
struct gprs_rlc_data_block_info *rdbi, GprsCodingScheme cs,
|
||||
gprs_llc *llc, int *offset, int *num_chunks,
|
||||
|
|
|
@ -21,6 +21,41 @@
|
|||
|
||||
#include "gprs_coding_scheme.h"
|
||||
|
||||
/*
|
||||
* 44.060 Table 8.1.1.1 and Table 8.1.1.2
|
||||
* In has 3 level indexing. 0th level is ARQ type
|
||||
* 1st level is Original MCS( index 0 corresponds to MCS1 and so on)
|
||||
* 2nd level is MS MCS (index 0 corresponds to MCS1 and so on)
|
||||
* in 0th level indexing only ARQ type 2 is supported i.e index 1 for
|
||||
* incremental redundancy
|
||||
*/
|
||||
|
||||
enum GprsCodingScheme::Scheme GprsCodingScheme::egprs_mcs_retx_tbl[MAX_NUM_ARQ]
|
||||
[MAX_NUM_MCS][MAX_NUM_MCS] = {
|
||||
{
|
||||
{MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1},
|
||||
{MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2},
|
||||
{MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3},
|
||||
{MCS1, MCS1, MCS1, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4},
|
||||
{MCS2, MCS2, MCS2, MCS2, MCS5, MCS5, MCS7, MCS7, MCS7},
|
||||
{MCS3, MCS3, MCS3, MCS3, MCS3, MCS6, MCS6, MCS6, MCS9},
|
||||
{MCS2, MCS2, MCS2, MCS2, MCS5, MCS5, MCS7, MCS7, MCS7},
|
||||
{MCS3, MCS3, MCS3, MCS3, MCS3, MCS6, MCS6, MCS8, MCS8},
|
||||
{MCS3, MCS3, MCS3, MCS3, MCS3, MCS6, MCS6, MCS6, MCS9}
|
||||
},
|
||||
{
|
||||
{MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1},
|
||||
{MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2},
|
||||
{MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3},
|
||||
{MCS4, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4},
|
||||
{MCS5, MCS5, MCS5, MCS5, MCS5, MCS5, MCS7, MCS7, MCS7},
|
||||
{MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS9},
|
||||
{MCS5, MCS5, MCS5, MCS5, MCS5, MCS5, MCS7, MCS7, MCS7},
|
||||
{MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS8, MCS8},
|
||||
{MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS9}
|
||||
}
|
||||
};
|
||||
|
||||
static struct {
|
||||
struct {
|
||||
unsigned int bytes;
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
|
||||
class GprsCodingScheme {
|
||||
public:
|
||||
|
||||
#define MAX_NUM_ARQ 2 /* max. number of ARQ */
|
||||
#define MAX_NUM_MCS 9 /* max. number of MCS */
|
||||
#define EGPRS_ARQ1 0x0
|
||||
#define EGPRS_ARQ2 0x1
|
||||
|
||||
enum Scheme {
|
||||
UNKNOWN,
|
||||
CS1, CS2, CS3, CS4,
|
||||
|
@ -64,6 +70,7 @@ public:
|
|||
unsigned int to_num() const;
|
||||
|
||||
GprsCodingScheme& operator =(Scheme s);
|
||||
bool operator == (Scheme s);
|
||||
GprsCodingScheme& operator =(GprsCodingScheme o);
|
||||
|
||||
bool isValid() const {return UNKNOWN <= m_scheme && m_scheme <= MCS9;}
|
||||
|
@ -105,6 +112,12 @@ public:
|
|||
static GprsCodingScheme getEgprsByNum(unsigned num);
|
||||
|
||||
static const char *modeName(Mode mode);
|
||||
static Scheme get_retx_mcs(const GprsCodingScheme &mcs,
|
||||
const GprsCodingScheme &retx_mcs,
|
||||
const unsigned char arq_type);
|
||||
|
||||
static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ]
|
||||
[MAX_NUM_MCS][MAX_NUM_MCS];
|
||||
private:
|
||||
GprsCodingScheme(int s); /* fail on use */
|
||||
GprsCodingScheme& operator =(int s); /* fail on use */
|
||||
|
@ -188,6 +201,13 @@ inline bool operator ==(GprsCodingScheme a, GprsCodingScheme b)
|
|||
return GprsCodingScheme::Scheme(a) == GprsCodingScheme::Scheme(b);
|
||||
}
|
||||
|
||||
inline bool GprsCodingScheme::operator == (Scheme scheme)
|
||||
{
|
||||
if (this->m_scheme == scheme)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool operator !=(GprsCodingScheme a, GprsCodingScheme b)
|
||||
{
|
||||
return !(a == b);
|
||||
|
@ -214,3 +234,11 @@ inline bool operator >=(GprsCodingScheme a, GprsCodingScheme b)
|
|||
return a == b || a > b;
|
||||
}
|
||||
|
||||
inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs(
|
||||
const GprsCodingScheme &mcs,
|
||||
const GprsCodingScheme &demanded_mcs,
|
||||
const unsigned char arq_type)
|
||||
{
|
||||
return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1]
|
||||
[demanded_mcs.to_num() - 1];
|
||||
}
|
||||
|
|
|
@ -237,7 +237,7 @@ void GprsMs::set_mode(GprsCodingScheme::Mode mode)
|
|||
if (!m_current_cs_ul.isEgprs()) {
|
||||
m_current_cs_ul = GprsCodingScheme::getEgprsByNum(
|
||||
m_bts->bts_data()->initial_mcs_ul);
|
||||
if (!m_current_cs_dl.isValid())
|
||||
if (!m_current_cs_ul.isValid())
|
||||
m_current_cs_ul = GprsCodingScheme::MCS1;
|
||||
}
|
||||
if (!m_current_cs_dl.isEgprs()) {
|
||||
|
@ -574,6 +574,11 @@ GprsCodingScheme GprsMs::max_cs_ul() const
|
|||
return GprsCodingScheme(GprsCodingScheme::MCS4);
|
||||
}
|
||||
|
||||
void GprsMs::set_current_cs_dl(GprsCodingScheme::Scheme scheme)
|
||||
{
|
||||
m_current_cs_dl = scheme;
|
||||
}
|
||||
|
||||
GprsCodingScheme GprsMs::max_cs_dl() const
|
||||
{
|
||||
struct gprs_rlcmac_bts *bts_data;
|
||||
|
@ -632,8 +637,8 @@ void GprsMs::update_cs_ul(const pcu_l1_meas *meas)
|
|||
high = bts_data->cs_lqual_ranges[current_cs_num-1].high;
|
||||
} else if (m_current_cs_ul.isEgprs()) {
|
||||
/* TODO, use separate table */
|
||||
if (current_cs_num > 4)
|
||||
current_cs_num = 4;
|
||||
if (current_cs_num > 9)
|
||||
current_cs_num = 9;
|
||||
low = bts_data->cs_lqual_ranges[current_cs_num-1].low;
|
||||
high = bts_data->cs_lqual_ranges[current_cs_num-1].high;
|
||||
} else {
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
uint8_t egprs_ms_class() const;
|
||||
void set_ms_class(uint8_t ms_class);
|
||||
void set_egprs_ms_class(uint8_t ms_class);
|
||||
void set_current_cs_dl(GprsCodingScheme::Scheme scheme);
|
||||
|
||||
GprsCodingScheme current_cs_ul() const;
|
||||
GprsCodingScheme current_cs_dl() const;
|
||||
|
|
|
@ -129,6 +129,9 @@ int gprs_rlcmac_received_lost(struct gprs_rlcmac_dl_tbf *tbf, uint16_t received,
|
|||
tbf->m_bw.dl_loss_received += received;
|
||||
tbf->m_bw.dl_loss_lost += lost;
|
||||
|
||||
tbf->m_bw.total_dl_loss_received += received;
|
||||
tbf->m_bw.total_dl_loss_lost += lost;
|
||||
|
||||
gettimeofday(&now_tv, NULL);
|
||||
elapsed = ((now_tv.tv_sec - loss_tv->tv_sec) << 7)
|
||||
+ ((now_tv.tv_usec - loss_tv->tv_usec) << 7) / 1000000;
|
||||
|
|
|
@ -132,7 +132,7 @@ static struct msgb *sched_select_ctrl_msg(
|
|||
|
||||
/*
|
||||
* Assignments for the same direction have lower precedence,
|
||||
* because they may kill the TBF when the CONTOL ACK is
|
||||
* because they may kill the TBF when the CONTROL ACK is
|
||||
* received, thus preventing the others from being processed.
|
||||
*/
|
||||
|
||||
|
@ -339,18 +339,28 @@ int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
|
|||
/* Prio 1: select control message */
|
||||
msg = sched_select_ctrl_msg(trx, ts, fn, block_nr, pdch, ul_ass_tbf,
|
||||
dl_ass_tbf, ul_ack_tbf);
|
||||
if (msg)
|
||||
bts->bts->rlc_sent_control();
|
||||
|
||||
/* Prio 2: select data message for downlink */
|
||||
if (!msg)
|
||||
if (!msg) {
|
||||
msg = sched_select_downlink(bts, trx, ts, fn, block_nr, pdch);
|
||||
if (msg)
|
||||
bts->bts->rlc_sent();
|
||||
}
|
||||
|
||||
/* Prio 3: send dummy contol message */
|
||||
if (!msg)
|
||||
if (!msg) {
|
||||
/* increase counter */
|
||||
msg = sched_dummy();
|
||||
if (msg)
|
||||
bts->bts->rlc_sent_dummy();
|
||||
}
|
||||
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
/* msg is now available */
|
||||
bts->bts->rlc_dl_bytes(msg->data_len);
|
||||
|
||||
/* set USF */
|
||||
OSMO_ASSERT(msgb_length(msg) > 0);
|
||||
|
|
|
@ -775,8 +775,8 @@ static int find_multi_slots(struct gprs_rlcmac_bts *bts,
|
|||
rx_window & tx_window, 'C'),
|
||||
capacity);
|
||||
#endif
|
||||
|
||||
if (capacity <= max_capacity)
|
||||
/* Give priority to DL as we support 1 TS in UL */
|
||||
if (/*capacity <= max_capacity && */(rx_window < max_dl_slots))
|
||||
continue;
|
||||
|
||||
max_capacity = capacity;
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
/* Interface handler for Nuran Wireless Litecell 1.5 L1 (real hardware) */
|
||||
|
||||
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
|
||||
* based on:
|
||||
* femto_l1_hw.c
|
||||
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/write_queue.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
|
||||
#include <nrw/litecell15/litecell15.h>
|
||||
#include <nrw/litecell15/gsml1prim.h>
|
||||
#include <nrw/litecell15/gsml1const.h>
|
||||
#include <nrw/litecell15/gsml1types.h>
|
||||
|
||||
#include "gprs_debug.h"
|
||||
#include "lc15bts.h"
|
||||
#include "lc15_l1_if.h"
|
||||
|
||||
#define DEV_SYS_DSP2ARM_NAME "/dev/msgq/litecell15_dsp2arm_trx"
|
||||
#define DEV_SYS_ARM2DSP_NAME "/dev/msgq/litecell15_arm2dsp_trx"
|
||||
#define DEV_L1_DSP2ARM_NAME "/dev/msgq/gsml1_sig_dsp2arm_trx"
|
||||
#define DEV_L1_ARM2DSP_NAME "/dev/msgq/gsml1_sig_arm2dsp_trx"
|
||||
|
||||
#define DEV_TCH_DSP2ARM_NAME "/dev/msgq/gsml1_tch_dsp2arm_trx"
|
||||
#define DEV_TCH_ARM2DSP_NAME "/dev/msgq/gsml1_tch_arm2dsp_trx"
|
||||
#define DEV_PDTCH_DSP2ARM_NAME "/dev/msgq/gsml1_pdtch_dsp2arm_trx"
|
||||
#define DEV_PDTCH_ARM2DSP_NAME "/dev/msgq/gsml1_pdtch_arm2dsp_trx"
|
||||
|
||||
static const char *rd_devnames[] = {
|
||||
[MQ_SYS_READ] = DEV_SYS_DSP2ARM_NAME,
|
||||
[MQ_L1_READ] = DEV_L1_DSP2ARM_NAME,
|
||||
[MQ_TCH_READ] = DEV_TCH_DSP2ARM_NAME,
|
||||
[MQ_PDTCH_READ] = DEV_PDTCH_DSP2ARM_NAME,
|
||||
};
|
||||
|
||||
static const char *wr_devnames[] = {
|
||||
[MQ_SYS_WRITE] = DEV_SYS_ARM2DSP_NAME,
|
||||
[MQ_L1_WRITE] = DEV_L1_ARM2DSP_NAME,
|
||||
[MQ_TCH_WRITE] = DEV_TCH_ARM2DSP_NAME,
|
||||
[MQ_PDTCH_WRITE]= DEV_PDTCH_ARM2DSP_NAME,
|
||||
};
|
||||
|
||||
/* callback when there's something to read from the l1 msg_queue */
|
||||
static int l1if_fd_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
{
|
||||
//struct msgb *msg = l1p_msgb_alloc();
|
||||
struct msgb *msg = msgb_alloc_headroom(sizeof(Litecell15_Prim_t) + 128,
|
||||
128, "1l_fd");
|
||||
struct lc15l1_hdl *fl1h = ofd->data;
|
||||
int rc;
|
||||
|
||||
msg->l1h = msg->data;
|
||||
rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg));
|
||||
if (rc < 0) {
|
||||
if (rc != -1)
|
||||
LOGP(DL1IF, LOGL_ERROR, "error reading from L1 msg_queue: %s\n",
|
||||
strerror(errno));
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
msgb_put(msg, rc);
|
||||
|
||||
switch (ofd->priv_nr) {
|
||||
case MQ_SYS_WRITE:
|
||||
if (rc != sizeof(Litecell15_Prim_t))
|
||||
LOGP(DL1IF, LOGL_NOTICE, "%u != "
|
||||
"sizeof(Litecell15_Prim_t)\n", rc);
|
||||
return l1if_handle_sysprim(fl1h, msg);
|
||||
case MQ_L1_WRITE:
|
||||
case MQ_TCH_WRITE:
|
||||
case MQ_PDTCH_WRITE:
|
||||
if (rc != sizeof(GsmL1_Prim_t))
|
||||
LOGP(DL1IF, LOGL_NOTICE, "%u != "
|
||||
"sizeof(GsmL1_Prim_t)\n", rc);
|
||||
return l1if_handle_l1prim(ofd->priv_nr, fl1h, msg);
|
||||
default:
|
||||
/* The compiler can't know that priv_nr is an enum. Assist. */
|
||||
LOGP(DL1IF, LOGL_FATAL, "writing on a wrong queue: %d\n",
|
||||
ofd->priv_nr);
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/* callback when we can write to one of the l1 msg_queue devices */
|
||||
static int l1fd_write_cb(struct osmo_fd *ofd, struct msgb *msg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = write(ofd->fd, msg->l1h, msgb_l1len(msg));
|
||||
if (rc < 0) {
|
||||
LOGP(DL1IF, LOGL_ERROR, "error writing to L1 msg_queue: %s\n",
|
||||
strerror(errno));
|
||||
return rc;
|
||||
} else if (rc < msg->len) {
|
||||
LOGP(DL1IF, LOGL_ERROR, "short write to L1 msg_queue: "
|
||||
"%u < %u\n", rc, msg->len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l1if_transport_open(int q, struct lc15l1_hdl *hdl)
|
||||
{
|
||||
int rc;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
/* Step 1: Open all msg_queue file descriptors */
|
||||
struct osmo_fd *read_ofd = &hdl->read_ofd[q];
|
||||
struct osmo_wqueue *wq = &hdl->write_q[q];
|
||||
struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
|
||||
|
||||
snprintf(buf, sizeof(buf)-1, "%s%d", rd_devnames[q], hdl->hw_info.trx_nr);
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
|
||||
rc = open(buf, O_RDONLY);
|
||||
if (rc < 0) {
|
||||
LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue %s: %s\n",
|
||||
buf, strerror(errno));
|
||||
return rc;
|
||||
}
|
||||
read_ofd->fd = rc;
|
||||
read_ofd->priv_nr = q;
|
||||
read_ofd->data = hdl;
|
||||
read_ofd->cb = l1if_fd_cb;
|
||||
read_ofd->when = BSC_FD_READ;
|
||||
rc = osmo_fd_register(read_ofd);
|
||||
if (rc < 0) {
|
||||
close(read_ofd->fd);
|
||||
read_ofd->fd = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf)-1, "%s%d", wr_devnames[q], hdl->hw_info.trx_nr);
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
|
||||
rc = open(buf, O_WRONLY);
|
||||
if (rc < 0) {
|
||||
LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue %s: %s\n",
|
||||
buf, strerror(errno));
|
||||
goto out_read;
|
||||
}
|
||||
osmo_wqueue_init(wq, 10);
|
||||
wq->write_cb = l1fd_write_cb;
|
||||
write_ofd->fd = rc;
|
||||
write_ofd->priv_nr = q;
|
||||
write_ofd->data = hdl;
|
||||
write_ofd->when = BSC_FD_WRITE;
|
||||
rc = osmo_fd_register(write_ofd);
|
||||
if (rc < 0) {
|
||||
close(write_ofd->fd);
|
||||
write_ofd->fd = -1;
|
||||
goto out_read;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_read:
|
||||
close(hdl->read_ofd[q].fd);
|
||||
osmo_fd_unregister(&hdl->read_ofd[q]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int l1if_transport_close(int q, struct lc15l1_hdl *hdl)
|
||||
{
|
||||
struct osmo_fd *read_ofd = &hdl->read_ofd[q];
|
||||
struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
|
||||
|
||||
osmo_fd_unregister(read_ofd);
|
||||
close(read_ofd->fd);
|
||||
read_ofd->fd = -1;
|
||||
|
||||
osmo_fd_unregister(write_ofd);
|
||||
close(write_ofd->fd);
|
||||
write_ofd->fd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,410 @@
|
|||
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
|
||||
* based on:
|
||||
* femto_l1_if.c
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nrw/litecell15/litecell15.h>
|
||||
#include <nrw/litecell15/gsml1prim.h>
|
||||
#include <nrw/litecell15/gsml1const.h>
|
||||
#include <nrw/litecell15/gsml1types.h>
|
||||
|
||||
#include <osmocom/core/gsmtap.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <lc15_l1_if.h>
|
||||
#include <gprs_debug.h>
|
||||
#include <pcu_l1_if.h>
|
||||
|
||||
extern void *tall_pcu_ctx;
|
||||
|
||||
uint32_t l1if_ts_to_hLayer2(uint8_t trx, uint8_t ts)
|
||||
{
|
||||
return (ts << 16) | (trx << 24);
|
||||
}
|
||||
|
||||
/* allocate a msgb containing a GsmL1_Prim_t */
|
||||
struct msgb *l1p_msgb_alloc(void)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc(sizeof(GsmL1_Prim_t), "l1_prim");
|
||||
|
||||
if (msg)
|
||||
msg->l1h = msgb_put(msg, sizeof(GsmL1_Prim_t));
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int l1if_req_pdch(struct lc15l1_hdl *fl1h, struct msgb *msg)
|
||||
{
|
||||
struct osmo_wqueue *wqueue = &fl1h->write_q[MQ_PDTCH_WRITE];
|
||||
|
||||
if (osmo_wqueue_enqueue(wqueue, msg) != 0) {
|
||||
LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping message.\n");
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *prim_init(GsmL1_Prim_t *prim, GsmL1_PrimId_t id, struct lc15l1_hdl *gl1)
|
||||
{
|
||||
prim->id = id;
|
||||
|
||||
switch (id) {
|
||||
case GsmL1_PrimId_MphInitReq:
|
||||
//prim->u.mphInitReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_MphCloseReq:
|
||||
prim->u.mphCloseReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_MphConnectReq:
|
||||
prim->u.mphConnectReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_MphDisconnectReq:
|
||||
prim->u.mphDisconnectReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_MphActivateReq:
|
||||
prim->u.mphActivateReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_MphDeactivateReq:
|
||||
prim->u.mphDeactivateReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_MphConfigReq:
|
||||
prim->u.mphConfigReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_MphMeasureReq:
|
||||
prim->u.mphMeasureReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_MphInitCnf:
|
||||
case GsmL1_PrimId_MphCloseCnf:
|
||||
case GsmL1_PrimId_MphConnectCnf:
|
||||
case GsmL1_PrimId_MphDisconnectCnf:
|
||||
case GsmL1_PrimId_MphActivateCnf:
|
||||
case GsmL1_PrimId_MphDeactivateCnf:
|
||||
case GsmL1_PrimId_MphConfigCnf:
|
||||
case GsmL1_PrimId_MphMeasureCnf:
|
||||
break;
|
||||
case GsmL1_PrimId_MphTimeInd:
|
||||
break;
|
||||
case GsmL1_PrimId_MphSyncInd:
|
||||
break;
|
||||
case GsmL1_PrimId_PhEmptyFrameReq:
|
||||
prim->u.phEmptyFrameReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_PhDataReq:
|
||||
prim->u.phDataReq.hLayer1 = (HANDLE)gl1->hLayer1;
|
||||
break;
|
||||
case GsmL1_PrimId_PhConnectInd:
|
||||
break;
|
||||
case GsmL1_PrimId_PhReadyToSendInd:
|
||||
break;
|
||||
case GsmL1_PrimId_PhDataInd:
|
||||
break;
|
||||
case GsmL1_PrimId_PhRaInd:
|
||||
break;
|
||||
default:
|
||||
LOGP(DL1IF, LOGL_ERROR, "unknown L1 primitive %u\n", id);
|
||||
break;
|
||||
}
|
||||
return &prim->u;
|
||||
}
|
||||
|
||||
struct sapi_dir {
|
||||
GsmL1_Sapi_t sapi;
|
||||
GsmL1_Dir_t dir;
|
||||
};
|
||||
|
||||
static const struct sapi_dir pdtch_sapis[] = {
|
||||
{ GsmL1_Sapi_Pdtch, GsmL1_Dir_TxDownlink },
|
||||
{ GsmL1_Sapi_Pdtch, GsmL1_Dir_RxUplink },
|
||||
{ GsmL1_Sapi_Ptcch, GsmL1_Dir_TxDownlink },
|
||||
{ GsmL1_Sapi_Prach, GsmL1_Dir_RxUplink },
|
||||
#if 0
|
||||
{ GsmL1_Sapi_Ptcch, GsmL1_Dir_RxUplink },
|
||||
{ GsmL1_Sapi_Pacch, GsmL1_Dir_TxDownlink },
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* connect PDTCH */
|
||||
int l1if_connect_pdch(void *obj, uint8_t ts)
|
||||
{
|
||||
struct lc15l1_hdl *fl1h = obj;
|
||||
struct msgb *msg = l1p_msgb_alloc();
|
||||
GsmL1_MphConnectReq_t *cr;
|
||||
|
||||
cr = prim_init(msgb_l1prim(msg), GsmL1_PrimId_MphConnectReq, fl1h);
|
||||
cr->u8Tn = ts;
|
||||
cr->logChComb = GsmL1_LogChComb_XIII;
|
||||
|
||||
return l1if_req_pdch(fl1h, msg);
|
||||
}
|
||||
|
||||
static int handle_ph_readytosend_ind(struct lc15l1_hdl *fl1h,
|
||||
GsmL1_PhReadyToSendInd_t *rts_ind)
|
||||
{
|
||||
struct gsm_time g_time;
|
||||
int rc = 0;
|
||||
|
||||
gsm_fn2gsmtime(&g_time, rts_ind->u32Fn);
|
||||
|
||||
DEBUGP(DL1IF, "Rx PH-RTS.ind %02u/%02u/%02u SAPI=%s\n",
|
||||
g_time.t1, g_time.t2, g_time.t3,
|
||||
get_value_string(lc15bts_l1sapi_names, rts_ind->sapi));
|
||||
|
||||
switch (rts_ind->sapi) {
|
||||
case GsmL1_Sapi_Pdtch:
|
||||
case GsmL1_Sapi_Pacch:
|
||||
rc = pcu_rx_rts_req_pdtch(fl1h->trx_no, rts_ind->u8Tn,
|
||||
rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr);
|
||||
case GsmL1_Sapi_Ptcch:
|
||||
// FIXME
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void get_meas(struct pcu_l1_meas *meas, const GsmL1_MeasParam_t *l1_meas)
|
||||
{
|
||||
meas->rssi = (int8_t) (l1_meas->fRssi);
|
||||
meas->have_rssi = 1;
|
||||
meas->ber = (uint8_t) (l1_meas->fBer * 100);
|
||||
meas->have_ber = 1;
|
||||
meas->bto = (int16_t) (l1_meas->i16BurstTiming);
|
||||
meas->have_bto = 1;
|
||||
meas->link_qual = (int16_t) (l1_meas->fLinkQuality);
|
||||
meas->have_link_qual = 1;
|
||||
}
|
||||
|
||||
static int handle_ph_data_ind(struct lc15l1_hdl *fl1h,
|
||||
GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg)
|
||||
{
|
||||
int rc = 0;
|
||||
struct pcu_l1_meas meas = {0};
|
||||
|
||||
DEBUGP(DL1IF, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
|
||||
get_value_string(lc15bts_l1sapi_names, data_ind->sapi),
|
||||
data_ind->hLayer2,
|
||||
osmo_hexdump(data_ind->msgUnitParam.u8Buffer,
|
||||
data_ind->msgUnitParam.u8Size));
|
||||
|
||||
/*
|
||||
* TODO: Add proper bad frame handling here. This could be used
|
||||
* to switch the used CS. Avoid a crash with the PCU right now
|
||||
* feed "0 - 1" amount of data.
|
||||
*/
|
||||
if (data_ind->msgUnitParam.u8Size == 0)
|
||||
return -1;
|
||||
|
||||
gsmtap_send(fl1h->gsmtap, data_ind->u16Arfcn | GSMTAP_ARFCN_F_UPLINK,
|
||||
data_ind->u8Tn, GSMTAP_CHANNEL_PACCH, 0,
|
||||
data_ind->u32Fn, 0, 0, data_ind->msgUnitParam.u8Buffer+1,
|
||||
data_ind->msgUnitParam.u8Size-1);
|
||||
|
||||
get_meas(&meas, &data_ind->measParam);
|
||||
|
||||
switch (data_ind->sapi) {
|
||||
case GsmL1_Sapi_Pdtch:
|
||||
case GsmL1_Sapi_Pacch:
|
||||
/* drop incomplete UL block */
|
||||
if (data_ind->msgUnitParam.u8Buffer[0]
|
||||
!= GsmL1_PdtchPlType_Full)
|
||||
break;
|
||||
/* PDTCH / PACCH frame handling */
|
||||
pcu_rx_data_ind_pdtch(fl1h->trx_no, data_ind->u8Tn,
|
||||
data_ind->msgUnitParam.u8Buffer + 1,
|
||||
data_ind->msgUnitParam.u8Size - 1,
|
||||
data_ind->u32Fn,
|
||||
&meas);
|
||||
break;
|
||||
case GsmL1_Sapi_Ptcch:
|
||||
// FIXME
|
||||
break;
|
||||
default:
|
||||
LOGP(DL1IF, LOGL_NOTICE, "Rx PH-DATA.ind for unknown L1 SAPI %s\n",
|
||||
get_value_string(lc15bts_l1sapi_names, data_ind->sapi));
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define MIN_QUAL_RACH 5.0f
|
||||
|
||||
static int handle_ph_ra_ind(struct lc15l1_hdl *fl1h, GsmL1_PhRaInd_t *ra_ind)
|
||||
{
|
||||
uint8_t acc_delay;
|
||||
|
||||
if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH)
|
||||
return 0;
|
||||
|
||||
DEBUGP(DL1IF, "Rx PH-RA.ind");
|
||||
|
||||
/* check for under/overflow / sign */
|
||||
if (ra_ind->measParam.i16BurstTiming < 0)
|
||||
acc_delay = 0;
|
||||
else
|
||||
acc_delay = ra_ind->measParam.i16BurstTiming >> 2;
|
||||
|
||||
LOGP(DL1IF, LOGL_NOTICE, "got (P)RACH request, TA = %u (ignored)\n",
|
||||
acc_delay);
|
||||
|
||||
#warning "The (P)RACH request is just dropped here"
|
||||
|
||||
#if 0
|
||||
if (acc_delay > bts->max_ta) {
|
||||
LOGP(DL1C, LOGL_INFO, "ignoring RACH request %u > max_ta(%u)\n",
|
||||
acc_delay, btsb->max_ta);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* handle any random indication from the L1 */
|
||||
int l1if_handle_l1prim(int wq, struct lc15l1_hdl *fl1h, struct msgb *msg)
|
||||
{
|
||||
GsmL1_Prim_t *l1p = msgb_l1prim(msg);
|
||||
int rc = 0;
|
||||
|
||||
LOGP(DL1IF, LOGL_DEBUG, "Rx L1 prim %s on queue %d\n",
|
||||
get_value_string(lc15bts_l1prim_names, l1p->id), wq);
|
||||
|
||||
switch (l1p->id) {
|
||||
#if 0
|
||||
case GsmL1_PrimId_MphTimeInd:
|
||||
rc = handle_mph_time_ind(fl1h, &l1p->u.mphTimeInd);
|
||||
break;
|
||||
case GsmL1_PrimId_MphSyncInd:
|
||||
break;
|
||||
case GsmL1_PrimId_PhConnectInd:
|
||||
break;
|
||||
#endif
|
||||
case GsmL1_PrimId_PhReadyToSendInd:
|
||||
rc = handle_ph_readytosend_ind(fl1h, &l1p->u.phReadyToSendInd);
|
||||
break;
|
||||
case GsmL1_PrimId_PhDataInd:
|
||||
rc = handle_ph_data_ind(fl1h, &l1p->u.phDataInd, msg);
|
||||
break;
|
||||
case GsmL1_PrimId_PhRaInd:
|
||||
rc = handle_ph_ra_ind(fl1h, &l1p->u.phRaInd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
msgb_free(msg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int l1if_handle_sysprim(struct lc15l1_hdl *fl1h, struct msgb *msg)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* send packet data request to L1 */
|
||||
int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn,
|
||||
uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len)
|
||||
{
|
||||
struct lc15l1_hdl *fl1h = obj;
|
||||
struct msgb *msg;
|
||||
GsmL1_Prim_t *l1p;
|
||||
GsmL1_PhDataReq_t *data_req;
|
||||
GsmL1_MsgUnitParam_t *msu_param;
|
||||
struct gsm_time g_time;
|
||||
|
||||
gsm_fn2gsmtime(&g_time, fn);
|
||||
|
||||
DEBUGP(DL1IF, "TX packet data %02u/%02u/%02u is_ptcch=%d ts=%d "
|
||||
"block_nr=%d, arfcn=%d, len=%d\n", g_time.t1, g_time.t2,
|
||||
g_time.t3, is_ptcch, ts, block_nr, arfcn, len);
|
||||
|
||||
msg = l1p_msgb_alloc();
|
||||
l1p = msgb_l1prim(msg);
|
||||
l1p->id = GsmL1_PrimId_PhDataReq;
|
||||
data_req = &l1p->u.phDataReq;
|
||||
data_req->hLayer1 = (HANDLE)fl1h->hLayer1;
|
||||
data_req->sapi = (is_ptcch) ? GsmL1_Sapi_Ptcch : GsmL1_Sapi_Pdtch;
|
||||
data_req->subCh = GsmL1_SubCh_NA;
|
||||
data_req->u8BlockNbr = block_nr;
|
||||
data_req->u8Tn = ts;
|
||||
data_req->u32Fn = fn;
|
||||
msu_param = &data_req->msgUnitParam;
|
||||
msu_param->u8Size = len;
|
||||
memcpy(msu_param->u8Buffer, data, len);
|
||||
|
||||
gsmtap_send(fl1h->gsmtap, arfcn, data_req->u8Tn, GSMTAP_CHANNEL_PACCH,
|
||||
0, data_req->u32Fn, 0, 0,
|
||||
data_req->msgUnitParam.u8Buffer,
|
||||
data_req->msgUnitParam.u8Size);
|
||||
|
||||
|
||||
/* transmit */
|
||||
if (osmo_wqueue_enqueue(&fl1h->write_q[MQ_PDTCH_WRITE], msg) != 0) {
|
||||
LOGP(DL1IF, LOGL_ERROR, "PDTCH queue full. dropping message.\n");
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *l1if_open_pdch(uint8_t trx_no, uint32_t hlayer1)
|
||||
{
|
||||
struct lc15l1_hdl *fl1h;
|
||||
int rc;
|
||||
|
||||
fl1h = talloc_zero(tall_pcu_ctx, struct lc15l1_hdl);
|
||||
if (!fl1h)
|
||||
return NULL;
|
||||
|
||||
fl1h->hLayer1 = hlayer1;
|
||||
fl1h->trx_no = trx_no;
|
||||
/* hardware queues are numbered starting from 1 */
|
||||
fl1h->hw_info.trx_nr = trx_no + 1;
|
||||
|
||||
DEBUGP(DL1IF, "PCU: Using TRX HW#%u\n", fl1h->hw_info.trx_nr);
|
||||
|
||||
rc = l1if_transport_open(MQ_PDTCH_WRITE, fl1h);
|
||||
if (rc < 0) {
|
||||
talloc_free(fl1h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fl1h->gsmtap = gsmtap_source_init("localhost", GSMTAP_UDP_PORT, 1);
|
||||
if (fl1h->gsmtap)
|
||||
gsmtap_source_add_sink(fl1h->gsmtap);
|
||||
|
||||
return fl1h;
|
||||
}
|
||||
|
||||
int l1if_close_pdch(void *obj)
|
||||
{
|
||||
struct lc15l1_hdl *fl1h = obj;
|
||||
if (fl1h)
|
||||
l1if_transport_close(MQ_PDTCH_WRITE, fl1h);
|
||||
talloc_free(fl1h);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
|
||||
* based on:
|
||||
* femto_l1_if.h
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LC15_L1_IF_H
|
||||
#define _LC15_L1_IF_H
|
||||
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/core/write_queue.h>
|
||||
#include <osmocom/core/gsmtap_util.h>
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
#include "lc15bts.h"
|
||||
|
||||
enum {
|
||||
MQ_SYS_READ,
|
||||
MQ_L1_READ,
|
||||
MQ_TCH_READ,
|
||||
MQ_PDTCH_READ,
|
||||
_NUM_MQ_READ
|
||||
};
|
||||
|
||||
enum {
|
||||
MQ_SYS_WRITE,
|
||||
MQ_L1_WRITE,
|
||||
MQ_TCH_WRITE,
|
||||
MQ_PDTCH_WRITE,
|
||||
_NUM_MQ_WRITE
|
||||
};
|
||||
|
||||
struct lc15l1_hdl {
|
||||
struct gsm_time gsm_time;
|
||||
uint32_t hLayer1; /* handle to the L1 instance in the DSP */
|
||||
uint32_t dsp_trace_f;
|
||||
struct llist_head wlc_list;
|
||||
|
||||
struct gsmtap_inst *gsmtap;
|
||||
uint32_t gsmtap_sapi_mask;
|
||||
|
||||
uint8_t trx_no;
|
||||
|
||||
struct osmo_timer_list alive_timer;
|
||||
unsigned int alive_prim_cnt;
|
||||
|
||||
struct osmo_fd read_ofd[_NUM_MQ_READ]; /* osmo file descriptors */
|
||||
struct osmo_wqueue write_q[_NUM_MQ_WRITE];
|
||||
|
||||
struct {
|
||||
int trx_nr; /* <1-2> */
|
||||
} hw_info;
|
||||
};
|
||||
|
||||
#define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h)
|
||||
#define msgb_sysprim(msg) ((Litecell15_Prim_t *)(msg)->l1h)
|
||||
|
||||
typedef int l1if_compl_cb(struct msgb *l1_msg, void *data);
|
||||
|
||||
/* send a request primitive to the L1 and schedule completion call-back */
|
||||
int l1if_req_compl(struct lc15l1_hdl *fl1h, struct msgb *msg,
|
||||
int is_system_prim, l1if_compl_cb *cb, void *data);
|
||||
|
||||
int l1if_reset(struct lc15l1_hdl *hdl);
|
||||
int l1if_activate_rf(struct lc15l1_hdl *hdl, int on);
|
||||
int l1if_set_trace_flags(struct lc15l1_hdl *hdl, uint32_t flags);
|
||||
int l1if_set_txpower(struct lc15l1_hdl *fl1h, float tx_power);
|
||||
|
||||
struct msgb *l1p_msgb_alloc(void);
|
||||
struct msgb *sysp_msgb_alloc(void);
|
||||
|
||||
uint32_t l1if_lchan_to_hLayer2(struct gsm_lchan *lchan);
|
||||
struct gsm_lchan *l1if_hLayer2_to_lchan(struct gsm_bts_trx *trx, uint32_t hLayer2);
|
||||
|
||||
int l1if_handle_sysprim(struct lc15l1_hdl *fl1h, struct msgb *msg);
|
||||
int l1if_handle_l1prim(int wq, struct lc15l1_hdl *fl1h, struct msgb *msg);
|
||||
|
||||
/* tch.c */
|
||||
int l1if_tch_rx(struct gsm_lchan *lchan, 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);
|
||||
|
||||
/*
|
||||
* The implementation of these functions is selected by either compiling and
|
||||
* linking sysmo_l1_hw.c or sysmo_l1_fwd.c
|
||||
*/
|
||||
int l1if_transport_open(int q, struct lc15l1_hdl *hdl);
|
||||
int l1if_transport_close(int q, struct lc15l1_hdl *hdl);
|
||||
|
||||
#endif /* _SYSMO_L1_IF_H */
|
|
@ -0,0 +1,332 @@
|
|||
/* NuRAN Wireless Litecell 1.5 L1 API related definitions */
|
||||
|
||||
/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
|
||||
* based on:
|
||||
* sysmobts.c
|
||||
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* 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 <nrw/litecell15/litecell15.h>
|
||||
#include <nrw/litecell15/gsml1const.h>
|
||||
#include <nrw/litecell15/gsml1dbg.h>
|
||||
|
||||
#include "lc15bts.h"
|
||||
|
||||
enum l1prim_type lc15bts_get_l1prim_type(GsmL1_PrimId_t id)
|
||||
{
|
||||
switch (id) {
|
||||
case GsmL1_PrimId_MphInitReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_MphCloseReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_MphConnectReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_MphDisconnectReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_MphActivateReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_MphDeactivateReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_MphConfigReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_MphMeasureReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_MphInitCnf: return L1P_T_CONF;
|
||||
case GsmL1_PrimId_MphCloseCnf: return L1P_T_CONF;
|
||||
case GsmL1_PrimId_MphConnectCnf: return L1P_T_CONF;
|
||||
case GsmL1_PrimId_MphDisconnectCnf: return L1P_T_CONF;
|
||||
case GsmL1_PrimId_MphActivateCnf: return L1P_T_CONF;
|
||||
case GsmL1_PrimId_MphDeactivateCnf: return L1P_T_CONF;
|
||||
case GsmL1_PrimId_MphConfigCnf: return L1P_T_CONF;
|
||||
case GsmL1_PrimId_MphMeasureCnf: return L1P_T_CONF;
|
||||
case GsmL1_PrimId_PhEmptyFrameReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_PhDataReq: return L1P_T_REQ;
|
||||
case GsmL1_PrimId_MphTimeInd: return L1P_T_IND;
|
||||
case GsmL1_PrimId_MphSyncInd: return L1P_T_IND;
|
||||
case GsmL1_PrimId_PhConnectInd: return L1P_T_IND;
|
||||
case GsmL1_PrimId_PhReadyToSendInd: return L1P_T_IND;
|
||||
case GsmL1_PrimId_PhDataInd: return L1P_T_IND;
|
||||
case GsmL1_PrimId_PhRaInd: return L1P_T_IND;
|
||||
default: return L1P_T_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
const struct value_string lc15bts_l1prim_names[GsmL1_PrimId_NUM+1] = {
|
||||
{ GsmL1_PrimId_MphInitReq, "MPH-INIT.req" },
|
||||
{ GsmL1_PrimId_MphCloseReq, "MPH-CLOSE.req" },
|
||||
{ GsmL1_PrimId_MphConnectReq, "MPH-CONNECT.req" },
|
||||
{ GsmL1_PrimId_MphDisconnectReq,"MPH-DISCONNECT.req" },
|
||||
{ GsmL1_PrimId_MphActivateReq, "MPH-ACTIVATE.req" },
|
||||
{ GsmL1_PrimId_MphDeactivateReq,"MPH-DEACTIVATE.req" },
|
||||
{ GsmL1_PrimId_MphConfigReq, "MPH-CONFIG.req" },
|
||||
{ GsmL1_PrimId_MphMeasureReq, "MPH-MEASURE.req" },
|
||||
{ GsmL1_PrimId_MphInitCnf, "MPH-INIT.conf" },
|
||||
{ GsmL1_PrimId_MphCloseCnf, "MPH-CLOSE.conf" },
|
||||
{ GsmL1_PrimId_MphConnectCnf, "MPH-CONNECT.conf" },
|
||||
{ GsmL1_PrimId_MphDisconnectCnf,"MPH-DISCONNECT.conf" },
|
||||
{ GsmL1_PrimId_MphActivateCnf, "MPH-ACTIVATE.conf" },
|
||||
{ GsmL1_PrimId_MphDeactivateCnf,"MPH-DEACTIVATE.conf" },
|
||||
{ GsmL1_PrimId_MphConfigCnf, "MPH-CONFIG.conf" },
|
||||
{ GsmL1_PrimId_MphMeasureCnf, "MPH-MEASURE.conf" },
|
||||
{ GsmL1_PrimId_MphTimeInd, "MPH-TIME.ind" },
|
||||
{ GsmL1_PrimId_MphSyncInd, "MPH-SYNC.ind" },
|
||||
{ GsmL1_PrimId_PhEmptyFrameReq, "PH-EMPTY_FRAME.req" },
|
||||
{ GsmL1_PrimId_PhDataReq, "PH-DATA.req" },
|
||||
{ GsmL1_PrimId_PhConnectInd, "PH-CONNECT.ind" },
|
||||
{ GsmL1_PrimId_PhReadyToSendInd,"PH-READY_TO_SEND.ind" },
|
||||
{ GsmL1_PrimId_PhDataInd, "PH-DATA.ind" },
|
||||
{ GsmL1_PrimId_PhRaInd, "PH-RA.ind" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
GsmL1_PrimId_t lc15bts_get_l1prim_conf(GsmL1_PrimId_t id)
|
||||
{
|
||||
switch (id) {
|
||||
case GsmL1_PrimId_MphInitReq: return GsmL1_PrimId_MphInitCnf;
|
||||
case GsmL1_PrimId_MphCloseReq: return GsmL1_PrimId_MphCloseCnf;
|
||||
case GsmL1_PrimId_MphConnectReq: return GsmL1_PrimId_MphConnectCnf;
|
||||
case GsmL1_PrimId_MphDisconnectReq: return GsmL1_PrimId_MphDisconnectCnf;
|
||||
case GsmL1_PrimId_MphActivateReq: return GsmL1_PrimId_MphActivateCnf;
|
||||
case GsmL1_PrimId_MphDeactivateReq: return GsmL1_PrimId_MphDeactivateCnf;
|
||||
case GsmL1_PrimId_MphConfigReq: return GsmL1_PrimId_MphConfigCnf;
|
||||
case GsmL1_PrimId_MphMeasureReq: return GsmL1_PrimId_MphMeasureCnf;
|
||||
default: return -1; // Weak
|
||||
}
|
||||
}
|
||||
|
||||
enum l1prim_type lc15bts_get_sysprim_type(Litecell15_PrimId_t id)
|
||||
{
|
||||
switch (id) {
|
||||
case Litecell15_PrimId_SystemInfoReq: return L1P_T_REQ;
|
||||
case Litecell15_PrimId_SystemInfoCnf: return L1P_T_CONF;
|
||||
case Litecell15_PrimId_SystemFailureInd: return L1P_T_IND;
|
||||
case Litecell15_PrimId_ActivateRfReq: return L1P_T_REQ;
|
||||
case Litecell15_PrimId_ActivateRfCnf: return L1P_T_CONF;
|
||||
case Litecell15_PrimId_DeactivateRfReq: return L1P_T_REQ;
|
||||
case Litecell15_PrimId_DeactivateRfCnf: return L1P_T_CONF;
|
||||
case Litecell15_PrimId_SetTraceFlagsReq: return L1P_T_REQ;
|
||||
case Litecell15_PrimId_Layer1ResetReq: return L1P_T_REQ;
|
||||
case Litecell15_PrimId_Layer1ResetCnf: return L1P_T_CONF;
|
||||
case Litecell15_PrimId_SetCalibTblReq: return L1P_T_REQ;
|
||||
case Litecell15_PrimId_SetCalibTblCnf: return L1P_T_CONF;
|
||||
case Litecell15_PrimId_MuteRfReq: return L1P_T_REQ;
|
||||
case Litecell15_PrimId_MuteRfCnf: return L1P_T_CONF;
|
||||
case Litecell15_PrimId_SetRxAttenReq: return L1P_T_REQ;
|
||||
case Litecell15_PrimId_SetRxAttenCnf: return L1P_T_CONF;
|
||||
default: return L1P_T_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
const struct value_string lc15bts_sysprim_names[Litecell15_PrimId_NUM+1] = {
|
||||
{ Litecell15_PrimId_SystemInfoReq, "SYSTEM-INFO.req" },
|
||||
{ Litecell15_PrimId_SystemInfoCnf, "SYSTEM-INFO.conf" },
|
||||
{ Litecell15_PrimId_SystemFailureInd, "SYSTEM-FAILURE.ind" },
|
||||
{ Litecell15_PrimId_ActivateRfReq, "ACTIVATE-RF.req" },
|
||||
{ Litecell15_PrimId_ActivateRfCnf, "ACTIVATE-RF.conf" },
|
||||
{ Litecell15_PrimId_DeactivateRfReq, "DEACTIVATE-RF.req" },
|
||||
{ Litecell15_PrimId_DeactivateRfCnf, "DEACTIVATE-RF.conf" },
|
||||
{ Litecell15_PrimId_SetTraceFlagsReq, "SET-TRACE-FLAGS.req" },
|
||||
{ Litecell15_PrimId_Layer1ResetReq, "LAYER1-RESET.req" },
|
||||
{ Litecell15_PrimId_Layer1ResetCnf, "LAYER1-RESET.conf" },
|
||||
{ Litecell15_PrimId_SetCalibTblReq, "SET-CALIB.req" },
|
||||
{ Litecell15_PrimId_SetCalibTblCnf, "SET-CALIB.cnf" },
|
||||
{ Litecell15_PrimId_MuteRfReq, "MUTE-RF.req" },
|
||||
{ Litecell15_PrimId_MuteRfCnf, "MUTE-RF.cnf" },
|
||||
{ Litecell15_PrimId_SetRxAttenReq, "SET-RX-ATTEN.req" },
|
||||
{ Litecell15_PrimId_SetRxAttenCnf, "SET-RX-ATTEN-CNF.cnf" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
Litecell15_PrimId_t lc15bts_get_sysprim_conf(Litecell15_PrimId_t id)
|
||||
{
|
||||
switch (id) {
|
||||
case Litecell15_PrimId_SystemInfoReq: return Litecell15_PrimId_SystemInfoCnf;
|
||||
case Litecell15_PrimId_ActivateRfReq: return Litecell15_PrimId_ActivateRfCnf;
|
||||
case Litecell15_PrimId_DeactivateRfReq: return Litecell15_PrimId_DeactivateRfCnf;
|
||||
case Litecell15_PrimId_Layer1ResetReq: return Litecell15_PrimId_Layer1ResetCnf;
|
||||
case Litecell15_PrimId_SetCalibTblReq: return Litecell15_PrimId_SetCalibTblCnf;
|
||||
case Litecell15_PrimId_MuteRfReq: return Litecell15_PrimId_MuteRfCnf;
|
||||
case Litecell15_PrimId_SetRxAttenReq: return Litecell15_PrimId_SetRxAttenCnf;
|
||||
default: return -1; // Weak
|
||||
}
|
||||
}
|
||||
|
||||
const struct value_string lc15bts_l1sapi_names[GsmL1_Sapi_NUM+1] = {
|
||||
{ GsmL1_Sapi_Idle, "IDLE" },
|
||||
{ GsmL1_Sapi_Fcch, "FCCH" },
|
||||
{ GsmL1_Sapi_Sch, "SCH" },
|
||||
{ GsmL1_Sapi_Sacch, "SACCH" },
|
||||
{ GsmL1_Sapi_Sdcch, "SDCCH" },
|
||||
{ GsmL1_Sapi_Bcch, "BCCH" },
|
||||
{ GsmL1_Sapi_Pch, "PCH" },
|
||||
{ GsmL1_Sapi_Agch, "AGCH" },
|
||||
{ GsmL1_Sapi_Cbch, "CBCH" },
|
||||
{ GsmL1_Sapi_Rach, "RACH" },
|
||||
{ GsmL1_Sapi_TchF, "TCH/F" },
|
||||
{ GsmL1_Sapi_FacchF, "FACCH/F" },
|
||||
{ GsmL1_Sapi_TchH, "TCH/H" },
|
||||
{ GsmL1_Sapi_FacchH, "FACCH/H" },
|
||||
{ GsmL1_Sapi_Nch, "NCH" },
|
||||
{ GsmL1_Sapi_Pdtch, "PDTCH" },
|
||||
{ GsmL1_Sapi_Pacch, "PACCH" },
|
||||
{ GsmL1_Sapi_Pbcch, "PBCCH" },
|
||||
{ GsmL1_Sapi_Pagch, "PAGCH" },
|
||||
{ GsmL1_Sapi_Ppch, "PPCH" },
|
||||
{ GsmL1_Sapi_Pnch, "PNCH" },
|
||||
{ GsmL1_Sapi_Ptcch, "PTCCH" },
|
||||
{ GsmL1_Sapi_Prach, "PRACH" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const struct value_string lc15bts_l1status_names[GSML1_STATUS_NUM+1] = {
|
||||
{ GsmL1_Status_Success, "Success" },
|
||||
{ GsmL1_Status_Generic, "Generic error" },
|
||||
{ GsmL1_Status_NoMemory, "Not enough memory" },
|
||||
{ GsmL1_Status_Timeout, "Timeout" },
|
||||
{ GsmL1_Status_InvalidParam, "Invalid parameter" },
|
||||
{ GsmL1_Status_Busy, "Resource busy" },
|
||||
{ GsmL1_Status_NoRessource, "No more resources" },
|
||||
{ GsmL1_Status_Uninitialized, "Trying to use uninitialized resource" },
|
||||
{ GsmL1_Status_NullInterface, "Trying to call a NULL interface" },
|
||||
{ GsmL1_Status_NullFctnPtr, "Trying to call a NULL function ptr" },
|
||||
{ GsmL1_Status_BadCrc, "Bad CRC" },
|
||||
{ GsmL1_Status_BadUsf, "Bad USF" },
|
||||
{ GsmL1_Status_InvalidCPS, "Invalid CPS field" },
|
||||
{ GsmL1_Status_UnexpectedBurst, "Unexpected burst" },
|
||||
{ GsmL1_Status_UnavailCodec, "AMR codec is unavailable" },
|
||||
{ GsmL1_Status_CriticalError, "Critical error" },
|
||||
{ GsmL1_Status_OverheatError, "Overheat error" },
|
||||
{ GsmL1_Status_DeviceError, "Device error" },
|
||||
{ GsmL1_Status_FacchError, "FACCH / TCH order error" },
|
||||
{ GsmL1_Status_AlreadyDeactivated, "Lchan already deactivated" },
|
||||
{ GsmL1_Status_TxBurstFifoOvrn, "FIFO overrun" },
|
||||
{ GsmL1_Status_TxBurstFifoUndr, "FIFO underrun" },
|
||||
{ GsmL1_Status_NotSynchronized, "Not synchronized" },
|
||||
{ GsmL1_Status_Unsupported, "Unsupported feature" },
|
||||
{ GsmL1_Status_ClockError, "System clock error" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const struct value_string lc15bts_tracef_names[29] = {
|
||||
{ DBG_DEBUG, "DEBUG" },
|
||||
{ DBG_L1WARNING, "L1_WARNING" },
|
||||
{ DBG_ERROR, "ERROR" },
|
||||
{ DBG_L1RXMSG, "L1_RX_MSG" },
|
||||
{ DBG_L1RXMSGBYTE, "L1_RX_MSG_BYTE" },
|
||||
{ DBG_L1TXMSG, "L1_TX_MSG" },
|
||||
{ DBG_L1TXMSGBYTE, "L1_TX_MSG_BYTE" },
|
||||
{ DBG_MPHCNF, "MPH_CNF" },
|
||||
{ DBG_MPHIND, "MPH_IND" },
|
||||
{ DBG_MPHREQ, "MPH_REQ" },
|
||||
{ DBG_PHIND, "PH_IND" },
|
||||
{ DBG_PHREQ, "PH_REQ" },
|
||||
{ DBG_PHYRF, "PHY_RF" },
|
||||
{ DBG_PHYRFMSGBYTE, "PHY_MSG_BYTE" },
|
||||
{ DBG_MODE, "MODE" },
|
||||
{ DBG_TDMAINFO, "TDMA_INFO" },
|
||||
{ DBG_BADCRC, "BAD_CRC" },
|
||||
{ DBG_PHINDBYTE, "PH_IND_BYTE" },
|
||||
{ DBG_PHREQBYTE, "PH_REQ_BYTE" },
|
||||
{ DBG_DEVICEMSG, "DEVICE_MSG" },
|
||||
{ DBG_RACHINFO, "RACH_INFO" },
|
||||
{ DBG_LOGCHINFO, "LOG_CH_INFO" },
|
||||
{ DBG_MEMORY, "MEMORY" },
|
||||
{ DBG_PROFILING, "PROFILING" },
|
||||
{ DBG_TESTCOMMENT, "TEST_COMMENT" },
|
||||
{ DBG_TEST, "TEST" },
|
||||
{ DBG_STATUS, "STATUS" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const struct value_string lc15bts_tracef_docs[29] = {
|
||||
{ DBG_DEBUG, "Debug Region" },
|
||||
{ DBG_L1WARNING, "L1 Warning Region" },
|
||||
{ DBG_ERROR, "Error Region" },
|
||||
{ DBG_L1RXMSG, "L1_RX_MSG Region" },
|
||||
{ DBG_L1RXMSGBYTE, "L1_RX_MSG_BYTE Region" },
|
||||
{ DBG_L1TXMSG, "L1_TX_MSG Region" },
|
||||
{ DBG_L1TXMSGBYTE, "L1_TX_MSG_BYTE Region" },
|
||||
{ DBG_MPHCNF, "MphConfirmation Region" },
|
||||
{ DBG_MPHIND, "MphIndication Region" },
|
||||
{ DBG_MPHREQ, "MphRequest Region" },
|
||||
{ DBG_PHIND, "PhIndication Region" },
|
||||
{ DBG_PHREQ, "PhRequest Region" },
|
||||
{ DBG_PHYRF, "PhyRF Region" },
|
||||
{ DBG_PHYRFMSGBYTE, "PhyRF Message Region" },
|
||||
{ DBG_MODE, "Mode Region" },
|
||||
{ DBG_TDMAINFO, "TDMA Info Region" },
|
||||
{ DBG_BADCRC, "Bad CRC Region" },
|
||||
{ DBG_PHINDBYTE, "PH_IND_BYTE" },
|
||||
{ DBG_PHREQBYTE, "PH_REQ_BYTE" },
|
||||
{ DBG_DEVICEMSG, "Device Message Region" },
|
||||
{ DBG_RACHINFO, "RACH Info" },
|
||||
{ DBG_LOGCHINFO, "LOG_CH_INFO" },
|
||||
{ DBG_MEMORY, "Memory Region" },
|
||||
{ DBG_PROFILING, "Profiling Region" },
|
||||
{ DBG_TESTCOMMENT, "Test Comments" },
|
||||
{ DBG_TEST, "Test Region" },
|
||||
{ DBG_STATUS, "Status Region" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const struct value_string lc15bts_tch_pl_names[] = {
|
||||
{ GsmL1_TchPlType_NA, "N/A" },
|
||||
{ GsmL1_TchPlType_Fr, "FR" },
|
||||
{ GsmL1_TchPlType_Hr, "HR" },
|
||||
{ GsmL1_TchPlType_Efr, "EFR" },
|
||||
{ GsmL1_TchPlType_Amr, "AMR(IF2)" },
|
||||
{ GsmL1_TchPlType_Amr_SidBad, "AMR(SID BAD)" },
|
||||
{ GsmL1_TchPlType_Amr_Onset, "AMR(ONSET)" },
|
||||
{ GsmL1_TchPlType_Amr_Ratscch, "AMR(RATSCCH)" },
|
||||
{ GsmL1_TchPlType_Amr_SidUpdateInH, "AMR(SID_UPDATE INH)" },
|
||||
{ GsmL1_TchPlType_Amr_SidFirstP1, "AMR(SID_FIRST P1)" },
|
||||
{ GsmL1_TchPlType_Amr_SidFirstP2, "AMR(SID_FIRST P2)" },
|
||||
{ GsmL1_TchPlType_Amr_SidFirstInH, "AMR(SID_FIRST INH)" },
|
||||
{ GsmL1_TchPlType_Amr_RatscchMarker, "AMR(RATSCCH MARK)" },
|
||||
{ GsmL1_TchPlType_Amr_RatscchData, "AMR(RATSCCH DATA)" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const struct value_string lc15bts_dir_names[] = {
|
||||
{ GsmL1_Dir_TxDownlink, "TxDL" },
|
||||
{ GsmL1_Dir_TxUplink, "TxUL" },
|
||||
{ GsmL1_Dir_RxUplink, "RxUL" },
|
||||
{ GsmL1_Dir_RxDownlink, "RxDL" },
|
||||
{ GsmL1_Dir_TxDownlink|GsmL1_Dir_RxUplink, "BOTH" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const struct value_string lc15bts_chcomb_names[] = {
|
||||
{ GsmL1_LogChComb_0, "dummy" },
|
||||
{ GsmL1_LogChComb_I, "tch_f" },
|
||||
{ GsmL1_LogChComb_II, "tch_h" },
|
||||
{ GsmL1_LogChComb_IV, "ccch" },
|
||||
{ GsmL1_LogChComb_V, "ccch_sdcch4" },
|
||||
{ GsmL1_LogChComb_VII, "sdcch8" },
|
||||
{ GsmL1_LogChComb_XIII, "pdtch" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
const uint8_t pdch_msu_size[_NUM_PDCH_CS] = {
|
||||
[PDCH_CS_1] = 23,
|
||||
[PDCH_CS_2] = 34,
|
||||
[PDCH_CS_3] = 40,
|
||||
[PDCH_CS_4] = 54,
|
||||
[PDCH_MCS_1] = 27,
|
||||
[PDCH_MCS_2] = 33,
|
||||
[PDCH_MCS_3] = 42,
|
||||
[PDCH_MCS_4] = 49,
|
||||
[PDCH_MCS_5] = 60,
|
||||
[PDCH_MCS_6] = 78,
|
||||
[PDCH_MCS_7] = 118,
|
||||
[PDCH_MCS_8] = 142,
|
||||
[PDCH_MCS_9] = 154
|
||||
};
|
|
@ -0,0 +1,64 @@
|
|||
#ifndef LC15BTS_H
|
||||
#define LC15BTS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
#include <nrw/litecell15/litecell15.h>
|
||||
#include <nrw/litecell15/gsml1const.h>
|
||||
|
||||
/*
|
||||
* Depending on the firmware version either GsmL1_Prim_t or Litecell15_Prim_t
|
||||
* is the bigger struct. For earlier firmware versions the GsmL1_Prim_t was the
|
||||
* bigger struct.
|
||||
*/
|
||||
#define LC15BTS_PRIM_SIZE \
|
||||
(OSMO_MAX(sizeof(Litecell15_Prim_t), sizeof(GsmL1_Prim_t)) + 128)
|
||||
|
||||
enum l1prim_type {
|
||||
L1P_T_INVALID, /* this must be 0 to detect uninitialized elements */
|
||||
L1P_T_REQ,
|
||||
L1P_T_CONF,
|
||||
L1P_T_IND,
|
||||
};
|
||||
|
||||
enum l1prim_type lc15bts_get_l1prim_type(GsmL1_PrimId_t id);
|
||||
const struct value_string lc15bts_l1prim_names[GsmL1_PrimId_NUM+1];
|
||||
GsmL1_PrimId_t lc15bts_get_l1prim_conf(GsmL1_PrimId_t id);
|
||||
|
||||
enum l1prim_type lc15bts_get_sysprim_type(Litecell15_PrimId_t id);
|
||||
const struct value_string lc15bts_sysprim_names[Litecell15_PrimId_NUM+1];
|
||||
Litecell15_PrimId_t lc15bts_get_sysprim_conf(Litecell15_PrimId_t id);
|
||||
|
||||
const struct value_string lc15bts_l1sapi_names[GsmL1_Sapi_NUM+1];
|
||||
const struct value_string lc15bts_l1status_names[GSML1_STATUS_NUM+1];
|
||||
|
||||
const struct value_string lc15bts_tracef_names[29];
|
||||
const struct value_string lc15bts_tracef_docs[29];
|
||||
|
||||
const struct value_string lc15bts_tch_pl_names[15];
|
||||
|
||||
const struct value_string lc15bts_clksrc_names[10];
|
||||
|
||||
const struct value_string lc15bts_dir_names[6];
|
||||
|
||||
enum pdch_cs {
|
||||
PDCH_CS_1,
|
||||
PDCH_CS_2,
|
||||
PDCH_CS_3,
|
||||
PDCH_CS_4,
|
||||
PDCH_MCS_1,
|
||||
PDCH_MCS_2,
|
||||
PDCH_MCS_3,
|
||||
PDCH_MCS_4,
|
||||
PDCH_MCS_5,
|
||||
PDCH_MCS_6,
|
||||
PDCH_MCS_7,
|
||||
PDCH_MCS_8,
|
||||
PDCH_MCS_9,
|
||||
_NUM_PDCH_CS
|
||||
};
|
||||
|
||||
const uint8_t pdch_msu_size[_NUM_PDCH_CS];
|
||||
|
||||
#endif /* LC15BTS_H */
|
|
@ -155,7 +155,7 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1h,
|
|||
switch (rts_ind->sapi) {
|
||||
case GsmL1_Sapi_Pdtch:
|
||||
case GsmL1_Sapi_Pacch:
|
||||
rc = pcu_rx_rts_req_pdtch((long)fl1h->priv, rts_ind->u8Tn,
|
||||
rc = pcu_rx_rts_req_pdtch(fl1h->trx_no, rts_ind->u8Tn,
|
||||
rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr);
|
||||
case GsmL1_Sapi_Ptcch:
|
||||
// FIXME
|
||||
|
@ -215,7 +215,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
|
|||
!= GsmL1_PdtchPlType_Full)
|
||||
break;
|
||||
/* PDTCH / PACCH frame handling */
|
||||
pcu_rx_data_ind_pdtch((long)fl1h->priv, data_ind->u8Tn,
|
||||
pcu_rx_data_ind_pdtch(fl1h->trx_no, data_ind->u8Tn,
|
||||
data_ind->msgUnitParam.u8Buffer + 1,
|
||||
data_ind->msgUnitParam.u8Size - 1,
|
||||
data_ind->u32Fn,
|
||||
|
@ -357,7 +357,7 @@ int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap)
|
||||
void *l1if_open_pdch(uint8_t trx_no, uint32_t hlayer1, struct gsmtap_inst *gsmtap)
|
||||
{
|
||||
struct femtol1_hdl *fl1h;
|
||||
int rc;
|
||||
|
@ -367,7 +367,7 @@ void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap)
|
|||
return NULL;
|
||||
|
||||
fl1h->hLayer1 = hlayer1;
|
||||
fl1h->priv = priv;
|
||||
fl1h->trx_no = trx_no;
|
||||
fl1h->clk_cal = 0;
|
||||
/* default clock source: OCXO */
|
||||
fl1h->clk_src = SuperFemto_ClkSrcId_Ocxo;
|
|
@ -38,7 +38,7 @@ struct femtol1_hdl {
|
|||
struct gsmtap_inst *gsmtap;
|
||||
uint32_t gsmtap_sapi_mask;
|
||||
|
||||
void *priv; /* user reference */
|
||||
uint8_t trx_no;
|
||||
|
||||
struct osmo_timer_list alive_timer;
|
||||
unsigned int alive_prim_cnt;
|
|
@ -100,7 +100,7 @@ static void pcu_sock_close(struct pcu_sock_state *state, int lost)
|
|||
|
||||
/* disable all slots, kick all TBFs */
|
||||
for (trx = 0; trx < 8; trx++) {
|
||||
#ifdef ENABLE_SYSMODSP
|
||||
#ifdef ENABLE_DIRECT_PHY
|
||||
if (bts->trx[trx].fl1h) {
|
||||
l1if_close_pdch(bts->trx[trx].fl1h);
|
||||
bts->trx[trx].fl1h = NULL;
|
||||
|
|
|
@ -44,7 +44,8 @@ extern "C" {
|
|||
|
||||
// FIXME: move this, when changed from c++ to c.
|
||||
extern "C" {
|
||||
void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap);
|
||||
void *l1if_open_pdch(uint8_t trx_no, uint32_t hlayer1,
|
||||
struct gsmtap_inst *gsmtap);
|
||||
int l1if_connect_pdch(void *obj, uint8_t ts);
|
||||
int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn,
|
||||
uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len);
|
||||
|
@ -128,7 +129,7 @@ void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
|
|||
{
|
||||
struct gprs_rlcmac_bts *bts = bts_main_data();
|
||||
|
||||
#ifdef ENABLE_SYSMODSP
|
||||
#ifdef ENABLE_DIRECT_PHY
|
||||
if (bts->trx[trx].fl1h) {
|
||||
l1if_pdch_req(bts->trx[trx].fl1h, ts, 0, fn, arfcn, block_nr,
|
||||
msg->data, msg->len);
|
||||
|
@ -147,7 +148,7 @@ void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
|
|||
{
|
||||
struct gprs_rlcmac_bts *bts = bts_main_data();
|
||||
|
||||
#ifdef ENABLE_SYSMODSP
|
||||
#ifdef ENABLE_DIRECT_PHY
|
||||
if (bts->trx[trx].fl1h) {
|
||||
l1if_pdch_req(bts->trx[trx].fl1h, ts, 1, fn, arfcn, block_nr,
|
||||
msg->data, msg->len);
|
||||
|
@ -330,8 +331,8 @@ static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind)
|
|||
struct gprs_bssgp_pcu *pcu;
|
||||
struct gprs_rlcmac_pdch *pdch;
|
||||
struct in_addr ia;
|
||||
int rc = 0;
|
||||
int trx, ts;
|
||||
int rc = 0, ts;
|
||||
uint8_t trx;
|
||||
int i;
|
||||
|
||||
if (info_ind->version != PCU_IF_VERSION) {
|
||||
|
@ -445,12 +446,12 @@ bssgp_failed:
|
|||
bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
|
||||
if ((info_ind->flags & PCU_IF_FLAG_SYSMO)
|
||||
&& info_ind->trx[trx].hlayer1) {
|
||||
#ifdef ENABLE_SYSMODSP
|
||||
#ifdef ENABLE_DIRECT_PHY
|
||||
LOGP(DL1IF, LOGL_DEBUG, " TRX %d hlayer1=%x\n", trx,
|
||||
info_ind->trx[trx].hlayer1);
|
||||
if (!bts->trx[trx].fl1h)
|
||||
bts->trx[trx].fl1h = l1if_open_pdch(
|
||||
(void *)trx,
|
||||
trx,
|
||||
info_ind->trx[trx].hlayer1,
|
||||
bts->gsmtap);
|
||||
if (!bts->trx[trx].fl1h) {
|
||||
|
@ -471,7 +472,7 @@ bssgp_failed:
|
|||
if ((info_ind->trx[trx].pdch_mask & (1 << ts))) {
|
||||
/* FIXME: activate dynamically at RLCMAC */
|
||||
if (!pdch->is_enabled()) {
|
||||
#ifdef ENABLE_SYSMODSP
|
||||
#ifdef ENABLE_DIRECT_PHY
|
||||
if ((info_ind->flags &
|
||||
PCU_IF_FLAG_SYSMO))
|
||||
l1if_connect_pdch(
|
||||
|
|
|
@ -46,7 +46,7 @@ void *tall_pcu_ctx;
|
|||
extern void *bv_tall_ctx;
|
||||
static int quit = 0;
|
||||
static int rt_prio = -1;
|
||||
static char *gsmtap_addr = "localhost"; // FIXME: use gengetopt's default value instead
|
||||
static const char *gsmtap_addr = "localhost"; // FIXME: use gengetopt's default value instead
|
||||
|
||||
static void print_help()
|
||||
{
|
||||
|
@ -189,8 +189,8 @@ int main(int argc, char *argv[])
|
|||
bts->cs_adj_lower_limit = 10; /* Increase CS if the error rate is below */
|
||||
bts->max_cs_ul = 4;
|
||||
bts->max_cs_dl = 4;
|
||||
bts->max_mcs_ul = 4;
|
||||
bts->max_mcs_dl = 4;
|
||||
bts->max_mcs_ul = 9;
|
||||
bts->max_mcs_dl = 9;
|
||||
/* CS-1 to CS-4 */
|
||||
bts->cs_lqual_ranges[0].low = -256;
|
||||
bts->cs_lqual_ranges[0].high = 6;
|
||||
|
@ -210,6 +210,12 @@ int main(int argc, char *argv[])
|
|||
bts->dl_tbf_idle_msec = 2000;
|
||||
bts->llc_idle_ack_csec = 10;
|
||||
|
||||
/*
|
||||
* By default resegmentation is supported in DL
|
||||
* TODO: VTY should be updated to make it configurable
|
||||
*/
|
||||
bts->arq_type = 0;
|
||||
|
||||
msgb_set_talloc_ctx(tall_pcu_ctx);
|
||||
|
||||
osmo_init_logging(&gprs_log_info);
|
||||
|
|
|
@ -66,14 +66,32 @@ static void tbf_print_vty_info(struct vty *vty, gprs_rlcmac_tbf *tbf)
|
|||
|
||||
if (ul_tbf) {
|
||||
gprs_rlc_ul_window *win = &ul_tbf->m_window;
|
||||
vty_out(vty, " V(Q)=%d V(R)=%d",
|
||||
win->v_q(), win->v_r());
|
||||
vty_out(vty, " V(Q)=%d V(R)=%d RX_CNTR=%d",
|
||||
win->v_q(), win->v_r(), ul_tbf->m_rx_counter);
|
||||
vty_out(vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
vty_out(vty, " MCS%d=%d ", i+1, tbf->m_ctr_num_blocks[i]);
|
||||
}
|
||||
}
|
||||
if (dl_tbf) {
|
||||
gprs_rlc_dl_window *win = &dl_tbf->m_window;
|
||||
vty_out(vty, " V(A)=%d V(S)=%d nBSN=%d%s",
|
||||
win->v_a(), win->v_s(), win->resend_needed(),
|
||||
win->window_stalled() ? " STALLED" : "");
|
||||
vty_out(vty,
|
||||
" V(A)=%d V(S)=%d LLC_QUEUE_SIZE=%d LLC_OCTETS=%d "
|
||||
"nBSN=%d%s NA=%u A=%u",
|
||||
win->v_a(), win->v_s(), dl_tbf->llc_queue()->size(),
|
||||
dl_tbf->llc_queue()->octets(),
|
||||
win->resend_needed(),
|
||||
win->window_stalled() ? " STALLED" : "",
|
||||
dl_tbf->m_bw.total_dl_loss_lost,
|
||||
dl_tbf->m_bw.total_dl_loss_received);
|
||||
vty_out(vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
vty_out(vty, " MCS%d=%d ", i+1, tbf->m_ctr_num_blocks[i]);
|
||||
}
|
||||
vty_out(vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
vty_out(vty, " retx%d=%d ", i+1, tbf->m_ctr_retx[i]);
|
||||
}
|
||||
}
|
||||
vty_out(vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
|
||||
}
|
||||
|
@ -102,7 +120,7 @@ int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)
|
|||
llist_for_each(ms_iter, &bts->ms_store().ms_list()) {
|
||||
GprsMs *ms = ms_iter->entry();
|
||||
|
||||
vty_out(vty, "MS TLLI=%08x, TA=%d, CS-UL=%s, CS-DL=%s, LLC=%d, "
|
||||
vty_out(vty, "MS TLLI=%08x, TA=%d, CS-UL=%s, CS-DL=%s, LLC=%zd, "
|
||||
"IMSI=%s%s",
|
||||
ms->tlli(),
|
||||
ms->ta(), ms->current_cs_ul().name(),
|
||||
|
@ -136,9 +154,9 @@ static int show_ms(struct vty *vty, GprsMs *ms)
|
|||
if (slots & (1 << i))
|
||||
vty_out(vty, "%d ", i);
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
vty_out(vty, " LLC queue length: %d%s", ms->llc_queue()->size(),
|
||||
vty_out(vty, " LLC queue length: %zd%s", ms->llc_queue()->size(),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " LLC queue octets: %d%s", ms->llc_queue()->octets(),
|
||||
vty_out(vty, " LLC queue octets: %zd%s", ms->llc_queue()->octets(),
|
||||
VTY_NEWLINE);
|
||||
if (ms->l1_meas()->have_rssi)
|
||||
vty_out(vty, " RSSI: %d dBm%s",
|
||||
|
|
135
src/rlc.cpp
135
src/rlc.cpp
|
@ -32,6 +32,10 @@ uint8_t *gprs_rlc_data::prepare(size_t block_data_len)
|
|||
/* todo.. only set it once if it turns out to be a bottleneck */
|
||||
memset(block, 0x0, sizeof(block));
|
||||
memset(block, 0x2b, block_data_len);
|
||||
m_ctr_num_retx = 0;
|
||||
|
||||
/* Initial value of puncturing scheme */
|
||||
next_ps = EGPRS_PS_1;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
@ -102,7 +106,7 @@ void gprs_rlc_dl_window::update(BTS *bts, const struct bitvec *rbb,
|
|||
uint16_t first_bsn, uint16_t *lost,
|
||||
uint16_t *received)
|
||||
{
|
||||
unsigned num_blocks = rbb->cur_bit;
|
||||
unsigned num_blocks = rbb->cur_bit > distance() ? distance() : rbb->cur_bit;
|
||||
unsigned bsn;
|
||||
|
||||
/* first_bsn is in range V(A)..V(S) */
|
||||
|
@ -224,7 +228,7 @@ void gprs_rlc_ul_window::update_rbb(char *rbb)
|
|||
{
|
||||
int i;
|
||||
for (i=0; i < ws(); i++) {
|
||||
if (m_v_n.is_received(ssn()-1-i))
|
||||
if (m_v_n.is_received((ssn()-1-i) & mod_sns()))
|
||||
rbb[ws()-1-i] = 'R';
|
||||
else
|
||||
rbb[ws()-1-i] = 'I';
|
||||
|
@ -282,7 +286,8 @@ bool gprs_rlc_ul_window::invalidate_bsn(const uint16_t bsn)
|
|||
}
|
||||
|
||||
static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc,
|
||||
GprsCodingScheme cs, bool with_padding, unsigned int header_bits)
|
||||
GprsCodingScheme cs, bool with_padding, unsigned int header_bits,
|
||||
unsigned int spb = 0)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int padding_bits = with_padding ? cs.optionalPaddingBits() : 0;
|
||||
|
@ -297,7 +302,7 @@ static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc,
|
|||
|
||||
for (i = 0; i < rlc->num_data_blocks; i++) {
|
||||
gprs_rlc_data_block_info_init(&rlc->block_info[i], cs,
|
||||
with_padding);
|
||||
with_padding, spb);
|
||||
|
||||
rlc->data_offs_bits[i] =
|
||||
header_bits + padding_bits +
|
||||
|
@ -307,10 +312,10 @@ static void gprs_rlc_data_header_init(struct gprs_rlc_data_info *rlc,
|
|||
}
|
||||
|
||||
void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc,
|
||||
GprsCodingScheme cs, bool with_padding)
|
||||
GprsCodingScheme cs, bool with_padding, unsigned int spb)
|
||||
{
|
||||
return gprs_rlc_data_header_init(rlc, cs, with_padding,
|
||||
cs.numDataHeaderBitsDL());
|
||||
cs.numDataHeaderBitsDL(), spb);
|
||||
}
|
||||
|
||||
void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc,
|
||||
|
@ -321,7 +326,7 @@ void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc,
|
|||
}
|
||||
|
||||
void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi,
|
||||
GprsCodingScheme cs, bool with_padding)
|
||||
GprsCodingScheme cs, bool with_padding, unsigned int spb)
|
||||
{
|
||||
unsigned int data_len = cs.maxDataBlockBytes();
|
||||
if (with_padding)
|
||||
|
@ -333,24 +338,35 @@ void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi,
|
|||
rdbi->e = 1;
|
||||
rdbi->cv = 15;
|
||||
rdbi->pi = 0;
|
||||
rdbi->spb = 0;
|
||||
rdbi->spb = spb;
|
||||
}
|
||||
|
||||
unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, int punct, int punct2,
|
||||
int with_padding)
|
||||
unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs,
|
||||
enum egprs_puncturing_values punct,
|
||||
enum egprs_puncturing_values punct2, int with_padding)
|
||||
{
|
||||
switch (GprsCodingScheme::Scheme(cs)) {
|
||||
case GprsCodingScheme::MCS1: return 0b1011 + punct % 2;
|
||||
case GprsCodingScheme::MCS2: return 0b1001 + punct % 2;
|
||||
case GprsCodingScheme::MCS1: return 0b1011 +
|
||||
punct % EGPRS_MAX_PS_NUM_2;
|
||||
case GprsCodingScheme::MCS2: return 0b1001 +
|
||||
punct % EGPRS_MAX_PS_NUM_2;
|
||||
case GprsCodingScheme::MCS3: return (with_padding ? 0b0110 : 0b0011) +
|
||||
punct % 3;
|
||||
case GprsCodingScheme::MCS4: return 0b0000 + punct % 3;
|
||||
case GprsCodingScheme::MCS5: return 0b100 + punct % 2;
|
||||
punct % EGPRS_MAX_PS_NUM_3;
|
||||
case GprsCodingScheme::MCS4: return 0b0000 +
|
||||
punct % EGPRS_MAX_PS_NUM_3;
|
||||
case GprsCodingScheme::MCS5: return 0b100 +
|
||||
punct % EGPRS_MAX_PS_NUM_2;
|
||||
case GprsCodingScheme::MCS6: return (with_padding ? 0b010 : 0b000) +
|
||||
punct % 2;
|
||||
case GprsCodingScheme::MCS7: return 0b10100 + 3 * (punct % 3) + punct2 % 3;
|
||||
case GprsCodingScheme::MCS8: return 0b01011 + 3 * (punct % 3) + punct2 % 3;
|
||||
case GprsCodingScheme::MCS9: return 0b00000 + 4 * (punct % 3) + punct2 % 3;
|
||||
punct % EGPRS_MAX_PS_NUM_2;
|
||||
case GprsCodingScheme::MCS7: return 0b10100 +
|
||||
3 * (punct % EGPRS_MAX_PS_NUM_3) +
|
||||
punct2 % EGPRS_MAX_PS_NUM_3;
|
||||
case GprsCodingScheme::MCS8: return 0b01011 +
|
||||
3 * (punct % EGPRS_MAX_PS_NUM_3) +
|
||||
punct2 % EGPRS_MAX_PS_NUM_3;
|
||||
case GprsCodingScheme::MCS9: return 0b00000 +
|
||||
4 * (punct % EGPRS_MAX_PS_NUM_3) +
|
||||
punct2 % EGPRS_MAX_PS_NUM_3;
|
||||
default: ;
|
||||
}
|
||||
|
||||
|
@ -385,3 +401,84 @@ void gprs_rlc_mcs_cps_decode(unsigned int cps,
|
|||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the PS value for retransmission with MCS change,
|
||||
* retransmission with no MCS change, fresh transmission cases.
|
||||
* The return value shall be used for current transmission only
|
||||
* 44.060 9.3.2.1 defines the PS selection for MCS change case
|
||||
* cs_current is the output of MCS selection algorithm for retx
|
||||
* cs is coding scheme of previous transmission of RLC data block
|
||||
*/
|
||||
enum egprs_puncturing_values gprs_get_punct_scheme(
|
||||
enum egprs_puncturing_values punct,
|
||||
const GprsCodingScheme &cs,
|
||||
const GprsCodingScheme &cs_current,
|
||||
unsigned int spb)
|
||||
{
|
||||
/* If it is second segment of the split block
|
||||
* dont change the puncturing scheme
|
||||
*/
|
||||
if (spb == 3)
|
||||
return punct;
|
||||
|
||||
/* TS 44.060 9.3.2.1.1 */
|
||||
if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS9) &&
|
||||
(GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS6)) {
|
||||
if ((punct == EGPRS_PS_1) || (punct == EGPRS_PS_3))
|
||||
return EGPRS_PS_1;
|
||||
else if (punct == EGPRS_PS_2)
|
||||
return EGPRS_PS_2;
|
||||
} else if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6) &&
|
||||
(GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS9)) {
|
||||
if (punct == EGPRS_PS_1)
|
||||
return EGPRS_PS_3;
|
||||
else if (punct == EGPRS_PS_2)
|
||||
return EGPRS_PS_2;
|
||||
} else if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS7) &&
|
||||
(GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS5))
|
||||
return EGPRS_PS_1;
|
||||
else if ((GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS5) &&
|
||||
(GprsCodingScheme::Scheme(cs_current) == GprsCodingScheme::MCS7))
|
||||
return EGPRS_PS_2;
|
||||
else if (cs != cs_current)
|
||||
return EGPRS_PS_1;
|
||||
/* TS 44.060 9.3.2.1.1 ends here */
|
||||
/*
|
||||
* Below else will handle fresh transmission, retransmission with no
|
||||
* MCS change case
|
||||
*/
|
||||
else
|
||||
return punct;
|
||||
return EGPRS_PS_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function calculates puncturing scheme for retransmission of a RLC
|
||||
* block with same MCS. The computed value shall be used for next transmission
|
||||
* of the same RLC block
|
||||
* TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1
|
||||
*/
|
||||
void gprs_update_punct_scheme(enum egprs_puncturing_values *punct,
|
||||
const GprsCodingScheme &cs)
|
||||
{
|
||||
switch (GprsCodingScheme::Scheme(cs)) {
|
||||
case GprsCodingScheme::MCS1 :
|
||||
case GprsCodingScheme::MCS2 :
|
||||
case GprsCodingScheme::MCS5 :
|
||||
case GprsCodingScheme::MCS6 :
|
||||
*punct = ((enum egprs_puncturing_values)((*punct + 1) %
|
||||
EGPRS_MAX_PS_NUM_2));
|
||||
break;
|
||||
case GprsCodingScheme::MCS3 :
|
||||
case GprsCodingScheme::MCS4 :
|
||||
case GprsCodingScheme::MCS7 :
|
||||
case GprsCodingScheme::MCS8 :
|
||||
case GprsCodingScheme::MCS9 :
|
||||
*punct = ((enum egprs_puncturing_values)((*punct + 1) %
|
||||
EGPRS_MAX_PS_NUM_3));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
117
src/rlc.h
117
src/rlc.h
|
@ -27,7 +27,6 @@
|
|||
|
||||
#define RLC_GPRS_SNS 128 /* GPRS, must be power of 2 */
|
||||
#define RLC_GPRS_WS 64 /* max window size */
|
||||
#define RLC_EGPRS_SNS 2048 /* EGPRS, must be power of 2 */
|
||||
#define RLC_EGPRS_MIN_WS 64 /* min window size */
|
||||
#define RLC_EGPRS_MAX_WS 1024 /* min window size */
|
||||
#define RLC_EGPRS_SNS 2048 /* EGPRS, must be power of 2 */
|
||||
|
@ -56,6 +55,43 @@ enum gprs_rlc_dl_bsn_state {
|
|||
GPRS_RLC_DL_BSN_MAX,
|
||||
};
|
||||
|
||||
/* EDGE resegment status information for UL */
|
||||
enum egprs_rlc_ul_reseg_bsn_state {
|
||||
EGPRS_RESEG_DEFAULT = 0,
|
||||
EGPRS_RESEG_FIRST_SEG_RXD = 0x01,
|
||||
EGPRS_RESEG_SECOND_SEG_RXD = 0x02,
|
||||
EGPRS_RESEG_INVALID
|
||||
};
|
||||
|
||||
/* EDGE resegment status information for DL */
|
||||
enum egprs_rlc_dl_reseg_bsn_state {
|
||||
EGPRS_RESEG_DL_DEFAULT = 0,
|
||||
EGPRS_RESEG_FIRST_SEG_SENT = 0x01,
|
||||
EGPRS_RESEG_SECOND_SEG_SENT = 0x02,
|
||||
EGPRS_RESEG_DL_STATE_INVALID
|
||||
};
|
||||
|
||||
/*
|
||||
* Valid puncturing scheme values
|
||||
* TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1
|
||||
*/
|
||||
enum egprs_puncturing_values {
|
||||
EGPRS_PS_1,
|
||||
EGPRS_PS_2,
|
||||
EGPRS_PS_3,
|
||||
EGPRS_PS_INVALID,
|
||||
};
|
||||
|
||||
/*
|
||||
* EGPRS_MAX_PS_NUM_2 is valid for MCS 1,2,5,6.
|
||||
* And EGPRS_MAX_PS_NUM_3 is valid for MCS 3,4,7,8,9
|
||||
* TS 44.060 10.4.8a.3.1, 10.4.8a.2.1, 10.4.8a.1.1
|
||||
*/
|
||||
enum egprs_puncturing_types {
|
||||
EGPRS_MAX_PS_NUM_2 = 2,
|
||||
EGPRS_MAX_PS_NUM_3,
|
||||
EGPRS_MAX_PS_NUM_INVALID,
|
||||
};
|
||||
|
||||
static inline uint16_t mod_sns_half()
|
||||
{
|
||||
|
@ -99,20 +135,51 @@ struct gprs_rlc_data {
|
|||
uint8_t len;
|
||||
|
||||
struct gprs_rlc_data_block_info block_info;
|
||||
/*
|
||||
* cs_current_trans is variable to hold the cs value for
|
||||
* current transmission. cs_current_trans is same as cs during
|
||||
* transmission case. during retransmission cs_current_trans is
|
||||
* fetched from egprs_mcs_retx_tbl table based on
|
||||
* cs and demanded cs.reference is 44.060 Table
|
||||
* 8.1.1.1 and Table 8.1.1.2
|
||||
*/
|
||||
GprsCodingScheme cs_current_trans;
|
||||
GprsCodingScheme cs;
|
||||
|
||||
/*
|
||||
* The MCS of initial transmission
|
||||
* This variable is used for split block
|
||||
* processing in DL
|
||||
*/
|
||||
GprsCodingScheme cs_init;
|
||||
|
||||
/* puncturing scheme value to be used for next transmission*/
|
||||
enum egprs_puncturing_values next_ps;
|
||||
|
||||
/* holds the current status of the block w.r.t UL split blocks*/
|
||||
egprs_rlc_ul_reseg_bsn_state block_status_ul;
|
||||
|
||||
/* Holds the current status of the block w.r.t DL split blocks*/
|
||||
egprs_rlc_dl_reseg_bsn_state block_status_dl;
|
||||
uint32_t m_ctr_num_retx;
|
||||
};
|
||||
|
||||
void gprs_rlc_data_info_init_dl(struct gprs_rlc_data_info *rlc,
|
||||
GprsCodingScheme cs, bool with_padding);
|
||||
GprsCodingScheme cs, bool with_padding, unsigned int spb = 0);
|
||||
void gprs_rlc_data_info_init_ul(struct gprs_rlc_data_info *rlc,
|
||||
GprsCodingScheme cs, bool with_padding);
|
||||
void gprs_rlc_data_block_info_init(struct gprs_rlc_data_block_info *rdbi,
|
||||
GprsCodingScheme cs, bool with_padding);
|
||||
unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, int punct, int punct2,
|
||||
int with_padding);
|
||||
GprsCodingScheme cs, bool with_padding, unsigned int spb = 0);
|
||||
unsigned int gprs_rlc_mcs_cps(GprsCodingScheme cs, enum egprs_puncturing_values
|
||||
punct, enum egprs_puncturing_values punct2, int with_padding);
|
||||
void gprs_rlc_mcs_cps_decode(unsigned int cps, GprsCodingScheme cs,
|
||||
int *punct, int *punct2, int *with_padding);
|
||||
|
||||
enum egprs_puncturing_values gprs_get_punct_scheme(enum egprs_puncturing_values
|
||||
punct, const GprsCodingScheme &cs,
|
||||
const GprsCodingScheme &cs_current_trans,
|
||||
unsigned int spb);
|
||||
void gprs_update_punct_scheme(enum egprs_puncturing_values *punct,
|
||||
const GprsCodingScheme &cs);
|
||||
/*
|
||||
* I hold the currently transferred blocks and will provide
|
||||
* the routines to manipulate these arrays.
|
||||
|
@ -288,6 +355,44 @@ struct rlc_li_field_egprs {
|
|||
li:7;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* TS 44.060 10.3a.4.1.1 */
|
||||
struct gprs_rlc_ul_header_egprs_1 {
|
||||
uint8_t r:1,
|
||||
si:1,
|
||||
cv:4,
|
||||
tfi_a:2;
|
||||
uint8_t tfi_b:3,
|
||||
bsn1_a:5;
|
||||
uint8_t bsn1_b:6,
|
||||
bsn2_a:2;
|
||||
uint8_t bsn2_b;
|
||||
uint8_t cps:5,
|
||||
rsb:1,
|
||||
pi:1,
|
||||
spare_a:1;
|
||||
uint8_t spare_b:6,
|
||||
dummy:2;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* TS 44.060 10.3a.4.2.1 */
|
||||
struct gprs_rlc_ul_header_egprs_2 {
|
||||
uint8_t r:1,
|
||||
si:1,
|
||||
cv:4,
|
||||
tfi_a:2;
|
||||
uint8_t tfi_b:3,
|
||||
bsn1_a:5;
|
||||
uint8_t bsn1_b:6,
|
||||
cps_a:2;
|
||||
uint8_t cps_b:1,
|
||||
rsb:1,
|
||||
pi:1,
|
||||
spare_a:5;
|
||||
uint8_t spare_b:5,
|
||||
dummy:3;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* TS 44.060 10.3a.4.3.1 */
|
||||
struct gprs_rlc_ul_header_egprs_3 {
|
||||
uint8_t r:1,
|
||||
si:1,
|
||||
|
|
56
src/tbf.cpp
56
src/tbf.cpp
|
@ -42,6 +42,10 @@ extern void *tall_pcu_ctx;
|
|||
|
||||
static void tbf_timer_cb(void *_tbf);
|
||||
|
||||
extern char log_xx[8000][500];
|
||||
extern uint32_t log_ptr;
|
||||
extern bool error_hit;
|
||||
|
||||
gprs_rlcmac_tbf::Meas::Meas() :
|
||||
rssi_sum(0),
|
||||
rssi_num(0)
|
||||
|
@ -86,7 +90,7 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(BTS *bts_, gprs_rlcmac_tbf_direction dir) :
|
|||
memset(&timer, 0, sizeof(timer));
|
||||
memset(&m_rlc, 0, sizeof(m_rlc));
|
||||
memset(&gsm_timer, 0, sizeof(gsm_timer));
|
||||
|
||||
memset(&m_ctr_num_blocks, 0, 9 * sizeof(uint32_t));
|
||||
m_llc.init();
|
||||
|
||||
m_name_buf[0] = '\0';
|
||||
|
@ -375,6 +379,24 @@ int gprs_rlcmac_tbf::update()
|
|||
return -rc;
|
||||
}
|
||||
|
||||
/* Only for DL direction. update the window size*/
|
||||
if (is_egprs_enabled()) {
|
||||
unsigned int num_pdch = pcu_bitcount(dl_slots());
|
||||
unsigned int ws = bts->bts_data()->ws_base + num_pdch * bts->bts_data()->ws_pdch;
|
||||
ws = (ws / 32) * 32;
|
||||
ws = OSMO_MAX(64, ws);
|
||||
if (num_pdch == 1)
|
||||
ws = OSMO_MIN(192, ws);
|
||||
else
|
||||
ws = OSMO_MIN(128 * num_pdch, ws);
|
||||
|
||||
LOGP(DRLCMAC, LOGL_INFO, "%s: Setting EGPRS window size to\
|
||||
%d num_pdch(%d) ws_base(%d) ws_pdch(%d)\n",
|
||||
name(), ws, num_pdch, bts->bts_data()->ws_base,
|
||||
bts->bts_data()->ws_pdch);
|
||||
|
||||
window()->set_ws(ws);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -473,6 +495,11 @@ void gprs_rlcmac_tbf::set_polling(uint32_t new_poll_fn, uint8_t ts)
|
|||
"%s: Scheduling polling at FN %d TS %d\n",
|
||||
name(), new_poll_fn, ts);
|
||||
|
||||
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this);
|
||||
#if 0
|
||||
sprintf(log_xx[log_ptr++ % 8000],"%s: Sc poll FN %d TS %d cur_fn(%d) va(%d) vs(%d)\n",
|
||||
name(), new_poll_fn, ts, bts->current_frame_number(), dl_tbf->m_window.v_a(), dl_tbf->m_window.v_s() );
|
||||
#endif
|
||||
/* schedule polling */
|
||||
poll_state = GPRS_RLCMAC_POLL_SCHED;
|
||||
poll_fn = new_poll_fn;
|
||||
|
@ -481,6 +508,9 @@ void gprs_rlcmac_tbf::set_polling(uint32_t new_poll_fn, uint8_t ts)
|
|||
|
||||
void gprs_rlcmac_tbf::poll_timeout()
|
||||
{
|
||||
sprintf(log_xx[log_ptr++ % 8000],"%s poll timeout for FN=%d, TS=%d (curr FN %d)\n",
|
||||
tbf_name(this), poll_fn, poll_ts, bts->current_frame_number());
|
||||
|
||||
LOGP(DRLCMAC, LOGL_NOTICE, "%s poll timeout for FN=%d, TS=%d (curr FN %d)\n",
|
||||
tbf_name(this), poll_fn, poll_ts, bts->current_frame_number());
|
||||
|
||||
|
@ -522,6 +552,7 @@ void gprs_rlcmac_tbf::poll_timeout()
|
|||
bts->rlc_ass_timedout();
|
||||
if (n3105 == bts_data()->n3105) {
|
||||
LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n");
|
||||
sprintf(log_xx[log_ptr++ % 8000],"- N3105 exceeded 1 n3105(%d) cfg_n3105(%d) \n", n3105, bts_data()->n3105);
|
||||
set_state(GPRS_RLCMAC_RELEASING);
|
||||
tbf_timer_start(this, 3195, bts_data()->t3195, 0);
|
||||
bts->rlc_ass_failed();
|
||||
|
@ -541,6 +572,9 @@ void gprs_rlcmac_tbf::poll_timeout()
|
|||
n3105++;
|
||||
bts->rlc_ass_timedout();
|
||||
if (n3105 == bts->bts_data()->n3105) {
|
||||
#if 1
|
||||
sprintf(log_xx[log_ptr++ % 8000],"- N3105 exceeded 2 n3105(%d) cfg_n3105(%d)\n", n3105, bts_data()->n3105);
|
||||
#endif
|
||||
LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n");
|
||||
set_state(GPRS_RLCMAC_RELEASING);
|
||||
tbf_timer_start(this, 3195, bts_data()->t3195, 0);
|
||||
|
@ -553,6 +587,12 @@ void gprs_rlcmac_tbf::poll_timeout()
|
|||
gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this);
|
||||
|
||||
if (!(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) {
|
||||
#if 1
|
||||
sprintf(log_xx[log_ptr++ % 8000],"- Timeout for polling %s "
|
||||
"PACKET DOWNLINK ACK. FN(%d) TS(%d) CURRENT_FN(%d) n3105(%d) cfgd_n3105(%d) va(%d) vs(%d)\n",
|
||||
tbf_name(this),poll_fn, poll_ts, bts->current_frame_number(), dl_tbf->n3105, dl_tbf->bts->bts_data()->n3105, dl_tbf->m_window.v_a(), dl_tbf->m_window.v_s());
|
||||
#endif
|
||||
|
||||
LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling "
|
||||
"PACKET DOWNLINK ACK.\n");
|
||||
dl_tbf->rlcmac_diag();
|
||||
|
@ -564,6 +604,9 @@ void gprs_rlcmac_tbf::poll_timeout()
|
|||
else
|
||||
bts->rlc_ack_timedout();
|
||||
if (dl_tbf->n3105 == dl_tbf->bts->bts_data()->n3105) {
|
||||
#if 1
|
||||
sprintf(log_xx[log_ptr++ % 8000],"- N3105 exceeded 3 n3105(%d) cfg_n3105(%d)\n", dl_tbf->n3105, dl_tbf->bts->bts_data()->n3105);
|
||||
#endif
|
||||
LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n");
|
||||
dl_tbf->set_state(GPRS_RLCMAC_RELEASING);
|
||||
tbf_timer_start(dl_tbf, 3195, dl_tbf->bts_data()->t3195, 0);
|
||||
|
@ -710,7 +753,9 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
|
|||
gprs_rlcmac_dl_tbf::BandWidth::BandWidth() :
|
||||
dl_bw_octets(0),
|
||||
dl_loss_lost(0),
|
||||
dl_loss_received(0)
|
||||
dl_loss_received(0),
|
||||
total_dl_loss_lost(0),
|
||||
total_dl_loss_received(0)
|
||||
{
|
||||
timerclear(&dl_bw_tv);
|
||||
timerclear(&dl_loss_tv);
|
||||
|
@ -1148,10 +1193,17 @@ int gprs_rlcmac_tbf::set_tlli_from_ul(uint32_t new_tlli)
|
|||
}
|
||||
|
||||
if (dl_tbf && dl_tbf->ms() != ms()) {
|
||||
uint32_t log_ptrx = log_ptr;
|
||||
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
|
||||
"TLLI=0x%08x while %s still exists. "
|
||||
"Killing pending DL TBF\n", tlli(),
|
||||
tbf_name(dl_tbf));
|
||||
sprintf(log_xx[log_ptr++ % 8000], "Got RACH from "
|
||||
"TLLI=0x%08x while %s still exists. "
|
||||
"Killing pending DL TBF llc_size(%d) llc_octets(%d) log_ptr(%d)\n", tlli(),
|
||||
tbf_name(dl_tbf), dl_tbf->llc_queue()->size(), dl_tbf->llc_queue()->octets(), log_ptr);
|
||||
error_hit = true;
|
||||
|
||||
tbf_free(dl_tbf);
|
||||
dl_tbf = NULL;
|
||||
}
|
||||
|
|
20
src/tbf.h
20
src/tbf.h
|
@ -224,6 +224,8 @@ struct gprs_rlcmac_tbf {
|
|||
*/
|
||||
uint8_t m_tfi;
|
||||
time_t m_created_ts;
|
||||
uint32_t m_ctr_num_blocks[9];
|
||||
uint32_t m_ctr_retx[3];
|
||||
|
||||
protected:
|
||||
gprs_rlcmac_bts *bts_data() const;
|
||||
|
@ -395,6 +397,9 @@ struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf {
|
|||
uint16_t dl_loss_lost; /* sum of lost packets */
|
||||
uint16_t dl_loss_received; /* sum of received packets */
|
||||
|
||||
uint32_t total_dl_loss_lost; /* total of lost packets */
|
||||
uint32_t total_dl_loss_received; /* total of received packets */
|
||||
|
||||
BandWidth();
|
||||
} m_bw;
|
||||
|
||||
|
@ -420,6 +425,9 @@ protected:
|
|||
void start_llc_timer();
|
||||
int analyse_errors(char *show_rbb, uint8_t ssn, ana_result *res);
|
||||
void schedule_next_frame();
|
||||
void egprs_dl_spb_status_get_data_buffer(int bsn, uint8_t **block_data);
|
||||
unsigned int get_egprs_dl_spb_status(int bsn);
|
||||
unsigned int get_egprs_dl_spb_value(int bsn);
|
||||
|
||||
struct osmo_timer_list m_llc_timer;
|
||||
};
|
||||
|
@ -439,6 +447,18 @@ struct gprs_rlcmac_ul_tbf : public gprs_rlcmac_tbf {
|
|||
int assemble_forward_llc(const gprs_rlc_data *data);
|
||||
int snd_ul_ud();
|
||||
|
||||
egprs_rlc_ul_reseg_bsn_state handle_egprs_ul_spb(
|
||||
const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block,
|
||||
uint8_t *data, const uint8_t block_idx);
|
||||
|
||||
egprs_rlc_ul_reseg_bsn_state handle_egprs_ul_first_seg(
|
||||
const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block,
|
||||
uint8_t *data, const uint8_t block_idx);
|
||||
|
||||
egprs_rlc_ul_reseg_bsn_state handle_egprs_ul_second_seg(
|
||||
const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block,
|
||||
uint8_t *data, const uint8_t block_idx);
|
||||
|
||||
/* Please note that all variables here will be reset when changing
|
||||
* from WAIT RELEASE back to FLOW state (re-use of TBF).
|
||||
* All states that need reset must be in this struct, so this is why
|
||||
|
|
263
src/tbf_dl.cpp
263
src/tbf_dl.cpp
|
@ -34,6 +34,7 @@
|
|||
extern "C" {
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/gprs/gprs_bssgp_bss.h>
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -42,12 +43,11 @@ extern "C" {
|
|||
|
||||
/* After sending these frames, we poll for ack/nack. */
|
||||
#define POLL_ACK_AFTER_FRAMES 20
|
||||
|
||||
extern "C" {
|
||||
int bssgp_tx_llc_discarded(struct bssgp_bvc_ctx *bctx, uint32_t tlli,
|
||||
uint8_t num_frames, uint32_t num_octets);
|
||||
}
|
||||
|
||||
extern char log_xx[8000][500];
|
||||
extern uint32_t log_ptr;
|
||||
bool error_hit = false;
|
||||
int error_cnt = 0;
|
||||
int alive_cnt = 0;
|
||||
static inline void tbf_update_ms_class(struct gprs_rlcmac_tbf *tbf,
|
||||
const uint8_t ms_class)
|
||||
{
|
||||
|
@ -361,11 +361,28 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
|
|||
int data_len2, force_data_len = -1;
|
||||
GprsCodingScheme cs2;
|
||||
GprsCodingScheme force_cs;
|
||||
int xx = 0;
|
||||
|
||||
bsn = m_window.resend_needed();
|
||||
|
||||
if (error_hit == true)
|
||||
error_cnt++;
|
||||
|
||||
if (alive_cnt++ % 30000 == 0 )
|
||||
LOGP(DRLCMAC, LOGL_ERROR, "dl Alive fn(%d) current_fn(%d)\n", fn,bts->current_frame_number());
|
||||
|
||||
if (error_cnt >= 100) {
|
||||
LOGP(DRLCMAC, LOGL_ERROR, "log_ptr(%d)", log_ptr);
|
||||
#if 0
|
||||
for(xx = 0; xx < 8000; xx++)
|
||||
LOGP(DRLCMAC, LOGL_ERROR, log_xx[xx]);
|
||||
#endif
|
||||
error_cnt = 0;
|
||||
log_ptr = 0;
|
||||
error_hit = false;
|
||||
}
|
||||
if (previous_bsn >= 0) {
|
||||
force_cs = m_rlc.block(previous_bsn)->cs;
|
||||
force_cs = m_rlc.block(previous_bsn)->cs_current_trans;
|
||||
if (!force_cs.isEgprs())
|
||||
return -1;
|
||||
force_data_len = m_rlc.block(previous_bsn)->len;
|
||||
|
@ -379,7 +396,30 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
|
|||
m_window.mod_sns(bsn - previous_bsn) > RLC_EGPRS_MAX_BSN_DELTA)
|
||||
return -1;
|
||||
|
||||
cs2 = m_rlc.block(bsn)->cs;
|
||||
if (is_egprs_enabled()) {
|
||||
m_rlc.block(bsn)->cs_current_trans =
|
||||
GprsCodingScheme::get_retx_mcs(
|
||||
m_rlc.block(bsn)->cs, ms()->current_cs_dl(),
|
||||
bts->bts_data()->arq_type);
|
||||
|
||||
/* TODO: Need to remove this check when MCS-8 -> MCS-6
|
||||
* transistion is handled
|
||||
*/
|
||||
if (m_rlc.block(bsn)->cs == GprsCodingScheme::MCS8)
|
||||
m_rlc.block(bsn)->cs_current_trans =
|
||||
GprsCodingScheme::MCS8;
|
||||
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG,
|
||||
"- current_cs_dl(%d) demanded_mcs(%d)"
|
||||
"cs_trans(%d) arq_type(%d) bsn(%d)\n",
|
||||
m_rlc.block(bsn)->cs.to_num(),
|
||||
ms()->current_cs_dl().to_num(),
|
||||
m_rlc.block(bsn)->cs_current_trans.to_num(),
|
||||
bts->bts_data()->arq_type, bsn);
|
||||
} else
|
||||
m_rlc.block(bsn)->cs_current_trans =
|
||||
m_rlc.block(bsn)->cs;
|
||||
|
||||
data_len2 = m_rlc.block(bsn)->len;
|
||||
if (force_data_len > 0 && force_data_len != data_len2)
|
||||
return -1;
|
||||
|
@ -422,7 +462,7 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
|
|||
"- Sending new dummy block at BSN %d, CS=%s\n",
|
||||
m_window.v_s(), current_cs().name());
|
||||
bsn = create_new_bsn(fn, current_cs());
|
||||
/* Don't send a second block, so don't set cs2 */
|
||||
/* Don't send a second block, so don't set cs_current_trans*/
|
||||
}
|
||||
|
||||
if (bsn < 0) {
|
||||
|
@ -433,7 +473,7 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
|
|||
bts->rlc_resent();
|
||||
}
|
||||
|
||||
*may_combine = cs2.numDataBlocks() > 1;
|
||||
*may_combine = m_rlc.block(bsn)->cs_current_trans.numDataBlocks() > 1;
|
||||
|
||||
return bsn;
|
||||
}
|
||||
|
@ -505,6 +545,9 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, GprsCodingScheme cs)
|
|||
rlc_data = m_rlc.block(bsn);
|
||||
data = rlc_data->prepare(block_data_len);
|
||||
rlc_data->cs = cs;
|
||||
rlc_data->cs_current_trans = cs;
|
||||
rlc_data->block_status_dl = EGPRS_RESEG_DL_DEFAULT;
|
||||
rlc_data->cs_init = cs;
|
||||
rlc_data->len = block_data_len;
|
||||
|
||||
rdbi = &(rlc_data->block_info);
|
||||
|
@ -550,6 +593,7 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, GprsCodingScheme cs)
|
|||
LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for %s"
|
||||
"len=%d\n", tbf_name(this), m_llc.frame_length());
|
||||
gprs_rlcmac_dl_bw(this, m_llc.frame_length());
|
||||
bts->llc_dl_bytes(m_llc.frame_length());
|
||||
m_llc.reset();
|
||||
|
||||
if (is_final) {
|
||||
|
@ -589,8 +633,9 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(
|
|||
GprsCodingScheme cs;
|
||||
int bsns[ARRAY_SIZE(rlc.block_info)];
|
||||
unsigned num_bsns;
|
||||
int punct[ARRAY_SIZE(rlc.block_info)];
|
||||
enum egprs_puncturing_values punct[ARRAY_SIZE(rlc.block_info)];
|
||||
bool need_padding = false;
|
||||
unsigned int spb = 0;
|
||||
|
||||
/*
|
||||
* TODO: This is an experimental work-around to put 2 BSN into
|
||||
|
@ -600,7 +645,8 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(
|
|||
* be put into the data area, even if the resulting CS is higher than
|
||||
* the current limit.
|
||||
*/
|
||||
cs = m_rlc.block(index)->cs;
|
||||
cs = m_rlc.block(index)->cs_current_trans;
|
||||
GprsCodingScheme &cs_init = m_rlc.block(index)->cs_init;
|
||||
bsns[0] = index;
|
||||
num_bsns = 1;
|
||||
|
||||
|
@ -609,14 +655,32 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(
|
|||
num_bsns += 1;
|
||||
}
|
||||
|
||||
if (num_bsns == 1) {
|
||||
if ((GprsCodingScheme::Scheme(cs_init) == GprsCodingScheme::MCS8) &&
|
||||
(GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS6 ||
|
||||
GprsCodingScheme::Scheme(cs) == GprsCodingScheme::MCS3)) {
|
||||
if ((get_egprs_dl_spb_status(index) ==
|
||||
EGPRS_RESEG_DL_DEFAULT) ||
|
||||
(get_egprs_dl_spb_status(index) ==
|
||||
EGPRS_RESEG_SECOND_SEG_SENT))
|
||||
need_padding = true;
|
||||
} else if (num_bsns == 1) {
|
||||
/* TODO: remove the conditional when MCS-6 padding isn't
|
||||
* failing to be decoded by MEs anymore */
|
||||
/* TODO: support of MCS-8 -> MCS-6 transition should be
|
||||
* handled
|
||||
*/
|
||||
if (cs != GprsCodingScheme(GprsCodingScheme::MCS8))
|
||||
cs.decToSingleBlock(&need_padding);
|
||||
}
|
||||
|
||||
gprs_rlc_data_info_init_dl(&rlc, cs, need_padding);
|
||||
spb = get_egprs_dl_spb_value(index);
|
||||
|
||||
LOGP(DRLCMACDL, LOGL_DEBUG, "- need_padding %d spb_status %d spb %d"
|
||||
"(BSN1 %d BSN2 %d)\n",
|
||||
need_padding,
|
||||
get_egprs_dl_spb_status(index), spb, index, index2);
|
||||
|
||||
gprs_rlc_data_info_init_dl(&rlc, cs, need_padding, spb);
|
||||
|
||||
rlc.usf = 7; /* will be set at scheduler */
|
||||
rlc.pr = 0; /* FIXME: power reduction */
|
||||
|
@ -635,7 +699,6 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(
|
|||
data_block_idx++)
|
||||
{
|
||||
int bsn;
|
||||
GprsCodingScheme cs_enc;
|
||||
uint8_t *block_data;
|
||||
gprs_rlc_data_block_info *rdbi, *block_info;
|
||||
|
||||
|
@ -645,25 +708,38 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(
|
|||
else
|
||||
bsn = bsns[0];
|
||||
|
||||
cs_enc = m_rlc.block(bsn)->cs;
|
||||
/* Get current puncturing scheme from block */
|
||||
m_rlc.block(bsn)->next_ps = gprs_get_punct_scheme(
|
||||
m_rlc.block(bsn)->next_ps,
|
||||
m_rlc.block(bsn)->cs, cs, spb);
|
||||
|
||||
/* get data and header from current block */
|
||||
block_data = m_rlc.block(bsn)->block;
|
||||
|
||||
/* TODO: Use real puncturing values */
|
||||
punct[data_block_idx] = data_block_idx;
|
||||
if (cs.isEgprs()) {
|
||||
OSMO_ASSERT(m_rlc.block(bsn)->next_ps >= EGPRS_PS_1);
|
||||
OSMO_ASSERT(m_rlc.block(bsn)->next_ps <= EGPRS_PS_3);
|
||||
}
|
||||
punct[data_block_idx] = m_rlc.block(bsn)->next_ps;
|
||||
|
||||
rdbi = &rlc.block_info[data_block_idx];
|
||||
block_info = &m_rlc.block(bsn)->block_info;
|
||||
|
||||
if(rdbi->data_len != m_rlc.block(bsn)->len) {
|
||||
LOGP(DRLCMACDL, LOGL_ERROR,
|
||||
"ERROR: Expected len = %d for %s instead of "
|
||||
"%d in data unit %d (BSN %d, %s)\n",
|
||||
rdbi->data_len, cs.name(), m_rlc.block(bsn)->len,
|
||||
data_block_idx, bsn, cs_enc.name());
|
||||
OSMO_ASSERT(rdbi->data_len == m_rlc.block(bsn)->len);
|
||||
}
|
||||
egprs_dl_spb_status_get_data_buffer(bsn, &block_data);
|
||||
|
||||
/* TODO: Need to handle 2 same bsns
|
||||
* in header type 1
|
||||
*/
|
||||
/*
|
||||
* If it is first segment of the split block set the state of
|
||||
* bsn to nacked. If it is the first segment dont update the
|
||||
* next ps value of bsn
|
||||
*/
|
||||
if (spb == 2)
|
||||
m_window.m_v_b.mark_nacked(bsn);
|
||||
else
|
||||
gprs_update_punct_scheme(&m_rlc.block(bsn)->next_ps,
|
||||
cs);
|
||||
|
||||
m_rlc.block(bsn)->cs = cs;
|
||||
|
||||
rdbi->e = block_info->e;
|
||||
rdbi->cv = block_info->cv;
|
||||
rdbi->bsn = bsn;
|
||||
|
@ -672,8 +748,15 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(
|
|||
LOGP(DRLCMACDL, LOGL_DEBUG, "- Copying data unit %d (BSN %d)\n",
|
||||
data_block_idx, bsn);
|
||||
|
||||
sprintf(log_xx[log_ptr++ % 8000],"-%s %s Copying data unit %d (BSN %d) framenumber(%d) current_fn %d TS(%d)\n",
|
||||
tbf_name(this),cs.name(), data_block_idx, bsn, fn, bts->current_frame_number(), ts);
|
||||
|
||||
Encoding::rlc_copy_from_aligned_buffer(&rlc, data_block_idx,
|
||||
msg_data, block_data);
|
||||
m_ctr_num_blocks[cs.to_num() - 1]++;
|
||||
m_rlc.block(bsn)->m_ctr_num_retx++;
|
||||
if(m_rlc.block(bsn)->m_ctr_num_retx > 1)
|
||||
m_ctr_retx[m_rlc.block(bsn)->m_ctr_num_retx > 3 ? 2:m_rlc.block(bsn)->m_ctr_num_retx - 2]++;
|
||||
}
|
||||
|
||||
OSMO_ASSERT(ARRAY_SIZE(punct) >= 2);
|
||||
|
@ -742,8 +825,6 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(
|
|||
/* Increment TX-counter */
|
||||
m_tx_counter++;
|
||||
|
||||
bts->rlc_sent();
|
||||
|
||||
return dl_msg;
|
||||
}
|
||||
|
||||
|
@ -763,7 +844,8 @@ int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn,
|
|||
uint16_t bsn = 0;
|
||||
unsigned received_bytes = 0, lost_bytes = 0;
|
||||
unsigned received_packets = 0, lost_packets = 0;
|
||||
unsigned num_blocks = strlen(show_rbb);
|
||||
unsigned num_blocks = strlen(show_rbb) > m_window.distance() ?
|
||||
m_window.distance() : strlen(show_rbb);
|
||||
|
||||
/* SSN - 1 is in range V(A)..V(S)-1 */
|
||||
for (unsigned int bitpos = 0; bitpos < num_blocks; bitpos++) {
|
||||
|
@ -843,7 +925,8 @@ int gprs_rlcmac_dl_tbf::update_window(unsigned first_bsn,
|
|||
char show_rbb[RLC_MAX_SNS + 1];
|
||||
int error_rate;
|
||||
struct ana_result ana_res;
|
||||
unsigned num_blocks = rbb->cur_bit;
|
||||
unsigned num_blocks = rbb->cur_bit > m_window.distance()
|
||||
? m_window.distance(): rbb->cur_bit;
|
||||
unsigned behind_last_bsn = m_window.mod_sns(first_bsn + num_blocks);
|
||||
|
||||
Decoding::extract_rbb(rbb, show_rbb);
|
||||
|
@ -865,9 +948,14 @@ int gprs_rlcmac_dl_tbf::update_window(unsigned first_bsn,
|
|||
* control ack!
|
||||
* TODO: check whether this FIXME still makes sense
|
||||
*/
|
||||
LOGP(DRLCMACDL, LOGL_NOTICE, "- ack range is out of "
|
||||
"V(A)..V(S) range %s Free TBF!\n", tbf_name(this));
|
||||
return 1; /* indicate to free TBF */
|
||||
uint32_t log_ptrx = log_ptr;
|
||||
LOGP(DRLCMAC, LOGL_ERROR, "- ack range is out of "
|
||||
"V(A) = %d ..V(S) = %d range %s Free TBF! num_blocks = %d dist = %d behind_last_bsn = %d first_bsn = %d log_ptr(%d)\n",m_window.v_a(), m_window.v_s(),
|
||||
tbf_name(this), num_blocks, dist, behind_last_bsn, first_bsn, log_ptrx);
|
||||
sprintf(log_xx[log_ptr++ % 8000],"- ack range is out of "
|
||||
"V(A) = %d ..V(S) = %d range %s Free TBF! num_blocks = %d dist = %d behind_last_bsn = %d first_bsn = %d log_ptr(%d)\n",m_window.v_a(), m_window.v_s(),
|
||||
tbf_name(this), num_blocks, dist, behind_last_bsn, first_bsn, log_ptrx);
|
||||
error_hit = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1125,3 +1213,106 @@ bool gprs_rlcmac_dl_tbf::keep_open(unsigned fn) const
|
|||
keep_time_frames = msecs_to_frames(bts_data()->dl_tbf_idle_msec);
|
||||
return frames_since_last_drain(fn) <= keep_time_frames;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the pointer to data which needs
|
||||
* to be copied. Also updates the status of the block related to
|
||||
* Split block handling in the RLC/MAC block.
|
||||
*/
|
||||
void gprs_rlcmac_dl_tbf::egprs_dl_spb_status_get_data_buffer(int bsn,
|
||||
uint8_t **block_data)
|
||||
{
|
||||
struct gprs_rlc_data *rlc_data = m_rlc.block(bsn);
|
||||
|
||||
GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans;
|
||||
GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init;
|
||||
|
||||
/*
|
||||
* Table 10.3a.0.1 of 44.060
|
||||
* MCS6,9: second segment starts at 74/2 = 37
|
||||
* MCS5,7: second segment starts at 56/2 = 28
|
||||
* MCS8: second segment starts at 31
|
||||
* MCS4: second segment starts at 44/2 = 22
|
||||
*/
|
||||
if (cs_current_trans.headerTypeData() ==
|
||||
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) {
|
||||
if (rlc_data->block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) {
|
||||
switch (GprsCodingScheme::Scheme(cs_init)) {
|
||||
case GprsCodingScheme::MCS6 :
|
||||
case GprsCodingScheme::MCS9 :
|
||||
*block_data = &rlc_data->block[37];
|
||||
break;
|
||||
case GprsCodingScheme::MCS7 :
|
||||
case GprsCodingScheme::MCS5 :
|
||||
*block_data = &rlc_data->block[28];
|
||||
break;
|
||||
case GprsCodingScheme::MCS8 :
|
||||
*block_data = &rlc_data->block[31];
|
||||
break;
|
||||
case GprsCodingScheme::MCS4 :
|
||||
*block_data = &rlc_data->block[22];
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
break;
|
||||
|
||||
}
|
||||
rlc_data->block_status_dl = EGPRS_RESEG_SECOND_SEG_SENT;
|
||||
return;
|
||||
} else if ((cs_init.headerTypeData() ==
|
||||
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) ||
|
||||
(cs_init.headerTypeData() ==
|
||||
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) {
|
||||
rlc_data->block_status_dl =
|
||||
EGPRS_RESEG_FIRST_SEG_SENT;
|
||||
} else if ((GprsCodingScheme::Scheme(cs_init) ==
|
||||
GprsCodingScheme::MCS4) &&
|
||||
(GprsCodingScheme::Scheme(cs_current_trans) ==
|
||||
GprsCodingScheme::MCS1)) {
|
||||
rlc_data->block_status_dl = EGPRS_RESEG_FIRST_SEG_SENT;
|
||||
}
|
||||
}
|
||||
*block_data = &rlc_data->block[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the status of split block
|
||||
* for RLC/MAC block.
|
||||
*/
|
||||
unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_status(int bsn)
|
||||
{
|
||||
struct gprs_rlc_data *rlc_data = m_rlc.block(bsn);
|
||||
|
||||
return rlc_data->block_status_dl;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the spb value to be sent OTA
|
||||
* for RLC/MAC block.
|
||||
*/
|
||||
unsigned int gprs_rlcmac_dl_tbf::get_egprs_dl_spb_value(int bsn)
|
||||
{
|
||||
struct gprs_rlc_data *rlc_data = m_rlc.block(bsn);
|
||||
|
||||
GprsCodingScheme &cs_current_trans = m_rlc.block(bsn)->cs_current_trans;
|
||||
GprsCodingScheme &cs_init = m_rlc.block(bsn)->cs_init;
|
||||
|
||||
/* Table 10.4.8b.1 of 44.060 */
|
||||
if (cs_current_trans.headerTypeData() ==
|
||||
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3) {
|
||||
if (rlc_data->block_status_dl == EGPRS_RESEG_FIRST_SEG_SENT) {
|
||||
return 3;
|
||||
} else if ((cs_init.headerTypeData() ==
|
||||
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) ||
|
||||
(cs_init.headerTypeData() ==
|
||||
GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2)) {
|
||||
return 2;
|
||||
} else if ((GprsCodingScheme::Scheme(cs_init) ==
|
||||
GprsCodingScheme::MCS4) &&
|
||||
(GprsCodingScheme::Scheme(cs_current_trans) ==
|
||||
GprsCodingScheme::MCS1)) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
175
src/tbf_ul.cpp
175
src/tbf_ul.cpp
|
@ -60,13 +60,15 @@ int gprs_rlcmac_ul_tbf::assemble_forward_llc(const gprs_rlc_data *_data)
|
|||
LOGP(DRLCMACUL, LOGL_DEBUG, "- Assembling frames: (len=%d)\n", len);
|
||||
|
||||
num_frames = Decoding::rlc_data_from_ul_data(
|
||||
rdbi, cs, data, &(frames[0]), sizeof(frames),
|
||||
rdbi, cs, data, &(frames[0]), ARRAY_SIZE(frames),
|
||||
&dummy_tlli);
|
||||
|
||||
/* create LLC frames */
|
||||
for (i = 0; i < num_frames; i++) {
|
||||
frame = frames + i;
|
||||
|
||||
bts->rlc_ul_payload_bytes(frame->length);
|
||||
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG, "-- Frame %d starts at offset %d, "
|
||||
"length=%d, is_complete=%d\n",
|
||||
i + 1, frame->offset, frame->length, frame->is_complete);
|
||||
|
@ -79,6 +81,7 @@ int gprs_rlcmac_ul_tbf::assemble_forward_llc(const gprs_rlc_data *_data)
|
|||
LOGP(DRLCMACUL, LOGL_INFO, "%s complete UL frame len=%d\n",
|
||||
tbf_name(this) , m_llc.frame_length());
|
||||
snd_ul_ud();
|
||||
bts->llc_ul_bytes(m_llc.frame_length());
|
||||
m_llc.reset();
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +141,135 @@ struct msgb *gprs_rlcmac_ul_tbf::create_ul_ack(uint32_t fn, uint8_t ts)
|
|||
return msg;
|
||||
}
|
||||
|
||||
egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::handle_egprs_ul_second_seg(
|
||||
const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block,
|
||||
uint8_t *data, const uint8_t block_idx)
|
||||
{
|
||||
const struct gprs_rlc_data_block_info *rdbi =
|
||||
&rlc->block_info[block_idx];
|
||||
|
||||
uint8_t *rlc_data = &(block->block[0]);
|
||||
|
||||
if (block->block_status_ul & EGPRS_RESEG_FIRST_SEG_RXD) {
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG,
|
||||
"Second seg is received "
|
||||
"first seg is already present "
|
||||
"set the status to complete\n");
|
||||
block->block_status_ul = EGPRS_RESEG_DEFAULT;
|
||||
|
||||
block->len += Decoding::rlc_copy_to_aligned_buffer(rlc,
|
||||
block_idx, data, rlc_data + block->len);
|
||||
block->block_info.data_len += rdbi->data_len;
|
||||
return EGPRS_RESEG_DEFAULT;
|
||||
|
||||
} else if (block->block_status_ul == EGPRS_RESEG_DEFAULT) {
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG,
|
||||
"Second seg is received "
|
||||
"first seg is not received "
|
||||
"set the status to second seg received\n");
|
||||
block->len = Decoding::rlc_copy_to_aligned_buffer(rlc,
|
||||
block_idx, data, rlc_data);
|
||||
block->block_status_ul = EGPRS_RESEG_SECOND_SEG_RXD;
|
||||
block->block_info = *rdbi;
|
||||
return EGPRS_RESEG_SECOND_SEG_RXD;
|
||||
}
|
||||
return EGPRS_RESEG_INVALID;
|
||||
}
|
||||
|
||||
|
||||
egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::handle_egprs_ul_first_seg(
|
||||
const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block,
|
||||
uint8_t *data, const uint8_t block_idx)
|
||||
{
|
||||
const struct gprs_rlc_data_block_info *rdbi =
|
||||
&rlc->block_info[block_idx];
|
||||
uint8_t *rlc_data = &(block->block[0]);
|
||||
|
||||
if (block->block_status_ul & EGPRS_RESEG_SECOND_SEG_RXD) {
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG,
|
||||
"First seg is received "
|
||||
"second seg is already present "
|
||||
"set the status to complete");
|
||||
static uint8_t seg_data[RLC_MAX_LEN];
|
||||
uint8_t len = block->len;
|
||||
|
||||
/* Assembling the resegmented split blocks */
|
||||
memcpy(seg_data, block->block, len);
|
||||
block->len = Decoding::rlc_copy_to_aligned_buffer(rlc,
|
||||
block_idx, data, rlc_data);
|
||||
memcpy(block->block + block->len, seg_data, len);
|
||||
block->len += len;
|
||||
block->block_info.data_len += rdbi->data_len;
|
||||
block->block_status_ul = EGPRS_RESEG_DEFAULT;
|
||||
return EGPRS_RESEG_DEFAULT;
|
||||
} else if (block->block_status_ul == EGPRS_RESEG_DEFAULT) {
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG,
|
||||
"First seg is received "
|
||||
"second seg is not received "
|
||||
"set the status to first seg "
|
||||
"received\n");
|
||||
|
||||
block->block_status_ul = EGPRS_RESEG_FIRST_SEG_RXD;
|
||||
block->len = Decoding::rlc_copy_to_aligned_buffer(rlc,
|
||||
block_idx, data, rlc_data);
|
||||
block->block_info = *rdbi;
|
||||
return EGPRS_RESEG_FIRST_SEG_RXD;
|
||||
}
|
||||
return EGPRS_RESEG_INVALID;
|
||||
}
|
||||
|
||||
egprs_rlc_ul_reseg_bsn_state gprs_rlcmac_ul_tbf::handle_egprs_ul_spb(
|
||||
const struct gprs_rlc_data_info *rlc, struct gprs_rlc_data *block,
|
||||
uint8_t *data, const uint8_t block_idx)
|
||||
{
|
||||
const struct gprs_rlc_data_block_info *rdbi =
|
||||
&rlc->block_info[block_idx];
|
||||
|
||||
LOGP(DRLCMACUL, LOGL_NOTICE,
|
||||
"Got SPB(%d) "
|
||||
"cs(%s) data block with BSN (%d), "
|
||||
"TFI(%d).\n", rdbi->spb, rlc->cs.name(), rdbi->bsn,
|
||||
rlc->tfi);
|
||||
|
||||
egprs_rlc_ul_reseg_bsn_state re_assemble_status = EGPRS_RESEG_INVALID;
|
||||
|
||||
/* Section 10.4.8b of 44.060*/
|
||||
if (rdbi->spb == 2)
|
||||
re_assemble_status = handle_egprs_ul_first_seg(rlc,
|
||||
block, data, block_idx);
|
||||
else if (rdbi->spb == 3)
|
||||
re_assemble_status = handle_egprs_ul_second_seg(rlc,
|
||||
block, data, block_idx);
|
||||
else {
|
||||
LOGP(DRLCMACUL, LOGL_ERROR,
|
||||
"Not supported SPB for this EGPRS configuration\n");
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* When the block is successfully constructed out of segmented blocks
|
||||
* upgrade the MCS to the type 2
|
||||
*/
|
||||
if (re_assemble_status == EGPRS_RESEG_DEFAULT) {
|
||||
switch (GprsCodingScheme::Scheme(rlc->cs)) {
|
||||
case GprsCodingScheme::MCS3 :
|
||||
block->cs = GprsCodingScheme::MCS6;
|
||||
break;
|
||||
case GprsCodingScheme::MCS2 :
|
||||
block->cs = GprsCodingScheme::MCS5;
|
||||
break;
|
||||
case GprsCodingScheme::MCS1 :
|
||||
block->cs = GprsCodingScheme::MCS4;
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return re_assemble_status;
|
||||
}
|
||||
|
||||
/*! \brief receive data from PDCH/L1 */
|
||||
int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
|
||||
const struct gprs_rlc_data_info *rlc,
|
||||
uint8_t *data, struct pcu_l1_meas *meas)
|
||||
|
@ -219,43 +351,33 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
|
|||
rdbi->bsn, m_window.v_q(),
|
||||
m_window.mod_sns(m_window.v_q() + ws - 1));
|
||||
block = m_rlc.block(rdbi->bsn);
|
||||
block->block_info = *rdbi;
|
||||
block->cs = rlc->cs;
|
||||
OSMO_ASSERT(rdbi->data_len < sizeof(block->block));
|
||||
OSMO_ASSERT(rdbi->data_len <= sizeof(block->block));
|
||||
rlc_data = &(block->block[0]);
|
||||
/* TODO: Handle SPB != 0 -> Set length to 2*len, add offset if
|
||||
* 2nd part. Note that resegmentation is currently disabled
|
||||
* within the UL assignment.
|
||||
*/
|
||||
|
||||
if (rdbi->spb) {
|
||||
LOGP(DRLCMACUL, LOGL_NOTICE,
|
||||
"Got SPB != 0 but resegmentation has been "
|
||||
"disabled, skipping %s data block with BSN %d, "
|
||||
"TFI=%d.\n", rlc->cs.name(), rdbi->bsn,
|
||||
rlc->tfi);
|
||||
continue;
|
||||
egprs_rlc_ul_reseg_bsn_state re_assemble_status =
|
||||
handle_egprs_ul_spb(rlc, block,
|
||||
data, block_idx);
|
||||
if (re_assemble_status != EGPRS_RESEG_DEFAULT)
|
||||
return 0;
|
||||
} else {
|
||||
block->block_info = *rdbi;
|
||||
block->cs = rlc->cs;
|
||||
block->len =
|
||||
Decoding::rlc_copy_to_aligned_buffer(rlc,
|
||||
block_idx, data, rlc_data);
|
||||
}
|
||||
|
||||
block->len =
|
||||
Decoding::rlc_copy_to_aligned_buffer(rlc, block_idx, data,
|
||||
rlc_data);
|
||||
|
||||
m_ctr_num_blocks[rlc->cs.to_num() - 1]++;
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG,
|
||||
"%s: data_length=%d, data=%s\n",
|
||||
name(), block->len, osmo_hexdump(rlc_data, block->len));
|
||||
|
||||
/* TODO: Handle SPB != 0 -> set state to partly received
|
||||
* (upper/lower) and continue with the loop, unless the other
|
||||
* part is already present.
|
||||
*/
|
||||
|
||||
/* Get/Handle TLLI */
|
||||
if (rdbi->ti) {
|
||||
num_chunks = Decoding::rlc_data_from_ul_data(
|
||||
rdbi, rlc->cs, rlc_data, NULL, 0, &new_tlli);
|
||||
|
||||
if (num_chunks < 0) {
|
||||
bts->decode_error();
|
||||
bts->llc_decode_err();
|
||||
LOGP(DRLCMACUL, LOGL_NOTICE,
|
||||
"Failed to decode TLLI of %s UL DATA "
|
||||
"TFI=%d.\n", rlc->cs.name(), rlc->tfi);
|
||||
|
@ -337,6 +459,7 @@ void gprs_rlcmac_ul_tbf::maybe_schedule_uplink_acknack(
|
|||
if (rlc->si) {
|
||||
LOGP(DRLCMACUL, LOGL_NOTICE, "- Scheduling Ack/Nack, "
|
||||
"because MS is stalled.\n");
|
||||
bts->rlc_ul_stalled();
|
||||
}
|
||||
if (have_ti) {
|
||||
LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "encoding.h"
|
||||
#include "rlc.h"
|
||||
#include "llc.h"
|
||||
|
||||
#include "bts.h"
|
||||
extern "C" {
|
||||
#include "pcu_vty.h"
|
||||
|
||||
|
@ -1101,6 +1101,250 @@ const struct log_info debug_log_info = {
|
|||
ARRAY_SIZE(default_categories),
|
||||
};
|
||||
|
||||
static void setup_bts(BTS *the_bts, uint8_t ts_no, uint8_t cs = 1)
|
||||
{
|
||||
gprs_rlcmac_bts *bts;
|
||||
gprs_rlcmac_trx *trx;
|
||||
|
||||
bts = the_bts->bts_data();
|
||||
bts->egprs_enabled = true;
|
||||
bts->alloc_algorithm = alloc_algorithm_a;
|
||||
bts->initial_cs_dl = cs;
|
||||
bts->initial_cs_ul = cs;
|
||||
trx = &bts->trx[0];
|
||||
trx->pdch[ts_no].enable();
|
||||
}
|
||||
static void uplink_header_type_2_parsing_test(BTS *the_bts,
|
||||
uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta,
|
||||
uint8_t ms_class)
|
||||
{
|
||||
GprsMs *ms;
|
||||
struct pcu_l1_meas meas;
|
||||
int tfi = 0;
|
||||
gprs_rlcmac_bts *bts;
|
||||
RlcMacUplink_t ulreq = {0};
|
||||
uint8_t data[79] = {0};
|
||||
struct gprs_rlc_ul_header_egprs_2 *egprs2 = NULL;
|
||||
|
||||
egprs2 = (struct gprs_rlc_ul_header_egprs_2 *) data;
|
||||
bts = the_bts->bts_data();
|
||||
|
||||
tfi = 1;
|
||||
|
||||
struct gprs_rlc_data_info rlc;
|
||||
GprsCodingScheme cs;
|
||||
int rc, offs;
|
||||
|
||||
/*without padding*/
|
||||
cs = GprsCodingScheme::MCS5;
|
||||
egprs2 = (struct gprs_rlc_ul_header_egprs_2 *) data;
|
||||
egprs2->r = 1;
|
||||
egprs2->si = 1;
|
||||
egprs2->cv = 7;
|
||||
egprs2->tfi_a = tfi & 0x03;
|
||||
egprs2->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs2->bsn1_a = 0;
|
||||
egprs2->bsn1_b = 0;
|
||||
egprs2->cps_a = 3;
|
||||
egprs2->cps_b = 0;
|
||||
egprs2->rsb = 0;
|
||||
egprs2->pi = 0;
|
||||
data[4] = 0x20; /* Setting E field */
|
||||
rc = Decoding::rlc_parse_ul_data_header(&rlc, data, cs);
|
||||
offs = rlc.data_offs_bits[0] / 8;
|
||||
OSMO_ASSERT(offs == 4);
|
||||
OSMO_ASSERT(rlc.tfi == 1);
|
||||
OSMO_ASSERT(rlc.num_data_blocks == 1);
|
||||
OSMO_ASSERT(rlc.block_info[0].e == 1);
|
||||
OSMO_ASSERT(rlc.block_info[0].ti == 0);
|
||||
OSMO_ASSERT(rlc.block_info[0].bsn == 0);
|
||||
|
||||
/* with padding case */
|
||||
cs = GprsCodingScheme::MCS6;
|
||||
egprs2 = (struct gprs_rlc_ul_header_egprs_2 *) data;
|
||||
egprs2->r = 1;
|
||||
egprs2->si = 1;
|
||||
egprs2->cv = 7;
|
||||
egprs2->tfi_a = tfi & 0x03;
|
||||
egprs2->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs2->bsn1_a = 0;
|
||||
egprs2->bsn1_b = 0;
|
||||
egprs2->cps_a = 3;
|
||||
egprs2->cps_b = 0;
|
||||
egprs2->rsb = 0;
|
||||
egprs2->pi = 0;
|
||||
data[10] = 0x20; /* Setting E field */
|
||||
rc = Decoding::rlc_parse_ul_data_header(&rlc, data, cs);
|
||||
offs = rlc.data_offs_bits[0] / 8;
|
||||
OSMO_ASSERT(offs == 10);
|
||||
OSMO_ASSERT(rlc.num_data_blocks == 1);
|
||||
OSMO_ASSERT(rlc.tfi == 1);
|
||||
OSMO_ASSERT(rlc.block_info[0].e == 1);
|
||||
OSMO_ASSERT(rlc.block_info[0].ti == 0);
|
||||
OSMO_ASSERT(rlc.block_info[0].bsn == 0);
|
||||
|
||||
egprs2->r = 1;
|
||||
egprs2->si = 1;
|
||||
egprs2->cv = 7;
|
||||
egprs2->tfi_a = tfi & 0x03;
|
||||
egprs2->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs2->bsn1_a = 1;
|
||||
egprs2->bsn1_b = 0;
|
||||
egprs2->cps_a = 2;
|
||||
egprs2->cps_b = 0;
|
||||
egprs2->rsb = 0;
|
||||
egprs2->pi = 0;
|
||||
data[10] = 0x20; /* Setting E field */
|
||||
rc = Decoding::rlc_parse_ul_data_header(&rlc, data, cs);
|
||||
offs = rlc.data_offs_bits[0] / 8;
|
||||
OSMO_ASSERT(offs == 10);
|
||||
OSMO_ASSERT(rlc.tfi == 1);
|
||||
OSMO_ASSERT(rlc.num_data_blocks == 1);
|
||||
OSMO_ASSERT(rlc.block_info[0].e == 1);
|
||||
OSMO_ASSERT(rlc.block_info[0].ti == 0);
|
||||
OSMO_ASSERT(rlc.block_info[0].bsn == 1);
|
||||
}
|
||||
|
||||
static void uplink_header_type2_test(void)
|
||||
{
|
||||
BTS the_bts;
|
||||
int ts_no = 7;
|
||||
uint32_t fn = 2654218;
|
||||
uint16_t qta = 31;
|
||||
uint32_t tlli = 0xf1223344;
|
||||
const char *imsi = "0011223344";
|
||||
uint8_t ms_class = 1;
|
||||
gprs_rlcmac_ul_tbf *ul_tbf;
|
||||
GprsMs *ms;
|
||||
|
||||
printf("=== start %s ===\n", __func__);
|
||||
setup_bts(&the_bts, ts_no, 10);
|
||||
|
||||
uplink_header_type_2_parsing_test(&the_bts, ts_no,
|
||||
tlli, &fn, qta, ms_class);
|
||||
printf("=== end %s ===\n", __func__);
|
||||
}
|
||||
|
||||
static void uplink_header_type_1_parsing_test(BTS *the_bts,
|
||||
uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta,
|
||||
uint8_t ms_class)
|
||||
{
|
||||
uint8_t trx_no = 0;
|
||||
int tfi = 0;
|
||||
struct gprs_rlcmac_pdch *pdch;
|
||||
gprs_rlcmac_bts *bts;
|
||||
uint8_t data[155] = {0};
|
||||
struct gprs_rlc_ul_header_egprs_1 *egprs1 = NULL;
|
||||
struct gprs_rlc_data_info rlc;
|
||||
GprsCodingScheme cs;
|
||||
int rc, offs;
|
||||
|
||||
egprs1 = (struct gprs_rlc_ul_header_egprs_1 *) data;
|
||||
bts = the_bts->bts_data();
|
||||
|
||||
tfi = 1;
|
||||
|
||||
/* MCS 7 */
|
||||
cs = GprsCodingScheme::MCS7;
|
||||
egprs1 = (struct gprs_rlc_ul_header_egprs_1 *) data;
|
||||
egprs1->si = 1;
|
||||
egprs1->r = 1;
|
||||
egprs1->cv = 7;
|
||||
egprs1->tfi_a = tfi & 0x03;
|
||||
egprs1->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs1->bsn1_a = 0;
|
||||
egprs1->bsn1_b = 0;
|
||||
egprs1->bsn2_a = 1;
|
||||
egprs1->bsn2_b = 0;
|
||||
egprs1->cps = 15;
|
||||
egprs1->rsb = 0;
|
||||
egprs1->pi = 0;
|
||||
data[5] = 0xc0;
|
||||
data[5 + 57] = 1;
|
||||
rc = Decoding::rlc_parse_ul_data_header(&rlc, data, cs);
|
||||
OSMO_ASSERT(rlc.num_data_blocks == 2);
|
||||
OSMO_ASSERT(rlc.block_info[0].e == 1);
|
||||
OSMO_ASSERT(rlc.block_info[0].ti == 1);
|
||||
OSMO_ASSERT(rlc.block_info[1].e == 1);
|
||||
OSMO_ASSERT(rlc.block_info[1].ti == 0);
|
||||
OSMO_ASSERT(rlc.block_info[0].bsn == 0);
|
||||
OSMO_ASSERT(rlc.block_info[1].bsn == 1);
|
||||
OSMO_ASSERT(rlc.tfi == 1);
|
||||
|
||||
/* MCS 8 */
|
||||
cs = GprsCodingScheme::MCS8;
|
||||
egprs1 = (struct gprs_rlc_ul_header_egprs_1 *) data;
|
||||
egprs1->si = 1;
|
||||
egprs1->r = 1;
|
||||
egprs1->cv = 7;
|
||||
egprs1->tfi_a = tfi & 0x03;
|
||||
egprs1->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs1->bsn1_a = 0;
|
||||
egprs1->bsn1_b = 0;
|
||||
egprs1->bsn2_a = 1;
|
||||
egprs1->bsn2_b = 0;
|
||||
egprs1->cps = 15;
|
||||
egprs1->rsb = 0;
|
||||
egprs1->pi = 0;
|
||||
data[5] = 0xc0;
|
||||
data[5 + 69] = 1;
|
||||
rc = Decoding::rlc_parse_ul_data_header(&rlc, data, cs);
|
||||
OSMO_ASSERT(rlc.num_data_blocks == 2);
|
||||
OSMO_ASSERT(rlc.block_info[0].e == 1);
|
||||
OSMO_ASSERT(rlc.block_info[0].ti == 1);
|
||||
OSMO_ASSERT(rlc.block_info[1].e == 1);
|
||||
OSMO_ASSERT(rlc.block_info[1].ti == 0);
|
||||
OSMO_ASSERT(rlc.block_info[0].bsn == 0);
|
||||
OSMO_ASSERT(rlc.block_info[1].bsn == 1);
|
||||
OSMO_ASSERT(rlc.tfi == 1);
|
||||
|
||||
/* MCS 9 */
|
||||
cs = GprsCodingScheme::MCS9;
|
||||
egprs1 = (struct gprs_rlc_ul_header_egprs_1 *) data;
|
||||
egprs1->si = 1;
|
||||
egprs1->r = 1;
|
||||
egprs1->cv = 7;
|
||||
egprs1->tfi_a = tfi & 0x03;
|
||||
egprs1->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs1->bsn1_a = 0;
|
||||
egprs1->bsn1_b = 0;
|
||||
egprs1->bsn2_a = 1;
|
||||
egprs1->bsn2_b = 0;
|
||||
egprs1->cps = 15;
|
||||
egprs1->rsb = 0;
|
||||
egprs1->pi = 0;
|
||||
data[5] = 0xc0;
|
||||
data[5 + 75] = 1;
|
||||
rc = Decoding::rlc_parse_ul_data_header(&rlc, data, cs);
|
||||
OSMO_ASSERT(rlc.num_data_blocks == 2);
|
||||
OSMO_ASSERT(rlc.block_info[0].e == 1);
|
||||
OSMO_ASSERT(rlc.block_info[0].ti == 1);
|
||||
OSMO_ASSERT(rlc.block_info[1].e == 1);
|
||||
OSMO_ASSERT(rlc.block_info[1].ti == 0);
|
||||
OSMO_ASSERT(rlc.block_info[0].bsn == 0);
|
||||
OSMO_ASSERT(rlc.block_info[1].bsn == 1);
|
||||
OSMO_ASSERT(rlc.tfi == 1);
|
||||
}
|
||||
|
||||
void uplink_header_type1_test(void)
|
||||
{
|
||||
BTS the_bts;
|
||||
int ts_no = 7;
|
||||
uint32_t fn = 2654218;
|
||||
uint16_t qta = 31;
|
||||
uint32_t tlli = 0xf1223344;
|
||||
const char *imsi = "0011223344";
|
||||
uint8_t ms_class = 1;
|
||||
gprs_rlcmac_ul_tbf *ul_tbf;
|
||||
GprsMs *ms;
|
||||
|
||||
printf("=== start %s ===\n", __func__);
|
||||
setup_bts(&the_bts, ts_no, 12);
|
||||
uplink_header_type_1_parsing_test(&the_bts, ts_no, tlli, &fn,
|
||||
qta, ms_class);
|
||||
printf("=== end %s ===\n", __func__);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct vty_app_info pcu_vty_info = {0};
|
||||
|
@ -1123,6 +1367,9 @@ int main(int argc, char **argv)
|
|||
test_rlc_unaligned_copy();
|
||||
test_rlc_unit_encoder();
|
||||
|
||||
uplink_header_type2_test();
|
||||
uplink_header_type1_test();
|
||||
|
||||
if (getenv("TALLOC_REPORT_FULL"))
|
||||
talloc_report_full(tall_pcu_ctx, stderr);
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -6,3 +6,7 @@
|
|||
=== end test_rlc_unit_decoder ===
|
||||
=== start test_rlc_unit_encoder ===
|
||||
=== end test_rlc_unit_encoder ===
|
||||
=== start uplink_header_type2_test ===
|
||||
=== end uplink_header_type2_test ===
|
||||
=== start uplink_header_type1_test ===
|
||||
=== end uplink_header_type1_test ===
|
||||
|
|
|
@ -89,9 +89,12 @@ void testRlcMacDownlink()
|
|||
|
||||
std::string testData[] = {
|
||||
"4e082500e3f1a81d080820800b2b2b2b2b2b2b2b2b2b2b", // Packet Downlink Assignment
|
||||
"48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b", // Packet Uplink Assignment
|
||||
"48282407a6a07422720100032b2b2b2b2b2b2b2b2b2b2b", // Packet Uplink Assignment
|
||||
"47240c00400000000000000079eb2ac9402b2b2b2b2b2b", // Packet Uplink Ack Nack
|
||||
"47283c367513ba333004242b2b2b2b2b2b2b2b2b2b2b2b" // Packet Uplink Assignment
|
||||
"47283c367513ba333004242b2b2b2b2b2b2b2b2b2b2b2b", // Packet Uplink Assignment
|
||||
"400820001a3904df0680efb3300b2b2b2b2b2b2b2b2b2b", // Packet Downlink Assignment (EGPRS)
|
||||
"40284f0000001009810c826f4406809dcecb2b2b2b2b2b", // Packet Uplink Assignment (EGPRS)
|
||||
"4024030f2f0000000087b0042b2b2b2b2b2b2b2b2b2b2b" // Packet Uplink Ack Nack (EGPRS)
|
||||
"4913e00850884013a8048b2b2b2b2b2b2b2b2b2b2b2b2b"
|
||||
"412430007fffffffffffffffefd19c7ba12b2b2b2b2b2b"
|
||||
"41942b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b"
|
||||
|
@ -152,9 +155,10 @@ void testRlcMacUplink()
|
|||
bitvec_unhex(resultVector, "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
|
||||
|
||||
std::string testData[] = {
|
||||
"400e1e61d11f2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b", // Packet Uplink Dummy Control Block
|
||||
"400b8020000000000000002480e00b2b2b2b2b2b2b2b2b", // Packet Downlink Ack/Nack
|
||||
"4016713dc094270ca2ae57ef909006aa0fc0001f80222b" // Packet Resource Request
|
||||
"400e1e61d11d2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b", // Packet Uplink Dummy Control Block
|
||||
"400b8020000000000000002480e0032b2b2b2b2b2b2b2b", // Packet Downlink Ack/Nack
|
||||
"4016713dc094270ca2ae57ef909006aa0fc0001f80222b", // Packet Resource Request
|
||||
"40200ffc0021ec010b2b2b2b2b2b2b2b2b2b2b2b2b2b2b", // EPDAN
|
||||
"400a9020000000000000003010012a0800132b2b2b2b2b"
|
||||
};
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@ vector1 = 4e8250e3f1a81d882080b2b2b2b2b2b2b2b2b2b2b
|
|||
vector1 = 4e8250e3f1a81d882080b2b2b2b2b2b2b2b2b2b2b
|
||||
vector2 = 4e8250e3f1a81d882080b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
vector1 = 4828247a6a074227210b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 = 4828247a6a07422721032b2b2b2b2b2b2b2b2b2b2b
|
||||
=========Start DECODE===========
|
||||
+++++++++Finish DECODE++++++++++
|
||||
=========Start ENCODE=============
|
||||
+++++++++Finish ENCODE+++++++++++
|
||||
vector1 = 4828247a6a074227210b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector2 = 4828247a6a074227210b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 = 4828247a6a07422721032b2b2b2b2b2b2b2b2b2b2b
|
||||
vector2 = 4828247a6a07422721032b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
vector1 = 4724c040000000079eb2ac9402b2b2b2b2b2b
|
||||
=========Start DECODE===========
|
||||
|
@ -31,22 +31,46 @@ vector1 = 47283c367513ba33304242b2b2b2b2b2b2b2b2b2b2b2b
|
|||
vector1 = 47283c367513ba33304242b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector2 = 47283c367513ba33304242b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
UPLINK
|
||||
vector1 = 40e1e61d11f2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 = 4082001a394df680efb330b2b2b2b2b2b2b2b2b2b
|
||||
=========Start DECODE===========
|
||||
+++++++++Finish DECODE++++++++++
|
||||
=========Start ENCODE=============
|
||||
+++++++++Finish ENCODE+++++++++++
|
||||
vector1 = 40e1e61d11f2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector2 = 40e1e61d11f2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 = 4082001a394df680efb330b2b2b2b2b2b2b2b2b2b
|
||||
vector2 = 4082001a394df680efb330b2b2b2b2b2b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
vector1 = 40b802000000002480e0b2b2b2b2b2b2b2b2b
|
||||
vector1 = 40284f00010981c826f446809dcecb2b2b2b2b2b
|
||||
=========Start DECODE===========
|
||||
+++++++++Finish DECODE++++++++++
|
||||
=========Start ENCODE=============
|
||||
+++++++++Finish ENCODE+++++++++++
|
||||
vector1 = 40b802000000002480e0b2b2b2b2b2b2b2b2b
|
||||
vector2 = 40b802000000002480e0b2b2b2b2b2b2b2b2b
|
||||
vector1 = 40284f00010981c826f446809dcecb2b2b2b2b2b
|
||||
vector2 = 40284f00010981c826f446809dcecb2b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
vector1 = 40243f2f000087b042b2b2b2b2b2b2b2b2b2b2b
|
||||
=========Start DECODE===========
|
||||
+++++++++Finish DECODE++++++++++
|
||||
=========Start ENCODE=============
|
||||
+++++++++Finish ENCODE+++++++++++
|
||||
vector1 = 40243f2f000087b042b2b2b2b2b2b2b2b2b2b2b
|
||||
vector2 = 40243f2f000087b042b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
UPLINK
|
||||
vector1 = 40e1e61d11d2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
=========Start DECODE===========
|
||||
+++++++++Finish DECODE++++++++++
|
||||
=========Start ENCODE=============
|
||||
+++++++++Finish ENCODE+++++++++++
|
||||
vector1 = 40e1e61d11d2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector2 = 40e1e61d11d2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
vector1 = 40b802000000002480e032b2b2b2b2b2b2b2b
|
||||
=========Start DECODE===========
|
||||
+++++++++Finish DECODE++++++++++
|
||||
=========Start ENCODE=============
|
||||
+++++++++Finish ENCODE+++++++++++
|
||||
vector1 = 40b802000000002480e032b2b2b2b2b2b2b2b
|
||||
vector2 = 40b802000000002480e032b2b2b2b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
vector1 = 4016713dc09427ca2ae57ef90906aafc001f80222b
|
||||
=========Start DECODE===========
|
||||
|
@ -56,3 +80,19 @@ vector1 = 4016713dc09427ca2ae57ef90906aafc001f80222b
|
|||
vector1 = 4016713dc09427ca2ae57ef90906aafc001f80222b
|
||||
vector2 = 4016713dc09427ca2ae57ef90906aafc001f80222b
|
||||
vector1 == vector2 : TRUE
|
||||
vector1 = 4020ffc021ec1b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
=========Start DECODE===========
|
||||
+++++++++Finish DECODE++++++++++
|
||||
=========Start ENCODE=============
|
||||
+++++++++Finish ENCODE+++++++++++
|
||||
vector1 = 4020ffc021ec1b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector2 = 4020ffc021ec1b2b2b2b2b2b2b2b2b2b2b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
vector1 = 40a90200000000301012a80132b2b2b2b2b
|
||||
=========Start DECODE===========
|
||||
+++++++++Finish DECODE++++++++++
|
||||
=========Start ENCODE=============
|
||||
+++++++++Finish ENCODE+++++++++++
|
||||
vector1 = 40a90200000000301012a80132b2b2b2b2b
|
||||
vector2 = 40a90200000000301012a80132b2b2b2b2b
|
||||
vector1 == vector2 : TRUE
|
||||
|
|
|
@ -617,6 +617,186 @@ static void send_control_ack(gprs_rlcmac_tbf *tbf)
|
|||
&ulreq, tbf->poll_fn);
|
||||
}
|
||||
|
||||
static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase_spb(BTS *the_bts,
|
||||
uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta,
|
||||
uint8_t ms_class, uint8_t egprs_ms_class)
|
||||
{
|
||||
GprsMs *ms;
|
||||
uint32_t rach_fn = *fn - 51;
|
||||
uint32_t sba_fn = *fn + 52;
|
||||
uint8_t trx_no = 0;
|
||||
int tfi = 0;
|
||||
gprs_rlcmac_ul_tbf *ul_tbf;
|
||||
struct gprs_rlcmac_pdch *pdch;
|
||||
gprs_rlcmac_bts *bts;
|
||||
RlcMacUplink_t ulreq = {0};
|
||||
struct pcu_l1_meas meas;
|
||||
struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL;
|
||||
GprsCodingScheme cs;
|
||||
|
||||
meas.set_rssi(31);
|
||||
bts = the_bts->bts_data();
|
||||
|
||||
/* needed to set last_rts_fn in the PDCH object */
|
||||
request_dl_rlc_block(bts, trx_no, ts_no, 0, fn);
|
||||
|
||||
/*
|
||||
* simulate RACH, this sends an Immediate
|
||||
* Assignment Uplink on the AGCH
|
||||
*/
|
||||
the_bts->rcv_rach(0x73, rach_fn, qta);
|
||||
|
||||
/* get next free TFI */
|
||||
tfi = the_bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
|
||||
|
||||
/* fake a resource request */
|
||||
ulreq.u.MESSAGE_TYPE = MT_PACKET_RESOURCE_REQUEST;
|
||||
ulreq.u.Packet_Resource_Request.PayloadType = GPRS_RLCMAC_CONTROL_BLOCK;
|
||||
ulreq.u.Packet_Resource_Request.ID.UnionType = 1; /* != 0 */
|
||||
ulreq.u.Packet_Resource_Request.ID.u.TLLI = tlli;
|
||||
ulreq.u.Packet_Resource_Request.Exist_MS_Radio_Access_capability = 1;
|
||||
ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
|
||||
Count_MS_RA_capability_value = 1;
|
||||
ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
|
||||
MS_RA_capability_value[0].u.Content.
|
||||
Exist_Multislot_capability = 1;
|
||||
ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
|
||||
MS_RA_capability_value[0].u.Content.Multislot_capability.
|
||||
Exist_GPRS_multislot_class = 1;
|
||||
ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
|
||||
MS_RA_capability_value[0].u.Content.Multislot_capability.
|
||||
GPRS_multislot_class = ms_class;
|
||||
if (egprs_ms_class) {
|
||||
ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
|
||||
MS_RA_capability_value[0].u.Content.
|
||||
Multislot_capability.Exist_EGPRS_multislot_class = 1;
|
||||
ulreq.u.Packet_Resource_Request.MS_Radio_Access_capability.
|
||||
MS_RA_capability_value[0].u.Content.
|
||||
Multislot_capability.EGPRS_multislot_class = ms_class;
|
||||
}
|
||||
|
||||
send_ul_mac_block(the_bts, trx_no, ts_no, &ulreq, sba_fn);
|
||||
|
||||
/* check the TBF */
|
||||
ul_tbf = the_bts->ul_tbf_by_tfi(tfi, trx_no, ts_no);
|
||||
OSMO_ASSERT(ul_tbf != NULL);
|
||||
OSMO_ASSERT(ul_tbf->ta() == qta / 4);
|
||||
|
||||
/* send packet uplink assignment */
|
||||
*fn = sba_fn;
|
||||
request_dl_rlc_block(ul_tbf, fn);
|
||||
|
||||
/* send real acknowledgement */
|
||||
send_control_ack(ul_tbf);
|
||||
|
||||
check_tbf(ul_tbf);
|
||||
|
||||
/* send fake data */
|
||||
uint8_t data_msg[42] = {
|
||||
0x00 | 0xf << 2, /* GPRS_RLCMAC_DATA_BLOCK << 6, CV = 15 */
|
||||
uint8_t(0 | (tfi << 1)),
|
||||
uint8_t(1), /* BSN:7, E:1 */
|
||||
};
|
||||
|
||||
pdch = &the_bts->bts_data()->trx[trx_no].pdch[ts_no];
|
||||
pdch->rcv_block(&data_msg[0], 23, *fn, &meas);
|
||||
|
||||
ms = the_bts->ms_by_tlli(tlli);
|
||||
OSMO_ASSERT(ms != NULL);
|
||||
OSMO_ASSERT(ms->ta() == qta/4);
|
||||
OSMO_ASSERT(ms->ul_tbf() == ul_tbf);
|
||||
|
||||
/*
|
||||
* TS 44.060, B.8.1
|
||||
* first seg received first, later second seg
|
||||
*/
|
||||
cs = GprsCodingScheme::MCS3;
|
||||
egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg;
|
||||
egprs3->si = 1;
|
||||
egprs3->r = 1;
|
||||
egprs3->cv = 7;
|
||||
egprs3->tfi_a = tfi & 0x03;
|
||||
egprs3->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs3->bsn1_a = 1;
|
||||
egprs3->bsn1_b = 0;
|
||||
egprs3->cps_a = 1;
|
||||
data_msg[3] = 0xff;
|
||||
egprs3->cps_b = 1;
|
||||
egprs3->rsb = 0;
|
||||
egprs3->spb = 2;
|
||||
egprs3->pi = 0;
|
||||
|
||||
pdch->rcv_block(data_msg, 42, *fn, &meas);
|
||||
|
||||
struct gprs_rlc_data *block = ul_tbf->m_rlc.block(1);
|
||||
|
||||
/* check the status of the block */
|
||||
OSMO_ASSERT(block->block_status_ul == EGPRS_RESEG_FIRST_SEG_RXD);
|
||||
|
||||
egprs3->si = 1;
|
||||
egprs3->r = 1;
|
||||
egprs3->cv = 7;
|
||||
egprs3->tfi_a = tfi & 0x03;
|
||||
egprs3->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs3->bsn1_a = 1;
|
||||
egprs3->bsn1_b = 0;
|
||||
egprs3->cps_a = 1;
|
||||
egprs3->cps_b = 1;
|
||||
egprs3->rsb = 0;
|
||||
egprs3->spb = 3;
|
||||
|
||||
pdch->rcv_block(data_msg, 42, *fn, &meas);
|
||||
|
||||
/* check the status of the block */
|
||||
OSMO_ASSERT(block->block_status_ul == EGPRS_RESEG_DEFAULT);
|
||||
|
||||
/*
|
||||
* TS 44.060, B.8.1
|
||||
* second seg first, later first seg
|
||||
*/
|
||||
cs = GprsCodingScheme::MCS3;
|
||||
egprs3 = (struct gprs_rlc_ul_header_egprs_3 *) data_msg;
|
||||
egprs3->si = 1;
|
||||
egprs3->r = 1;
|
||||
egprs3->cv = 7;
|
||||
egprs3->tfi_a = tfi & 0x03;
|
||||
egprs3->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs3->bsn1_a = 2;
|
||||
egprs3->bsn1_b = 0;
|
||||
egprs3->cps_a = 1;
|
||||
egprs3->cps_b = 1;
|
||||
egprs3->rsb = 0;
|
||||
egprs3->spb = 3;
|
||||
egprs3->pi = 0;
|
||||
|
||||
pdch->rcv_block(data_msg, 42, *fn, &meas);
|
||||
|
||||
block = ul_tbf->m_rlc.block(2);
|
||||
/* check the status of the block */
|
||||
OSMO_ASSERT(block->block_status_ul == EGPRS_RESEG_SECOND_SEG_RXD);
|
||||
|
||||
egprs3->si = 1;
|
||||
egprs3->r = 1;
|
||||
egprs3->cv = 7;
|
||||
egprs3->tfi_a = tfi & 0x03;
|
||||
egprs3->tfi_b = (tfi & 0x1c) >> 2;
|
||||
egprs3->bsn1_a = 2;
|
||||
egprs3->bsn1_b = 0;
|
||||
egprs3->cps_a = 1;
|
||||
data_msg[3] = 0xff;
|
||||
egprs3->cps_b = 1;
|
||||
egprs3->rsb = 0;
|
||||
egprs3->spb = 2;
|
||||
egprs3->pi = 0;
|
||||
|
||||
pdch->rcv_block(data_msg, 42, *fn, &meas);
|
||||
|
||||
/* check the status of the block */
|
||||
OSMO_ASSERT(block->block_status_ul == EGPRS_RESEG_DEFAULT);
|
||||
|
||||
return ul_tbf;
|
||||
}
|
||||
|
||||
static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts,
|
||||
uint8_t ts_no, uint32_t tlli, uint32_t *fn, uint16_t qta,
|
||||
uint8_t ms_class, uint8_t egprs_ms_class)
|
||||
|
@ -632,6 +812,8 @@ static gprs_rlcmac_ul_tbf *establish_ul_tbf_two_phase(BTS *the_bts,
|
|||
RlcMacUplink_t ulreq = {0};
|
||||
struct pcu_l1_meas meas;
|
||||
meas.set_rssi(31);
|
||||
struct gprs_rlc_ul_header_egprs_3 *egprs3 = NULL;
|
||||
GprsCodingScheme cs;
|
||||
|
||||
bts = the_bts->bts_data();
|
||||
|
||||
|
@ -1179,6 +1361,41 @@ static void test_tbf_ws()
|
|||
gprs_bssgp_destroy();
|
||||
}
|
||||
|
||||
static void test_tbf_egprs_two_phase_spb(void)
|
||||
{
|
||||
BTS the_bts;
|
||||
int ts_no = 7;
|
||||
uint32_t fn = 2654218;
|
||||
uint16_t qta = 31;
|
||||
uint32_t tlli = 0xf1223344;
|
||||
const char *imsi = "0011223344";
|
||||
uint8_t ms_class = 1;
|
||||
uint8_t egprs_ms_class = 1;
|
||||
gprs_rlcmac_ul_tbf *ul_tbf;
|
||||
GprsMs *ms;
|
||||
uint8_t test_data[256];
|
||||
|
||||
printf("=== start %s ===\n", __func__);
|
||||
|
||||
memset(test_data, 1, sizeof(test_data));
|
||||
|
||||
setup_bts(&the_bts, ts_no, 4);
|
||||
the_bts.bts_data()->initial_mcs_dl = 9;
|
||||
the_bts.bts_data()->egprs_enabled = 1;
|
||||
|
||||
ul_tbf = establish_ul_tbf_two_phase_spb(&the_bts, ts_no, tlli, &fn, qta,
|
||||
ms_class, egprs_ms_class);
|
||||
|
||||
ms = ul_tbf->ms();
|
||||
fprintf(stderr, "Got '%s', TA=%d\n", ul_tbf->name(), ul_tbf->ta());
|
||||
fprintf(stderr,
|
||||
"Got MS: TLLI = 0x%08x, TA = %d\n", ms->tlli(), ms->ta());
|
||||
|
||||
send_dl_data(&the_bts, tlli, imsi, test_data, sizeof(test_data));
|
||||
|
||||
printf("=== end %s ===\n", __func__);
|
||||
}
|
||||
|
||||
static void test_tbf_egprs_two_phase()
|
||||
{
|
||||
BTS the_bts;
|
||||
|
@ -1272,6 +1489,354 @@ static void establish_and_use_egprs_dl_tbf(BTS *the_bts, int mcs)
|
|||
tbf_free(dl_tbf);
|
||||
}
|
||||
|
||||
static gprs_rlcmac_dl_tbf *tbf_init(BTS *the_bts,
|
||||
int mcs)
|
||||
{
|
||||
unsigned i;
|
||||
uint8_t ms_class = 11;
|
||||
uint8_t egprs_ms_class = 11;
|
||||
uint32_t fn = 0;
|
||||
uint8_t trx_no;
|
||||
uint32_t tlli = 0xffeeddcc;
|
||||
uint8_t test_data[512];
|
||||
|
||||
uint8_t rbb[64/8];
|
||||
|
||||
gprs_rlcmac_dl_tbf *dl_tbf;
|
||||
|
||||
memset(test_data, 1, sizeof(test_data));
|
||||
the_bts->bts_data()->initial_mcs_dl = mcs;
|
||||
|
||||
dl_tbf = create_dl_tbf(the_bts, ms_class, egprs_ms_class, &trx_no);
|
||||
dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
|
||||
|
||||
for (i = 0; i < sizeof(test_data); i++)
|
||||
test_data[i] = i%256;
|
||||
|
||||
OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
|
||||
|
||||
/* Schedule a LLC frame
|
||||
* passing only 100 bytes, since it is enough to construct
|
||||
* 2 RLC data blocks. Which are enough to test Header Type 1
|
||||
* cases
|
||||
*/
|
||||
dl_tbf->append_data(ms_class, 1000, test_data, 100);
|
||||
|
||||
OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_FLOW));
|
||||
|
||||
return dl_tbf;
|
||||
|
||||
}
|
||||
|
||||
static void tbf_cleanup(gprs_rlcmac_dl_tbf *dl_tbf)
|
||||
{
|
||||
uint32_t fn = 0;
|
||||
uint8_t rbb[64/8];
|
||||
|
||||
/* Receive a final ACK */
|
||||
dl_tbf->rcvd_dl_ack(1, dl_tbf->m_window.v_s(), rbb);
|
||||
|
||||
/* Clean up and ensure tbfs are in the correct state */
|
||||
OSMO_ASSERT(dl_tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE));
|
||||
dl_tbf->dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
|
||||
check_tbf(dl_tbf);
|
||||
tbf_free(dl_tbf);
|
||||
|
||||
}
|
||||
|
||||
static void establish_and_use_egprs_dl_tbf_for_spb(BTS *the_bts,
|
||||
int mcs, int demanded_mcs)
|
||||
{
|
||||
uint32_t fn = 0;
|
||||
gprs_rlcmac_dl_tbf *dl_tbf;
|
||||
uint8_t block_nr = 0;
|
||||
int index1 = 0;
|
||||
uint8_t bn;
|
||||
struct msgb *msg;
|
||||
struct gprs_rlc_dl_header_egprs_3 *egprs3;
|
||||
|
||||
printf("Testing retx for MCS %d to reseg_mcs %d\n", mcs, demanded_mcs);
|
||||
|
||||
/* Table 10.4.8a.3.1 of 44.060 */
|
||||
dl_tbf = tbf_init(the_bts, mcs);
|
||||
if (((mcs == 5) && (demanded_mcs == 2)) ||
|
||||
((mcs == 6) && (demanded_mcs == 3)) ||
|
||||
((mcs == 4) && (demanded_mcs == 1))) {
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Send first RLC data block BSN 0 */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
|
||||
dl_tbf->m_window.m_v_b.mark_nacked(0);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0));
|
||||
|
||||
dl_tbf->ms()->set_current_cs_dl
|
||||
((GprsCodingScheme::Scheme)(GprsCodingScheme::CS4 +
|
||||
demanded_mcs));
|
||||
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
|
||||
/* Send first segment with demanded_mcs */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== demanded_mcs);
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->block_status_dl
|
||||
== EGPRS_RESEG_FIRST_SEG_SENT);
|
||||
|
||||
egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data;
|
||||
OSMO_ASSERT(egprs3->spb == 2);
|
||||
|
||||
/* Table 10.4.8a.3.1 of 44.060 */
|
||||
switch (demanded_mcs) {
|
||||
case 3:
|
||||
OSMO_ASSERT(egprs3->cps == 3);
|
||||
break;
|
||||
case 2:
|
||||
OSMO_ASSERT(egprs3->cps == 9);
|
||||
break;
|
||||
case 1:
|
||||
OSMO_ASSERT(egprs3->cps == 11);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Send second segment with demanded_mcs */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== demanded_mcs);
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->block_status_dl
|
||||
== EGPRS_RESEG_SECOND_SEG_SENT);
|
||||
|
||||
egprs3 = (struct gprs_rlc_dl_header_egprs_3 *) msg->data;
|
||||
/* Table 10.4.8a.3.1 of 44.060 */
|
||||
OSMO_ASSERT(egprs3->spb == 3);
|
||||
|
||||
/* Table 10.4.8a.3.1 of 44.060 */
|
||||
switch (demanded_mcs) {
|
||||
case 3:
|
||||
OSMO_ASSERT(egprs3->cps == 3);
|
||||
break;
|
||||
case 2:
|
||||
OSMO_ASSERT(egprs3->cps == 9);
|
||||
break;
|
||||
case 1:
|
||||
OSMO_ASSERT(egprs3->cps == 11);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
tbf_cleanup(dl_tbf);
|
||||
}
|
||||
}
|
||||
|
||||
static void establish_and_use_egprs_dl_tbf_for_retx(BTS *the_bts,
|
||||
int mcs, int demanded_mcs)
|
||||
{
|
||||
uint32_t fn = 0;
|
||||
gprs_rlcmac_dl_tbf *dl_tbf;
|
||||
uint8_t block_nr = 0;
|
||||
int index1 = 0;
|
||||
uint8_t bn;
|
||||
struct msgb *msg;
|
||||
|
||||
printf("Testing retx for MCS %d - %d\n", mcs, demanded_mcs);
|
||||
|
||||
dl_tbf = tbf_init(the_bts, mcs);
|
||||
|
||||
/* For MCS reduction cases like MCS9->MCS6, MCS7->MCS5
|
||||
* The MCS transition are referred from table Table 8.1.1.2
|
||||
* of TS 44.060
|
||||
*/
|
||||
/* TODO: Need to support of MCS8 -> MCS6 transistion */
|
||||
if (((mcs == 9) && (demanded_mcs < 9)) ||
|
||||
((mcs == 7) && (demanded_mcs < 7))) {
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Send 2 RLC data block */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(1));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(1)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
|
||||
dl_tbf->m_window.m_v_b.mark_nacked(0);
|
||||
dl_tbf->m_window.m_v_b.mark_nacked(1);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(1));
|
||||
|
||||
/* Set the demanded MCS to demanded_mcs */
|
||||
dl_tbf->ms()->set_current_cs_dl
|
||||
((GprsCodingScheme::Scheme)(GprsCodingScheme::CS4 +
|
||||
demanded_mcs));
|
||||
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Retransmit the first RLC data block with demanded_mcs */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(1));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== demanded_mcs);
|
||||
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Retransmit the second RLC data block with demanded_mcs */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(1));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(1)->cs_current_trans.to_num()
|
||||
== demanded_mcs);
|
||||
} else if (((mcs == 5) && (demanded_mcs > 6)) ||
|
||||
((mcs == 6) && (demanded_mcs > 8))) {
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Send first RLC data block BSN 0 */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Send second RLC data block BSN 1 */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(1));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(1)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
|
||||
dl_tbf->m_window.m_v_b.mark_nacked(0);
|
||||
dl_tbf->m_window.m_v_b.mark_nacked(1);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(1));
|
||||
|
||||
dl_tbf->ms()->set_current_cs_dl
|
||||
((GprsCodingScheme::Scheme)(GprsCodingScheme::CS4 +
|
||||
demanded_mcs));
|
||||
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Send first, second RLC data blocks with demanded_mcs */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(1));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== demanded_mcs);
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(1)->cs_current_trans.to_num()
|
||||
== demanded_mcs);
|
||||
} else if (mcs > 6) {
|
||||
/* No Mcs change cases are handled here for mcs > MCS6*/
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Send first,second RLC data blocks */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(1));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(1)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
|
||||
dl_tbf->m_window.m_v_b.mark_nacked(0);
|
||||
dl_tbf->m_window.m_v_b.mark_nacked(1);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(1));
|
||||
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Send first,second RLC data blocks with demanded_mcs*/
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(1));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(1)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
} else {
|
||||
|
||||
/* No MCS change cases are handled here for mcs <= MCS6*/
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Send first RLC data block */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
|
||||
dl_tbf->m_window.m_v_b.mark_nacked(0);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_nacked(0));
|
||||
|
||||
fn = fn_add_blocks(fn, 1);
|
||||
/* Send first RLC data block with demanded_mcs */
|
||||
msg = dl_tbf->create_dl_acked_block(fn, dl_tbf->control_ts);
|
||||
OSMO_ASSERT(dl_tbf->m_window.m_v_b.is_unacked(0));
|
||||
OSMO_ASSERT(dl_tbf->m_rlc.block(0)->cs_current_trans.to_num()
|
||||
== mcs);
|
||||
}
|
||||
|
||||
tbf_cleanup(dl_tbf);
|
||||
}
|
||||
|
||||
static void test_tbf_egprs_retx_dl(void)
|
||||
{
|
||||
BTS the_bts;
|
||||
gprs_rlcmac_bts *bts;
|
||||
uint8_t ts_no = 4;
|
||||
int i, j;
|
||||
|
||||
printf("=== start %s ===\n", __func__);
|
||||
|
||||
bts = the_bts.bts_data();
|
||||
bts->cs_downgrade_threshold = 0;
|
||||
setup_bts(&the_bts, ts_no);
|
||||
bts->dl_tbf_idle_msec = 200;
|
||||
bts->egprs_enabled = 1;
|
||||
|
||||
/* ARQ II */
|
||||
bts->arq_type = 1;
|
||||
|
||||
/* First parameter is current MCS, second one is demanded_mcs */
|
||||
establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 6);
|
||||
establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 1, 9);
|
||||
establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 2, 8);
|
||||
establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 5, 7);
|
||||
establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 6, 9);
|
||||
establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 7, 5);
|
||||
establish_and_use_egprs_dl_tbf_for_retx(&the_bts, 9, 6);
|
||||
|
||||
printf("=== end %s ===\n", __func__);
|
||||
}
|
||||
|
||||
static void test_tbf_egprs_spb_dl(void)
|
||||
{
|
||||
BTS the_bts;
|
||||
gprs_rlcmac_bts *bts;
|
||||
uint8_t ts_no = 4;
|
||||
int i, j;
|
||||
|
||||
printf("=== start %s ===\n", __func__);
|
||||
|
||||
bts = the_bts.bts_data();
|
||||
bts->cs_downgrade_threshold = 0;
|
||||
setup_bts(&the_bts, ts_no);
|
||||
bts->dl_tbf_idle_msec = 200;
|
||||
bts->egprs_enabled = 1;
|
||||
|
||||
/* ARQ I resegmentation support */
|
||||
bts->arq_type = 0;
|
||||
|
||||
/*
|
||||
* First parameter is current MCS, second one is demanded_mcs
|
||||
* currently only MCS5->MCS2, MCS6->3, MCS4->MCS1 is tested in UT
|
||||
* rest scenarios has been integration tested
|
||||
*/
|
||||
establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 6, 3);
|
||||
establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 5, 2);
|
||||
establish_and_use_egprs_dl_tbf_for_spb(&the_bts, 4, 1);
|
||||
|
||||
printf("=== end %s ===\n", __func__);
|
||||
}
|
||||
|
||||
static void test_tbf_egprs_dl()
|
||||
{
|
||||
BTS the_bts;
|
||||
|
@ -1355,7 +1920,10 @@ int main(int argc, char **argv)
|
|||
test_tbf_gprs_egprs();
|
||||
test_tbf_ws();
|
||||
test_tbf_egprs_two_phase();
|
||||
test_tbf_egprs_two_phase_spb();
|
||||
test_tbf_egprs_dl();
|
||||
test_tbf_egprs_retx_dl();
|
||||
test_tbf_egprs_spb_dl();
|
||||
|
||||
if (getenv("TALLOC_REPORT_FULL"))
|
||||
talloc_report_full(tall_pcu_ctx, stderr);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -32,6 +32,8 @@
|
|||
=== end test_tbf_ws ===
|
||||
=== start test_tbf_egprs_two_phase ===
|
||||
=== end test_tbf_egprs_two_phase ===
|
||||
=== start test_tbf_egprs_two_phase_spb ===
|
||||
=== end test_tbf_egprs_two_phase_spb ===
|
||||
=== start test_tbf_egprs_dl ===
|
||||
Testing MCS-1
|
||||
Testing MCS-2
|
||||
|
@ -43,3 +45,17 @@ Testing MCS-7
|
|||
Testing MCS-8
|
||||
Testing MCS-9
|
||||
=== end test_tbf_egprs_dl ===
|
||||
=== start test_tbf_egprs_retx_dl ===
|
||||
Testing retx for MCS 6 - 6
|
||||
Testing retx for MCS 1 - 9
|
||||
Testing retx for MCS 2 - 8
|
||||
Testing retx for MCS 5 - 7
|
||||
Testing retx for MCS 6 - 9
|
||||
Testing retx for MCS 7 - 5
|
||||
Testing retx for MCS 9 - 6
|
||||
=== end test_tbf_egprs_retx_dl ===
|
||||
=== start test_tbf_egprs_spb_dl ===
|
||||
Testing retx for MCS 6 to reseg_mcs 3
|
||||
Testing retx for MCS 5 to reseg_mcs 2
|
||||
Testing retx for MCS 4 to reseg_mcs 1
|
||||
=== end test_tbf_egprs_spb_dl ===
|
||||
|
|
Loading…
Reference in New Issue