1121 lines
33 KiB
Plaintext
1121 lines
33 KiB
Plaintext
module BTS_Tests_SMSCB {
|
|
|
|
/* Integration Tests for OsmoBTS
|
|
* (C) 2019 by Harald Welte <laforge@gnumonks.org>
|
|
* All rights reserved.
|
|
*
|
|
* Released under the terms of GNU General Public License, Version 2 or
|
|
* (at your option) any later version.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*
|
|
* This test suite tests the SMSCB (Cell Broadcast) related functionality of
|
|
* OsmoBTS by attaching to the A-bis RSL and Um interface and emulating both
|
|
* BSC and MS.
|
|
*/
|
|
|
|
import from Misc_Helpers all;
|
|
import from General_Types all;
|
|
import from Osmocom_Types all;
|
|
import from GSM_Types all;
|
|
import from L1CTL_PortType all;
|
|
import from L1CTL_Types all;
|
|
import from LAPDm_Types all;
|
|
import from IPA_Emulation all;
|
|
import from GSM_RR_Types all;
|
|
import from L3_Templates all;
|
|
|
|
import from RSL_Types all;
|
|
|
|
import from PCUIF_Types all;
|
|
import from PCUIF_CodecPort all;
|
|
|
|
import from Osmocom_VTY_Functions all;
|
|
|
|
import from BTS_Tests all;
|
|
|
|
/***********************************************************************
|
|
* Cell Broadcast related tests
|
|
***********************************************************************/
|
|
|
|
/* Test parameters for one channel (e.g. Basic, Extended) */
|
|
type record CbchTestParsChan {
|
|
/* list of "normal" (sent-once) SMSCB messages */
|
|
CbchTestMsgs msgs,
|
|
/* default message, if any */
|
|
CbchTestMsg default_msg optional
|
|
}
|
|
|
|
private template (value) CbchTestParsChan
|
|
t_CbchPC(template (value) CbchTestMsgs msgs, template (omit) CbchTestMsg def := omit) := {
|
|
msgs := msgs,
|
|
default_msg := def
|
|
}
|
|
|
|
/* CBCH test parameters for most of our tests */
|
|
type record CbchTestPars {
|
|
/* Should we execute on SDCCH4 or SDCCH8? */
|
|
RslChannelNr chan_nr,
|
|
/* Frequency Hopping parameters */
|
|
FreqHopPars fhp,
|
|
/* Parameters for BASIC CBCH */
|
|
CbchTestParsChan basic,
|
|
/* Parameters for EXTENDED CBCH */
|
|
CbchTestParsChan extended optional
|
|
};
|
|
|
|
type record CbchTestMsg {
|
|
/* config / input data */
|
|
RSL_CbCommand rsl_cb_cmd,
|
|
uint2_t last_block, /* 0..3 */
|
|
octetstring payload,
|
|
/* computed / result data */
|
|
CbchBlocks blocks optional
|
|
};
|
|
type record of CbchTestMsg CbchTestMsgs;
|
|
|
|
/* a single 22byte block within a CbchTestMsg */
|
|
type record CbchBlock {
|
|
uint4_t seq_nr, /* as per TS 04.12 */
|
|
boolean is_last,
|
|
OCT22 payload,
|
|
boolean seen_once
|
|
};
|
|
type record of CbchBlock CbchBlocks;
|
|
|
|
/* compute the expected blocks for given test parameters */
|
|
private function f_cbch_compute_exp_blocks(inout CbchTestPars pars) {
|
|
f_cbch_compute_exp_blocks_chan(pars.basic);
|
|
if (ispresent(pars.extended)) {
|
|
f_cbch_compute_exp_blocks_chan(pars.extended);
|
|
}
|
|
}
|
|
private function f_cbch_compute_exp_blocks_chan(inout CbchTestParsChan pars_chan) {
|
|
var integer i;
|
|
for (i := 0; i < lengthof(pars_chan.msgs); i := i+1) {
|
|
pars_chan.msgs[i].blocks := f_comp_blocks(pars_chan.msgs[i]);
|
|
}
|
|
if (ispresent(pars_chan.default_msg)) {
|
|
pars_chan.default_msg.blocks := f_comp_blocks(pars_chan.default_msg);
|
|
}
|
|
}
|
|
private function f_comp_blocks(in CbchTestMsg msg) return CbchBlocks {
|
|
var CbchBlocks blocks := {};
|
|
var integer i;
|
|
|
|
for (i := 0; i <= msg.last_block; i := i+1) {
|
|
var CbchBlock block := {
|
|
seq_nr := i,
|
|
is_last := false,
|
|
payload := substr(msg.payload, 22*i, 22),
|
|
seen_once := false
|
|
};
|
|
if (msg.rsl_cb_cmd == RSL_CB_CMD_SCHEDULE and i == 0) {
|
|
block.seq_nr := 8;
|
|
}
|
|
if (i == msg.last_block) {
|
|
block.is_last := true;
|
|
}
|
|
blocks := blocks & {block};
|
|
}
|
|
|
|
return blocks;
|
|
};
|
|
|
|
/* TS 48.058 Section 9.3.41 */
|
|
private function f_cbch_block_nr2rsl(uint2_t nr) return uint2_t {
|
|
select (nr) {
|
|
case (0) { return 1; }
|
|
case (1) { return 2; }
|
|
case (2) { return 3; }
|
|
case (3) { return 0; }
|
|
}
|
|
setverdict(fail, "Invalid block number");
|
|
mtc.stop;
|
|
}
|
|
|
|
private function f_cbch_fn2tb(uint32_t fn) return integer
|
|
{
|
|
return (fn/51) mod 8; /* TS 05.02 Section 6.5.4 */
|
|
}
|
|
|
|
/* Verify the CBCH TB scheduling rules of TS 05.02 Section 6.5.4 */
|
|
private function f_cbch_fn_verify(uint32_t fn, CBCH_Block cb)
|
|
{
|
|
var integer tb := f_cbch_fn2tb(fn);
|
|
if (cb.block_type.seq_nr == 15 /* null */) {
|
|
/* always permitted */
|
|
return;
|
|
} else if (cb.block_type.seq_nr == 8 /* schedule */) {
|
|
if (tb != 0) {
|
|
setverdict(fail, "Schedule block at TB=", tb);
|
|
}
|
|
} else if (cb.block_type.seq_nr < 4) {
|
|
if (cb.block_type.seq_nr != tb and cb.block_type.seq_nr+4 != tb) {
|
|
setverdict(fail, "Normal block at wrong TB=", tb, ": ", cb);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function f_rsl_smscb_default_null() runs on test_CT
|
|
{
|
|
var RSL_IE_CbCommandType cmd_type :=
|
|
valueof(ts_RSL_IE_CbCmdType(RSL_CB_CMD_DEFAULT, 1, true));
|
|
RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_SMSCB_CMD(cmd_type, ''O)));
|
|
}
|
|
|
|
template RSL_IE t_RSL_IE_SMSCB_EXT := t_RSL_IE(RSL_IE_SMSCB_CHAN_INDICATOR, {smscb_chan_ind := 1});
|
|
|
|
private function f_smscb_setup_rsl_chan(inout CbchTestParsChan pars_chan, boolean extd := false)
|
|
runs on test_CT {
|
|
var integer i;
|
|
var CbchTestMsg msg;
|
|
var uint2_t rsl_last_block;
|
|
var RSL_IE_CbCommandType cmd_type;
|
|
var RSL_Message rsl;
|
|
|
|
/* send SMSCB[s] via RSL */
|
|
for (i := 0; i < lengthof(pars_chan.msgs); i := i+1) {
|
|
msg := pars_chan.msgs[i];
|
|
rsl_last_block := f_cbch_block_nr2rsl(msg.last_block);
|
|
cmd_type := valueof(ts_RSL_IE_CbCmdType(msg.rsl_cb_cmd, rsl_last_block));
|
|
rsl := valueof(ts_RSL_SMSCB_CMD(cmd_type, msg.payload));
|
|
if (extd) {
|
|
rsl.ies := rsl.ies & { valueof(t_RSL_IE_SMSCB_EXT) };
|
|
}
|
|
RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
|
|
}
|
|
if (ispresent(pars_chan.default_msg)) {
|
|
msg := pars_chan.default_msg;
|
|
rsl_last_block := f_cbch_block_nr2rsl(msg.last_block);
|
|
cmd_type := valueof(ts_RSL_IE_CbCmdType(msg.rsl_cb_cmd, rsl_last_block, false));
|
|
rsl := valueof(ts_RSL_SMSCB_CMD(cmd_type, msg.payload));
|
|
if (extd) {
|
|
rsl.ies := rsl.ies & { valueof(t_RSL_IE_SMSCB_EXT) };
|
|
}
|
|
RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
|
|
}
|
|
}
|
|
|
|
private function f_vty_cbch_setup(in RslChannelNr chan_nr) runs on test_CT {
|
|
|
|
if (match(chan_nr, t_RslChanNr_CBCH4(0))) {
|
|
f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0", "timeslot 0"},
|
|
"phys_chan_config CCCH+SDCCH4+CBCH");
|
|
/* (Re)configure timeslots 1..3 as TCH/F */
|
|
for (var integer tn := 1; tn <= 3; tn := tn + 1) {
|
|
f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0",
|
|
"timeslot " & int2str(tn) },
|
|
"phys_chan_config TCH/F");
|
|
}
|
|
} else if (match(chan_nr, t_RslChanNr_CBCH8(?))) {
|
|
f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0", "timeslot 0"},
|
|
"phys_chan_config CCCH+SDCCH4");
|
|
f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0",
|
|
"timeslot " & int2str(chan_nr.tn) },
|
|
"phys_chan_config SDCCH8+CBCH");
|
|
|
|
/* (Re)configure timeslots 1..3 (excluding the given one) as TCH/F */
|
|
for (var integer tn := 1; tn <= 3; tn := tn + 1) {
|
|
if (tn == chan_nr.tn)
|
|
{ continue; }
|
|
f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0",
|
|
"timeslot " & int2str(tn) },
|
|
"phys_chan_config TCH/F");
|
|
}
|
|
}
|
|
f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
|
|
f_sleep(2.0);
|
|
}
|
|
private function f_smscb_setup(inout CbchTestPars pars) runs on test_CT {
|
|
/* Make sure we've got either SDCCH4+CBCH or SDCCH8+CBCH.
|
|
* SDCCH4+CBCH can only be allocated on TS0, SDCCH8+CBCH on TS0..3.
|
|
* On C0 the first timeslot shall always transmit BCCH, thus TS1..3.*/
|
|
if (not match(pars.chan_nr, (t_RslChanNr_CBCH4(0), t_RslChanNr_CBCH8(1),
|
|
t_RslChanNr_CBCH8(2), t_RslChanNr_CBCH8(3)))) {
|
|
setverdict(inconc, "Unhandled channel number: ", pars.chan_nr);
|
|
mtc.stop;
|
|
}
|
|
|
|
/* Obtain frequency hopping parameters for a given timeslot */
|
|
if (mp_freq_hop_enabled and mp_transceiver_num > 1)
|
|
{ f_resolve_fh_params(pars.fhp, pars.chan_nr.tn); }
|
|
else
|
|
{ pars.fhp.enabled := false; }
|
|
|
|
f_cbch_compute_exp_blocks(pars);
|
|
|
|
f_init_vty_bsc();
|
|
/* ensure that a CBCH is present in channel combination */
|
|
f_vty_cbch_setup(pars.chan_nr);
|
|
f_init();
|
|
|
|
f_init_l1ctl();
|
|
|
|
/* Tune L1 to the given CBCH timeslot (SDCCH4+CBCH or SDCCH8+CBCH) */
|
|
if (match(pars.chan_nr, t_RslChanNr_CBCH4(0))) {
|
|
f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH);
|
|
} else {
|
|
f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED);
|
|
|
|
if (pars.fhp.enabled) {
|
|
L1CTL.send(ts_L1CTL_DM_EST_REQ_H1(pars.chan_nr,
|
|
7 /* TODO: mp_tsc */,
|
|
pars.fhp.maio_hsn.hsn,
|
|
pars.fhp.maio_hsn.maio,
|
|
pars.fhp.ma));
|
|
} else {
|
|
L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(pars.chan_nr,
|
|
7 /* TODO: mp_tsc */,
|
|
mp_trx0_arfcn));
|
|
}
|
|
}
|
|
|
|
/* send SMSCB[s] via RSL */
|
|
f_smscb_setup_rsl_chan(pars.basic, false);
|
|
if (ispresent(pars.extended)) {
|
|
f_smscb_setup_rsl_chan(pars.extended, true);
|
|
}
|
|
}
|
|
|
|
/* construct a receive/match template for given block_nr in given msg */
|
|
private function f_get_block_template(CbchTestMsg msg, integer block_nr) return template CBCH_Block {
|
|
var template CBCH_Block tr;
|
|
if (block_nr < lengthof(msg.blocks)) {
|
|
var CbchBlock b := msg.blocks[block_nr];
|
|
tr := tr_CBCH_Block(b.seq_nr, b.is_last, b.payload);
|
|
} else {
|
|
tr := tr_CBCH_Block(15, ?, ?);
|
|
}
|
|
return tr;
|
|
}
|
|
|
|
/* the heart of the CBCH test case matching engine for one channel (basic, extended) */
|
|
private function f_cbch_match(inout CbchTestParsChan pars_chan, CBCH_Block cb, integer tb)
|
|
{
|
|
var integer block_nr := tb mod 4;
|
|
var integer i;
|
|
|
|
if (not match(cb, tr_CBCH_Block)) {
|
|
setverdict(fail, "Illegal CBCH Block received: ", cb);
|
|
} else {
|
|
var boolean matched := false;
|
|
/* check if it's any of our expected blocks */
|
|
for (i := 0; i < lengthof(pars_chan.msgs); i := i+1) {
|
|
if (block_nr < lengthof(pars_chan.msgs[i].blocks)) {
|
|
if (match(cb, f_get_block_template(pars_chan.msgs[i], block_nr))) {
|
|
log("Found block_nr ", block_nr, " of msg ", i);
|
|
if (not pars_chan.msgs[i].blocks[block_nr].seen_once) {
|
|
pars_chan.msgs[i].blocks[block_nr].seen_once := true;
|
|
setverdict(pass);
|
|
} else {
|
|
setverdict(fail, "Received SMSCB twice! ", cb);
|
|
}
|
|
matched := true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (not matched) {
|
|
var template CBCH_Block tr;
|
|
if (ispresent(pars_chan.default_msg)) {
|
|
/* it must be a block of the default message */
|
|
tr := f_get_block_template(pars_chan.default_msg, block_nr);
|
|
} else {
|
|
/* it must be a NULL block */
|
|
tr := tr_CBCH_Block(15, ?, ?);
|
|
}
|
|
if (not match(cb, tr)) {
|
|
setverdict(fail, "Received unexpected CBCH block: ", cb);
|
|
} else {
|
|
log("Found block_nr ", block_nr, " of DEFAULT/NULL");
|
|
if (ispresent(pars_chan.default_msg) and
|
|
block_nr < lengthof(pars_chan.default_msg.blocks)) {
|
|
pars_chan.default_msg.blocks[block_nr].seen_once := true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Report/Evaluate the per-channel CBCH test results */
|
|
private function f_cbch_report(CbchTestParsChan pars_chan, charstring id)
|
|
{
|
|
var integer i, j;
|
|
|
|
/* verify that each block of each message has been seen once */
|
|
for (i := 0; i < lengthof(pars_chan.msgs); i := i+1) {
|
|
for (j := 0; j < lengthof(pars_chan.msgs[i].blocks); j := j+1) {
|
|
var CbchBlock b := pars_chan.msgs[i].blocks[j];
|
|
if (not b.seen_once) {
|
|
setverdict(fail, "Timeout waiting for ", id, " CBCH block ",
|
|
j, " of msg ", i);
|
|
}
|
|
}
|
|
}
|
|
if (ispresent(pars_chan.default_msg)) {
|
|
/* verify that each block of default message has been seen at least once */
|
|
for (j := 0; j < lengthof(pars_chan.default_msg.blocks); j := j+1) {
|
|
var CbchBlock b := pars_chan.default_msg.blocks[j];
|
|
if (not b.seen_once) {
|
|
setverdict(fail, "Timeout waiting for at leaset one instance of ",
|
|
"CBCH block ", j, " of DEFAULT msg");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* shared function doing the heavy lifting for most CBCH tests */
|
|
private function f_TC_smscb(CbchTestPars pars) runs on test_CT {
|
|
var L1ctlDlMessage dl;
|
|
var integer msg_count;
|
|
timer T;
|
|
|
|
msg_count := lengthof(pars.basic.msgs);
|
|
if (ispresent(pars.basic.default_msg)) {
|
|
msg_count := msg_count + 1;
|
|
}
|
|
if (ispresent(pars.extended)) {
|
|
msg_count := msg_count + lengthof(pars.extended.msgs);
|
|
if (ispresent(pars.extended.default_msg)) {
|
|
msg_count := msg_count + 1;
|
|
}
|
|
}
|
|
|
|
f_smscb_setup(pars);
|
|
|
|
/* dynamically adjust timeout based on number of messages */
|
|
T.start(5.0 + 3.0 * int2float(msg_count));
|
|
/* Expect this to show up exactly once on the basic CBCH (four blocks) */
|
|
alt {
|
|
[] L1CTL.receive(tr_L1CTL_DATA_IND(pars.chan_nr)) -> value dl {
|
|
var integer tb := f_cbch_fn2tb(dl.dl_info.frame_nr);
|
|
var CBCH_Block cb := dec_CBCH_Block(dl.payload.data_ind.payload);
|
|
log("Tb=", tb, ", CBCH: ", dl, ", block: ", cb);
|
|
|
|
/* detect the proper CBCH messages; check frame number */
|
|
f_cbch_fn_verify(dl.dl_info.frame_nr, cb);
|
|
|
|
if (tb < 4) {
|
|
f_cbch_match(pars.basic, cb, tb);
|
|
} else {
|
|
if (not ispresent(pars.extended)) {
|
|
/* no parameters for ext. BCCH given: ignore */
|
|
repeat;
|
|
}
|
|
f_cbch_match(pars.extended, cb, tb);
|
|
}
|
|
repeat;
|
|
}
|
|
[] L1CTL.receive { repeat; }
|
|
[] T.timeout {
|
|
f_cbch_report(pars.basic, "Basic");
|
|
if (ispresent(pars.extended)) {
|
|
f_cbch_report(pars.extended, "Extended");
|
|
}
|
|
}
|
|
}
|
|
|
|
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass);
|
|
}
|
|
|
|
private function f_TC_smscb_default_only(CbchTestPars pars) runs on test_CT {
|
|
var L1ctlDlMessage dl;
|
|
timer T := 5.0;
|
|
|
|
f_smscb_setup(pars);
|
|
|
|
/* ensure whatever initial NULL messages have all been drained */
|
|
f_sleep(5.0);
|
|
L1CTL.clear;
|
|
|
|
T.start;
|
|
alt {
|
|
[] L1CTL.receive(tr_L1CTL_DATA_IND(pars.chan_nr)) -> value dl {
|
|
var integer tb := f_cbch_fn2tb(dl.dl_info.frame_nr);
|
|
log("CBCH: ", dl);
|
|
var CBCH_Block cb := dec_CBCH_Block(dl.payload.data_ind.payload);
|
|
/* detect the proper CBCH messages; check frame number */
|
|
f_cbch_fn_verify(dl.dl_info.frame_nr, cb);
|
|
if (tb >= 4) {
|
|
/* skip extended CBCH for now */
|
|
repeat;
|
|
}
|
|
if (not match(cb, tr_CBCH_Block)) {
|
|
setverdict(fail, "Illegal CBCH Block received: ", cb);
|
|
} else {
|
|
var uint4_t rx_seq_nr := cb.block_type.seq_nr;
|
|
var template CBCH_Block tr;
|
|
if (rx_seq_nr < lengthof(pars.basic.msgs[0].blocks)) {
|
|
var CbchBlock b := pars.basic.msgs[0].blocks[rx_seq_nr];
|
|
tr := tr_CBCH_Block(b.seq_nr, b.is_last, b.payload);
|
|
} else {
|
|
tr := tr_CBCH_Block(15, ?, ?);
|
|
}
|
|
if (match(cb, tr)) {
|
|
setverdict(pass); /* FIXME: check that all blocks are received? */
|
|
repeat;
|
|
} else {
|
|
setverdict(fail, "Unexpected CBCH block ", cb, ", expected ", tr);
|
|
}
|
|
}
|
|
}
|
|
[] L1CTL.receive { repeat; }
|
|
[] T.timeout {}
|
|
}
|
|
|
|
/* don't shut down; some tests still want to continue */
|
|
}
|
|
|
|
private const CbchTestMsgs msgs_1m_1b_norm := {
|
|
{ RSL_CB_CMD_NORMAL, 0, '001000320f1141660c344dd3cba09a0c000000000000'O, omit }
|
|
}
|
|
|
|
private const CbchTestMsgs msgs_1m_2b_norm := {
|
|
{ RSL_CB_CMD_NORMAL, 1, '001000320f1141660c344dd3cba09a0c000000000000'O &
|
|
'000102030405060708090a0b0c0d0e0f101213141516'O,
|
|
omit }
|
|
}
|
|
|
|
private const CbchTestMsgs msgs_1m_3b_norm := {
|
|
{ RSL_CB_CMD_NORMAL, 2, '001000320f1141660c344dd3cba09a0c000000000000'O &
|
|
'000102030405060708090a0b0c0d0e0f101213141516'O &
|
|
'101112131415161718191a1b1c1d1e1f202223242526'O,
|
|
omit }
|
|
}
|
|
|
|
private const CbchTestMsgs msgs_1m_4b_norm := {
|
|
{ RSL_CB_CMD_NORMAL, 3, '001000320f1141660c344dd3cba09a0c000000000000'O &
|
|
'000102030405060708090a0b0c0d0e0f101213141516'O &
|
|
'101112131415161718191a1b1c1d1e1f202223242526'O &
|
|
'202122232425262728292a2b2c2d2e2f303233343536'O,
|
|
omit }
|
|
}
|
|
|
|
private const CbchTestMsgs msgs_1m_4b_sched := {
|
|
{ RSL_CB_CMD_SCHEDULE, 3, '001000320f1141660c344dd3cba09a0c000000000000'O &
|
|
'000102030405060708090a0b0c0d0e0f101213141516'O &
|
|
'101112131415161718191a1b1c1d1e1f202223242526'O &
|
|
'202122232425262728292a2b2c2d2e2f303233343536'O,
|
|
omit }
|
|
}
|
|
|
|
private const CbchTestMsgs msgs_3m_4b_norm := {
|
|
{ RSL_CB_CMD_NORMAL, 3, '001000320f1141660c344dd3cba09a0c000000000000'O &
|
|
'000102030405060708090a0b0c0d0e0f101213141516'O &
|
|
'101112131415161718191a1b1c1d1e1f202223242526'O &
|
|
'201122232425262728292a2b2c2d2e2f303233343536'O,
|
|
omit },
|
|
{ RSL_CB_CMD_NORMAL, 3, '002000320f1141660c344dd3cba09a0c000000000000'O &
|
|
'002102030405060708090a0b0c0d0e0f101213141516'O &
|
|
'102112131415161718191a1b1c1d1e1f202223242526'O &
|
|
'202122232425262728292a2b2c2d2e2f303233343536'O,
|
|
omit },
|
|
{ RSL_CB_CMD_NORMAL, 3, '003000320f1141660c344dd3cba09a0c000000000000'O &
|
|
'003102030405060708090a0b0c0d0e0f101213141516'O &
|
|
'103112131415161718191a1b1c1d1e1f202223242526'O &
|
|
'203122232425262728292a2b2c2d2e2f303233343536'O,
|
|
omit }
|
|
}
|
|
|
|
private const CbchTestMsgs msgs_1m_3b_default := {
|
|
{ RSL_CB_CMD_DEFAULT, 2, '001000320f1141660c344dd3cba09a0c000000000000'O &
|
|
'000102030405060708090a0b0c0d0e0f101213141516'O &
|
|
'101112131415161718191a1b1c1d1e1f202223242526'O,
|
|
omit }
|
|
}
|
|
private const CbchTestMsg msg_default := {
|
|
RSL_CB_CMD_DEFAULT, 0, '010203040506070708090a0b0c0d0e0f101112131415'O,
|
|
omit
|
|
}
|
|
|
|
/* transmit single-block SMSCB COMMAND */
|
|
testcase TC_sms_cb_cmd_sdcch4_1block() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_1b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
testcase TC_sms_cb_cmd_sdcch8_1block() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
|
|
basic := valueof(t_CbchPC(msgs_1m_1b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
|
|
/* transmit dual-block SMSCB COMMAND */
|
|
testcase TC_sms_cb_cmd_sdcch4_2block() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_2b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
testcase TC_sms_cb_cmd_sdcch8_2block() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
|
|
basic := valueof(t_CbchPC(msgs_1m_2b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
|
|
/* transmit triple-block SMSCB COMMAND */
|
|
testcase TC_sms_cb_cmd_sdcch4_3block() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_3b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
testcase TC_sms_cb_cmd_sdcch8_3block() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
|
|
basic := valueof(t_CbchPC(msgs_1m_3b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
|
|
/* transmit quad-block SMSCB COMMAND */
|
|
testcase TC_sms_cb_cmd_sdcch4_4block() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_4b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
testcase TC_sms_cb_cmd_sdcch8_4block() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
|
|
basic := valueof(t_CbchPC(msgs_1m_4b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
|
|
/* transmit multiple commands of each 4 blocks */
|
|
testcase TC_sms_cb_cmd_sdcch4_multi() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_3m_4b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
testcase TC_sms_cb_cmd_sdcch8_multi() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
|
|
basic := valueof(t_CbchPC(msgs_3m_4b_norm)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
|
|
/* transmit multiple commands of each 4 blocks on CBCH EXTD */
|
|
testcase TC_sms_cb_cmd_sdcch4_extd_multi() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC({})),
|
|
extended := valueof(t_CbchPC(msgs_3m_4b_norm))
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
testcase TC_sms_cb_cmd_sdcch8_extd_multi() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
|
|
basic := valueof(t_CbchPC({})),
|
|
extended := valueof(t_CbchPC(msgs_3m_4b_norm))
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
|
|
/* transmit SMSCB COMMAND with SCHEDULE payload */
|
|
testcase TC_sms_cb_cmd_sdcch4_schedule() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_4b_sched)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
testcase TC_sms_cb_cmd_sdcch8_schedule() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
|
|
basic := valueof(t_CbchPC(msgs_1m_4b_sched)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
|
|
/* set a DEFAULT message; verify it gets transmitted all the time */
|
|
testcase TC_sms_cb_cmd_sdcch4_default_only() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_3b_default)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb_default_only(pars);
|
|
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass);
|
|
}
|
|
testcase TC_sms_cb_cmd_sdcch8_default_only() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_3b_default)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb_default_only(pars);
|
|
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass);
|
|
}
|
|
|
|
testcase TC_sms_cb_cmd_sdcch4_default_and_normal() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_3b_norm, msg_default)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
testcase TC_sms_cb_cmd_sdcch8_default_and_normal() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
|
|
basic := valueof(t_CbchPC(msgs_1m_3b_norm, msg_default)),
|
|
extended := omit
|
|
};
|
|
f_TC_smscb(pars);
|
|
}
|
|
|
|
/* first set a DEFAULT message, then disable it again */
|
|
testcase TC_sms_cb_cmd_sdcch4_default_then_null() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_3b_default)),
|
|
extended := omit
|
|
};
|
|
var template RslChannelNr t_chan_nr := t_RslChanNr_CBCH4(0);
|
|
var L1ctlDlMessage dl;
|
|
timer T := 5.0;
|
|
|
|
f_TC_smscb_default_only(pars);
|
|
|
|
/* disable DEFAULT message; switch back to NULL */
|
|
f_rsl_smscb_default_null();
|
|
|
|
/* ensure whatever initial non-NULL messages have all been drained */
|
|
f_sleep(5.0);
|
|
L1CTL.clear;
|
|
|
|
T.start;
|
|
alt {
|
|
[] L1CTL.receive(tr_L1CTL_DATA_IND(t_chan_nr)) -> value dl {
|
|
log("CBCH: ", dl);
|
|
var CBCH_Block cb := dec_CBCH_Block(dl.payload.data_ind.payload);
|
|
/* detect the proper CBCH messages; check frame number */
|
|
f_cbch_fn_verify(dl.dl_info.frame_nr, cb);
|
|
if (not match(cb, tr_CBCH_Block)) {
|
|
setverdict(fail, "Illegal CBCH Block received: ", cb);
|
|
} else {
|
|
if (not match(cb, tr_CBCH_Block(15, ?, ?))) {
|
|
setverdict(fail, "Unexpected non-NULL CBCH block received");
|
|
}
|
|
repeat;
|
|
}
|
|
}
|
|
[] L1CTL.receive { repeat; }
|
|
[] T.timeout {
|
|
setverdict(pass);
|
|
}
|
|
}
|
|
|
|
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass);
|
|
}
|
|
|
|
/* Verify there are no CBCH load indications if no CBCH is present */
|
|
testcase TC_cbch_load_idle_no_cbch() runs on test_CT {
|
|
var ASP_RSL_Unitdata rx_ud;
|
|
timer T := 10.0;
|
|
|
|
f_init();
|
|
f_init_vty_bsc();
|
|
|
|
T.start;
|
|
alt {
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC)) -> value rx_ud {
|
|
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
|
|
}
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD)) -> value rx_ud {
|
|
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
|
|
}
|
|
[] RSL_CCHAN.receive { repeat; }
|
|
[] T.timeout {
|
|
setverdict(pass);
|
|
}
|
|
}
|
|
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
|
|
}
|
|
|
|
/* Verify the CBCH load indications of an idle cell (without CBCH load) */
|
|
function f_TC_cbc_load_idle() runs on test_CT {
|
|
template integer tr_slot_count := (2 .. 15);
|
|
const integer min_load_ind := 4;
|
|
var integer basic_count := 0;
|
|
var integer extd_count := 0;
|
|
var ASP_RSL_Unitdata rx_ud;
|
|
timer T := 10.0;
|
|
|
|
f_init();
|
|
|
|
RSL_CCHAN.clear;
|
|
T.start;
|
|
alt {
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC(false, tr_slot_count))) {
|
|
basic_count := basic_count + 1;
|
|
repeat;
|
|
}
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD(false, tr_slot_count))) -> value rx_ud {
|
|
extd_count := extd_count + 1;
|
|
repeat;
|
|
}
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC)) -> value rx_ud {
|
|
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
|
|
}
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD)) -> value rx_ud {
|
|
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
|
|
}
|
|
[] RSL_CCHAN.receive { repeat; }
|
|
[] T.timeout {
|
|
if ((basic_count >= min_load_ind) and (extd_count >= min_load_ind)) {
|
|
setverdict(pass);
|
|
} else {
|
|
setverdict(fail, "Insufficient number of CBCH LOAD IND: ",
|
|
"BASIC=", basic_count, " EXTD=", extd_count);
|
|
}
|
|
}
|
|
}
|
|
|
|
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
|
|
}
|
|
testcase TC_cbc_sdcch4_load_idle() runs on test_CT {
|
|
f_init_vty_bsc();
|
|
f_vty_cbch_setup(valueof(ts_RslChanNr_CBCH4(0)));
|
|
f_TC_cbc_load_idle();
|
|
}
|
|
testcase TC_cbc_sdcch8_load_idle() runs on test_CT {
|
|
f_init_vty_bsc();
|
|
f_vty_cbch_setup(valueof(ts_RslChanNr_CBCH8(2)));
|
|
f_TC_cbc_load_idle();
|
|
}
|
|
|
|
/* Verify CBCH overload indications are sent when sending too many SMS CB CMD */
|
|
function f_TC_cbc_load_overload(CbchTestPars pars) runs on test_CT {
|
|
template integer tr_slot_count_basic := (11 .. 13);
|
|
template integer tr_slot_count_extd := (2 .. 15);
|
|
const integer min_load_ind := 4;
|
|
var integer basic_count := 0;
|
|
var integer extd_count := 0;
|
|
var ASP_RSL_Unitdata rx_ud;
|
|
timer T_total := 10.0;
|
|
timer T_retransmit := 0.2;
|
|
timer T_initial_guard := 2.0;
|
|
var integer i;
|
|
|
|
f_init();
|
|
|
|
/* send tons of SMSCB Command */
|
|
for (i := 0; i < 30; i := i+1) {
|
|
f_smscb_setup_rsl_chan(pars.basic);
|
|
}
|
|
|
|
/* keep sending SMSCB Commands for another two seconds */
|
|
T_initial_guard.start;
|
|
T_retransmit.start;
|
|
alt {
|
|
[] T_retransmit.timeout {
|
|
f_smscb_setup_rsl_chan(pars.basic);
|
|
T_retransmit.start;
|
|
repeat;
|
|
}
|
|
[] T_initial_guard.timeout { }
|
|
}
|
|
/* clear any pending messages (where load may not have peaked yet) */
|
|
RSL_CCHAN.clear;
|
|
|
|
/* keep sending SMSCB Commands while verifying LOAD INDICATIONS */
|
|
T_total.start;
|
|
T_retransmit.start;
|
|
alt {
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC(true, tr_slot_count_basic))) {
|
|
basic_count := basic_count + 1;
|
|
repeat;
|
|
}
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD(false, tr_slot_count_extd))) {
|
|
extd_count := extd_count + 1;
|
|
repeat;
|
|
}
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC)) -> value rx_ud {
|
|
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
|
|
}
|
|
[] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD)) -> value rx_ud {
|
|
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
|
|
}
|
|
[] RSL_CCHAN.receive { repeat; }
|
|
[] T_retransmit.timeout {
|
|
f_smscb_setup_rsl_chan(pars.basic);
|
|
T_retransmit.start;
|
|
repeat;
|
|
}
|
|
[] T_total.timeout {
|
|
if ((basic_count >= min_load_ind) and (extd_count >= min_load_ind)) {
|
|
setverdict(pass);
|
|
} else {
|
|
setverdict(fail, "Insufficient number of CBCH LOAD IND: ",
|
|
"BASIC=", basic_count, " EXTD=", extd_count);
|
|
}
|
|
}
|
|
}
|
|
|
|
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
|
|
}
|
|
testcase TC_cbc_sdcch4_load_overload() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
|
|
basic := valueof(t_CbchPC(msgs_1m_3b_norm)),
|
|
extended := omit
|
|
};
|
|
|
|
f_init_vty_bsc();
|
|
f_vty_cbch_setup(pars.chan_nr);
|
|
f_TC_cbc_load_overload(pars);
|
|
}
|
|
testcase TC_cbc_sdcch8_load_overload() runs on test_CT {
|
|
var CbchTestPars pars := {
|
|
chan_nr := valueof(ts_RslChanNr_CBCH4(2)),
|
|
basic := valueof(t_CbchPC(msgs_1m_3b_norm)),
|
|
extended := omit
|
|
};
|
|
|
|
f_init_vty_bsc();
|
|
f_vty_cbch_setup(pars.chan_nr);
|
|
f_TC_cbc_load_overload(pars);
|
|
}
|
|
|
|
|
|
private template GsmRrMessage tr_PagingType1 := {
|
|
header := t_RrHeader(PAGING_REQUEST_TYPE_1, ?),
|
|
payload :=?
|
|
};
|
|
|
|
/* we expect four blocks of 14 bytes, let's fill them with content easily distinguishable */
|
|
const octetstring c_etws_seg0 := '000102030405060708090a0b0c0d'O;
|
|
const octetstring c_etws_seg1 := '101112131415161718191a1b1c1d'O;
|
|
const octetstring c_etws_seg2 := '202122232425262728292a2b2c2d'O;
|
|
const octetstring c_etws_seg3 := '303132333435363738393a3b3c3d'O;
|
|
const octetstring c_etws := c_etws_seg0 & c_etws_seg1 & c_etws_seg2 & c_etws_seg3;
|
|
|
|
/* Ensure only Paging Type 1 with segmented ETWS Primary Notification are sent after RSL_OSMO_ETWS_CMD */
|
|
testcase TC_etws_p1ro() runs on test_CT {
|
|
var template RslChannelNr t_chan_nr := ts_RslChanNr_PCH_AGCH(0);
|
|
/* decoding the actual entire P1 rest octets by manually generated code is
|
|
* too much effort; instead simply do a binary compare to this constant */
|
|
const bitstring c_P1RO_hdr := '00101011101'B;
|
|
var integer seg_received[4] := { 0, 0, 0, 0 };
|
|
var L1ctlDlMessage dl;
|
|
timer T := 10.0;
|
|
|
|
f_init();
|
|
f_init_l1ctl();
|
|
f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH);
|
|
|
|
RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws)));
|
|
/* wait for a bit until old non-ETWS Paging messages are gone */
|
|
f_sleep(1.0);
|
|
L1CTL.clear;
|
|
T.start;
|
|
alt {
|
|
[] L1CTL.receive(tr_L1CTL_DATA_IND(t_chan_nr)) -> value dl {
|
|
var GsmRrMessage l3 := dec_GsmRrMessage(dl.payload.data_ind.payload);
|
|
select (l3) {
|
|
case (tr_PAG_REQ1(tr_MI_LV(t_MI_NoIdentity()))) {
|
|
var octetstring p1ro := l3.payload.pag_req_1.rest_octets;
|
|
var bitstring midamble := oct2bit(substr(p1ro, 0, 3));
|
|
var octetstring segment := substr(p1ro, 3, lengthof(p1ro)-3);
|
|
var BIT1 not_first := substr(midamble, 11, 1);
|
|
var integer seg_nr := bit2int(substr(midamble, 12, 4));
|
|
var boolean err := false;
|
|
if (substr(midamble, 0, 11) != c_P1RO_hdr) {
|
|
setverdict(fail, "Received unexpected P1 RO header ", midamble);
|
|
}
|
|
if (not_first == '1'B) {
|
|
select (seg_nr) {
|
|
case (2) {
|
|
if (segment != c_etws_seg1) {
|
|
err := true
|
|
} else {
|
|
seg_received[1] := seg_received[1] + 1;
|
|
}}
|
|
case (3) {
|
|
if (segment != c_etws_seg2) {
|
|
err := true
|
|
} else {
|
|
seg_received[2] := seg_received[2] + 1;
|
|
}}
|
|
case (4) {
|
|
if (segment != c_etws_seg3) {
|
|
err := true
|
|
} else {
|
|
seg_received[3] := seg_received[3] + 1;
|
|
}}
|
|
case else { setverdict(fail, "Unknown segment Nr ", seg_nr); }
|
|
}
|
|
if (err) {
|
|
setverdict(fail, "Unexpected segment ", seg_nr, ": ", segment);
|
|
}
|
|
} else {
|
|
if (seg_nr != 4) {
|
|
setverdict(fail, "Invalid number of segments ", seg_nr);
|
|
err := true;
|
|
}
|
|
if (segment != c_etws_seg0) {
|
|
setverdict(fail, "Invalid first segment ", segment);
|
|
err := true;
|
|
}
|
|
if (not err) {
|
|
seg_received[0] := seg_received[0] + 1;
|
|
}
|
|
}
|
|
}
|
|
case (tr_PagingType1) {
|
|
setverdict(fail, "Received unexpected PAGING TYPE 1: ", l3);
|
|
}
|
|
}
|
|
repeat;
|
|
}
|
|
[] L1CTL.receive { repeat; }
|
|
[] T.timeout {
|
|
setverdict(pass);
|
|
}
|
|
}
|
|
log("Quantity of received ETWS PN segments: ", seg_received);
|
|
var integer i;
|
|
for (i := 0; i < 4; i := i+1) {
|
|
if (seg_received[i] < 15) {
|
|
setverdict(fail, "Segment ", i, " not received often enough");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Ensure only Paging Type 1 without ETWS Primary Notification are sent after disabling them */
|
|
testcase TC_etws_p1ro_end() runs on test_CT {
|
|
var template RslChannelNr t_chan_nr := ts_RslChanNr_PCH_AGCH(0);
|
|
/* we expect four blocks of 14 bytes, let's fill them with content easily
|
|
* distinguishable */
|
|
/* decoding the actual entire P1 rest octets by manually generated code is
|
|
* too much effort; instead simply do a binary compare to this constant */
|
|
const bitstring c_P1RO_hdr := '00101011101'B;
|
|
var L1ctlDlMessage dl;
|
|
timer T := 10.0;
|
|
|
|
f_init();
|
|
f_init_l1ctl();
|
|
f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH);
|
|
|
|
RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws)));
|
|
/* wait for a bit until old non-ETWS Paging messages are gone */
|
|
f_sleep(3.0);
|
|
/* disable the ETWS PN again */
|
|
RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_OSMO_ETWS_CMD(''O)));
|
|
f_sleep(2.0);
|
|
T.start;
|
|
L1CTL.clear;
|
|
alt {
|
|
[] L1CTL.receive(tr_L1CTL_DATA_IND(t_chan_nr)) -> value dl {
|
|
var GsmRrMessage l3 := dec_GsmRrMessage(dl.payload.data_ind.payload);
|
|
select (l3) {
|
|
case (tr_PAG_REQ1(tr_MI_LV(t_MI_NoIdentity()))) { repeat; }
|
|
case (tr_PagingType1) {
|
|
setverdict(fail, "Received non-empty PT1 after disabling ETWS PN: ", l3);
|
|
}
|
|
}
|
|
repeat;
|
|
}
|
|
[] L1CTL.receive { repeat; }
|
|
[] T.timeout {
|
|
setverdict(pass);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Ensure ETWS Primary Notification is passed from RSL to PCU interface */
|
|
testcase TC_etws_pcu() runs on test_CT {
|
|
timer T := 10.0;
|
|
|
|
f_init();
|
|
f_init_l1ctl();
|
|
f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH);
|
|
|
|
RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws)));
|
|
|
|
T.start;
|
|
alt {
|
|
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_APP_INFO_REQ(0, 0, c_etws))) {
|
|
setverdict(pass);
|
|
}
|
|
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_APP_INFO_REQ(?, ?, ?))) {
|
|
setverdict(fail, "PCU socket received invalid APP INFO");
|
|
}
|
|
[] PCU.receive { repeat; }
|
|
[] T.timeout {
|
|
setverdict(fail, "PCU socket timeout receiving APP INFO (ETWS)");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* SMSCB TODO:
|
|
* multiple SMS BC CMD at the same time: Ensure all of them are sent exactly once
|
|
* extended CBCH vs. normal CBCH
|
|
*
|
|
*/
|
|
|
|
control {
|
|
execute( TC_cbch_load_idle_no_cbch() );
|
|
|
|
execute( TC_sms_cb_cmd_sdcch4_1block() );
|
|
execute( TC_sms_cb_cmd_sdcch4_2block() );
|
|
execute( TC_sms_cb_cmd_sdcch4_3block() );
|
|
execute( TC_sms_cb_cmd_sdcch4_4block() );
|
|
execute( TC_sms_cb_cmd_sdcch4_multi() );
|
|
execute( TC_sms_cb_cmd_sdcch4_schedule() );
|
|
execute( TC_sms_cb_cmd_sdcch4_default_only() );
|
|
execute( TC_sms_cb_cmd_sdcch4_default_and_normal() );
|
|
execute( TC_sms_cb_cmd_sdcch4_default_then_null() );
|
|
execute( TC_cbc_sdcch4_load_idle() );
|
|
execute( TC_cbc_sdcch4_load_overload() );
|
|
|
|
execute( TC_sms_cb_cmd_sdcch8_1block() );
|
|
execute( TC_sms_cb_cmd_sdcch8_2block() );
|
|
execute( TC_sms_cb_cmd_sdcch8_3block() );
|
|
execute( TC_sms_cb_cmd_sdcch8_4block() );
|
|
execute( TC_sms_cb_cmd_sdcch8_multi() );
|
|
execute( TC_sms_cb_cmd_sdcch8_schedule() );
|
|
execute( TC_sms_cb_cmd_sdcch8_default_only() );
|
|
execute( TC_sms_cb_cmd_sdcch8_default_and_normal() );
|
|
execute( TC_cbc_sdcch8_load_idle() );
|
|
execute( TC_cbc_sdcch8_load_overload() );
|
|
|
|
execute( TC_etws_p1ro() );
|
|
execute( TC_etws_p1ro_end() );
|
|
execute( TC_etws_pcu() );
|
|
}
|
|
|
|
|
|
}
|