add DTX fill frame BTS tests
Add tests TC_tch_sign_l2_fill_frame and TC_tch_sign_l2_fill_frame_dtxd.
TC_tch_sign_l2_fill_frame is already passing and verifies that fill
frames are sent if there is nothing else to transmit on a SDCCH4/SDCCH8,
TCH/H, or TCH/F signalling channel where DTX is disabled for downlink.
TC_tch_sign_l2_fill_frame_dtxd is currently failing. It verifies that
only specific fill frames are sent, as required by GSM 05.08 for TCHF
signalling channels with DTX enabled for downlink. At present, our
implementation generates no fill frames in this case, which is one
piece of the problem described in issue OS#1950.
Change-Id: Id4e0de6e78b62cd408f600a57a28617d91da64af
Related: OS#1950
diff --git a/bts/BTS_Tests.ttcn b/bts/BTS_Tests.ttcn
index fb6137c..890be91 100644
--- a/bts/BTS_Tests.ttcn
+++ b/bts/BTS_Tests.ttcn
@@ -3794,6 +3794,187 @@
f_assert_lapdm('03e00d063505'O, tr_LAPDm_I(0, true, false, 7, 0, '063505'O), "I/7/0");
}
+/***********************************************************************
+ * DTX Related (see GSM 05.08, section 8.3)
+ ***********************************************************************/
+
+/* XXX These functions must be kept in sync with g_AllChannels defined on test_CT. */
+function f_g_chan_is_tchf() runs on ConnHdlr return boolean {
+ return (g_chan_nr == valueof(ts_RslChanNr_Bm(1)) or
+ g_chan_nr == valueof(ts_RslChanNr_Bm(2)) or
+ g_chan_nr == valueof(ts_RslChanNr_Bm(3)) or
+ g_chan_nr == valueof(ts_RslChanNr_Bm(4)));
+}
+function f_g_chan_is_tchh() runs on ConnHdlr return boolean {
+ return (g_chan_nr == valueof(ts_RslChanNr_Lm(5,0)) or
+ g_chan_nr == valueof(ts_RslChanNr_Lm(5,1)));
+}
+function f_g_chan_is_sdcch4() runs on ConnHdlr return boolean {
+ return (g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,0)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,1)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,2)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,3)));
+}
+function f_g_chan_is_sdcch8() runs on ConnHdlr return boolean {
+ return (g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,0)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,1)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,2)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,3)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,4)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,5)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,6)) or
+ g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,7)));
+}
+
+function f_test_l2_fill_frames(boolean dtxd) runs on ConnHdlr {
+ var L1ctlDlMessage dl;
+ var octetstring l2_fill_frame := '0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O;
+ var octetstring l2_fill_frame_sacch := substr(l2_fill_frame, 0, lengthof(l2_fill_frame) - 2);
+ var GsmFrameNumber first_fn;
+ var boolean is_first_frame := true;
+ var integer nfill_frames := 0;
+ const integer dtx_tchf_mod := 104;
+ /* Frames numbers (mod 104) for which a fill frame is expected on TCHF if DTX is enabled. */
+ var Integers required_tdma_frames_dtx_tchf := { 52, 53, 54, 55, 56, 57, 58, 59 };
+ timer T := 5.0;
+
+ f_l1_tune(L1CTL);
+ RSL.clear;
+ L1CTL.clear;
+
+ /* activate TCHF signalling channel */
+ f_est_dchan(false);
+
+ T.start;
+ alt {
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, ?)) -> value dl {
+ var GsmFrameNumber fn := dl.dl_info.frame_nr;
+ var octetstring l2 := dl.payload.data_ind.payload;
+
+ if (is_first_frame) {
+ is_first_frame := false;
+ first_fn := dl.dl_info.frame_nr;
+ }
+
+ if (dl.dl_info.link_id.c == SACCH) {
+ l2 := substr(l2, 2, lengthof(l2) - 2); /* remove L1 header */
+ if (not match(l2_fill_frame_sacch, l2)) {
+ repeat;
+ }
+ } else if (not match(l2_fill_frame, l2)) {
+ repeat;
+ }
+
+ if (dtxd) {
+ if (not f_g_chan_is_tchf()) {
+ T.stop;
+ f_rsl_chan_deact();
+ f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
+ setverdict(fail, "Received fill frame on non-TCH/F channel; DTX is only allowed on TCH/F!");
+ }
+ if (fn >= first_fn + dtx_tchf_mod) {
+ T.stop;
+ f_rsl_chan_deact();
+ f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
+ /* With DTX enabled we can expect at least 1 fill frame every 104 frames. */
+ if (nfill_frames < 1) {
+ setverdict(fail);
+ } else {
+ setverdict(pass);
+ }
+ }
+ for (var integer i := 0; i < lengthof(required_tdma_frames_dtx_tchf); i := i + 1) {
+ if (fn mod dtx_tchf_mod == required_tdma_frames_dtx_tchf[i]) {
+ nfill_frames := nfill_frames + 1;
+ repeat;
+ }
+ }
+ log("Received DTX TCH fill frame with bad frame number: ", fn,
+ " (mod ", dtx_tchf_mod, ": ", fn mod dtx_tchf_mod, ")");
+ f_rsl_chan_deact();
+ f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
+ setverdict(fail, "Unexpected L2 fill frame received on Um");
+ } else {
+ nfill_frames := nfill_frames + 1;
+ if (fn >= first_fn + dtx_tchf_mod) {
+ var integer expected_fill_frames;
+ T.stop;
+ if (f_g_chan_is_tchf()) {
+ /* Without DTX we can expect 25 fill frames for every 104 frames.
+ * (24 FACCH + 1 SACCH filling) */
+ expected_fill_frames := 25;
+ } else if (f_g_chan_is_tchh()) {
+ /* We can expect 2 fill frames for every 104 frames. */
+ expected_fill_frames := 2;
+ } else if (f_g_chan_is_sdcch4() or f_g_chan_is_sdcch8()) {
+ /* We can expect 5 fill frames for every 104 frames. */
+ expected_fill_frames := 5;
+ } else {
+ f_rsl_chan_deact();
+ f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
+ setverdict(fail, "Unknown channel type");
+ }
+
+ f_rsl_chan_deact();
+ f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
+ if (nfill_frames >= expected_fill_frames) {
+ setverdict(pass);
+ } else {
+ setverdict(fail, "Not enough fill frames received");
+ }
+ } else {
+ repeat;
+ }
+ }
+ }
+ [] L1CTL.receive { repeat; }
+ [] T.timeout {
+ f_rsl_chan_deact();
+ f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
+ setverdict(fail, "Timeout waiting for L2 fill frames on Um");
+ mtc.stop;
+ }
+ }
+}
+
+function f_TC_tch_sign_l2_fill_frame(charstring id) runs on ConnHdlr {
+ f_test_l2_fill_frames(false);
+}
+
+function f_TC_tch_sign_l2_fill_frame_dtxd(charstring id) runs on ConnHdlr {
+ f_test_l2_fill_frames(true);
+}
+
+function f_tch_sign_l2_fill_frame(boolean dtxd) runs on test_CT {
+ var ConnHdlr vc_conn;
+ var ConnHdlrPars pars;
+ pars.t_guard := 60.0;
+ f_init(testcasename());
+ for (var integer i := 0; i < sizeof(g_AllChannels); i := i + 1) {
+ pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN(dtxd)));
+ if (dtxd) {
+ if (i >= 4) { /* DTX is only allowed on TCH/F */
+ break;
+ }
+ vc_conn := f_start_handler(refers(f_TC_tch_sign_l2_fill_frame_dtxd), pars);
+ } else {
+ vc_conn := f_start_handler(refers(f_TC_tch_sign_l2_fill_frame), pars);
+ }
+ vc_conn.done;
+ }
+}
+
+/* Verify that L2 fill frames are sent on TCH in signaling mode if
+ * there is nothing to transmit while DTX is disabled on downlink. */
+testcase TC_tch_sign_l2_fill_frame() runs on test_CT {
+ f_tch_sign_l2_fill_frame(false);
+}
+
+/* Verify that particular L2 fill frames are sent on TCH in signaling mode if
+ * there is nothing to transmit while DTX is enabled on downlink. */
+testcase TC_tch_sign_l2_fill_frame_dtxd() runs on test_CT {
+ f_tch_sign_l2_fill_frame(true);
+}
/* test generation of RLL ERR IND based on Um errors (TS 48.058 3.9) */
/* protocol error as per 44.006 */
@@ -3926,6 +4107,9 @@
execute( TC_encr_cmd_a53() );
execute( TC_lapdm_selftest() );
+
+ execute( TC_tch_sign_l2_fill_frame() );
+ execute( TC_tch_sign_l2_fill_frame_dtxd() );
}
diff --git a/bts/expected-results.xml b/bts/expected-results.xml
index d1a65a3..8bfd305 100644
--- a/bts/expected-results.xml
+++ b/bts/expected-results.xml
@@ -85,4 +85,11 @@
<testcase classname='BTS_Tests' name='TC_encr_cmd_a52' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_encr_cmd_a53' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_lapdm_selftest' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_tch_sign_l2_fill_frame' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_tch_sign_l2_fill_frame_dtxd' time='MASKED'>
+ <failure type='fail-verdict'>"Unexpected L2 fill frame received on Um"
+ BTS_Tests.ttcn:MASKED BTS_Tests control part
+ BTS_Tests.ttcn:MASKED TC_tch_sign_l2_fill_frame_dtxd testcase
+ </failure>
+ </testcase>
</testsuite>
diff --git a/library/RSL_Types.ttcn b/library/RSL_Types.ttcn
index d4d0c4d..95a7b1f 100644
--- a/library/RSL_Types.ttcn
+++ b/library/RSL_Types.ttcn
@@ -325,20 +325,21 @@
RSL_SpeechAlgo coding_alg_rate
} with { variant (len) "LENGTHTO(reserved,dtx_d,dtx_u,spd_ind,ch_rate_type,coding_alg_rate)" }
- template (value) RSL_IE_ChannelMode ts_RSL_ChanMode_SIGN := {
+ template (value) RSL_IE_ChannelMode ts_RSL_ChanMode_SIGN(boolean dtx_downlink := false) := {
len := 0, /* overwritten */
reserved := '000000'B,
- dtx_d := false,
+ dtx_d := dtx_downlink,
dtx_u := false,
spd_ind := RSL_SPDI_SIGN,
ch_rate_type := RSL_CHRT_SDCCH,
coding_alg_rate := RSL_CMOD_NO_RESOURCE
}
- template (value) RSL_IE_ChannelMode ts_RSL_ChanMode(RSL_ChanRateType t, RSL_SpeechAlgo alg) := {
+ template (value) RSL_IE_ChannelMode ts_RSL_ChanMode(RSL_ChanRateType t, RSL_SpeechAlgo alg,
+ boolean dtx_downlink := false) := {
len := 0, /* overwritten */
reserved := '000000'B,
- dtx_d := false,
+ dtx_d := dtx_downlink,
dtx_u := false,
spd_ind := RSL_SPDI_SPEECH,
ch_rate_type := t,