| 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. |
| * |
| * 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 RSL_Types 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 (true) or SDCCH8 (false) ? */ |
| boolean use_sdcch4, |
| /* 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_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_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_RSL_UD(rsl)); |
| } |
| } |
| private function f_smscb_setup(inout CbchTestPars pars) runs on test_CT { |
| |
| f_cbch_compute_exp_blocks(pars); |
| |
| f_init_vty_bsc(); |
| /* ensure that a CBCH is present in channel combination */ |
| if (pars.use_sdcch4) { |
| f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 0"}, |
| "phys_chan_config CCCH+SDCCH4+CBCH"); |
| f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 6"}, |
| "phys_chan_config SDCCH8"); |
| } else { |
| 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 6"}, |
| "phys_chan_config SDCCH8+CBCH"); |
| } |
| f_vty_transceive(BSCVTY, "drop bts connection 0 oml"); |
| f_sleep(2.0); |
| f_init(testcasename()); |
| |
| f_init_l1ctl(); |
| f_l1_tune(L1CTL); |
| /* FIXME: switch to dedicated mode for SDCCH/8 */ |
| |
| /* 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); |
| } |
| } |
| |
| private function f_smscb_cleanup() runs on test_CT { |
| /* reset timeslot 0 channel combination to default */ |
| 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 6"}, |
| "phys_chan_config SDCCH8"); |
| } |
| |
| /* 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 { |
| /* FIXME: Channel Nr for SDCCH/8 */ |
| [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_CBCH(0))) -> 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"); |
| } |
| } |
| } |
| |
| f_smscb_cleanup(); |
| 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(t_RslChanNr_CBCH(0))) -> 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 {} |
| } |
| |
| f_smscb_cleanup(); |
| /* 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 := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := false, |
| 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 := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := false, |
| 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 := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := false, |
| 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 := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := false, |
| 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 := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := false, |
| basic := valueof(t_CbchPC(msgs_3m_4b_norm)), |
| extended := omit |
| }; |
| f_TC_smscb(pars); |
| } |
| |
| /* transmit SMSCB COMMAND with SCHEDULE payload */ |
| testcase TC_sms_cb_cmd_sdcch4_schedule() runs on test_CT { |
| var CbchTestPars pars := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := false, |
| 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 := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := true, |
| 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 := { |
| use_sdcch4 := true, |
| basic := valueof(t_CbchPC(msgs_1m_3b_default)), |
| extended := omit |
| }; |
| 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_RslChanNr_CBCH(0))) -> 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); |
| } |
| |
| |
| |
| /* 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_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() ); |
| if (false) { /* FIXME: SDCCH/8 support broken, needs trxcon + L1CTL work */ |
| 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() ); |
| } |
| } |
| |
| |
| } |