bts: Add PCU Interface testcases
Change-Id: I671b8e2c61705485f46602f648eb5fdc01db12f7
This commit is contained in:
parent
56c0580c5f
commit
883340c719
|
@ -13,6 +13,7 @@ mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC;
|
|||
*.BTSVTY.CTRL_READMODE := "buffered"
|
||||
*.BTSVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes"
|
||||
*.BTSVTY.PROMPT1 := "OsmoBTS> "
|
||||
*.PCU.socket_type := "SEQPACKET"
|
||||
|
||||
[MODULE_PARAMETERS]
|
||||
Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoBTS";
|
||||
|
|
|
@ -22,6 +22,9 @@ import from TRXC_Types all;
|
|||
import from TRXC_CodecPort all;
|
||||
import from TRXC_CodecPort_CtrlFunct all;
|
||||
|
||||
import from PCUIF_Types all;
|
||||
import from PCUIF_CodecPort all;
|
||||
|
||||
import from MobileL3_CommonIE_Types all;
|
||||
import from MobileL3_RRM_Types all;
|
||||
import from MobileL3_Types all;
|
||||
|
@ -43,6 +46,7 @@ modulepar {
|
|||
integer mp_rsl_port := 3003;
|
||||
integer mp_trx0_arfcn := 871;
|
||||
integer mp_bb_trxc_port := 5704;
|
||||
charstring mp_pcu_socket := PCU_SOCK_DEFAULT;
|
||||
}
|
||||
|
||||
type component test_CT extends CTRL_Adapter_CT {
|
||||
|
@ -62,6 +66,12 @@ type component test_CT extends CTRL_Adapter_CT {
|
|||
|
||||
port TELNETasp_PT BTSVTY;
|
||||
|
||||
/* PCU Interface of BTS */
|
||||
port PCUIF_CODEC_PT PCU;
|
||||
var integer g_pcu_conn_id;
|
||||
/* Last PCU INFO IND we received */
|
||||
var PCUIF_Message g_pcu_last_info;
|
||||
|
||||
/* SI configuration */
|
||||
var SystemInformationConfig si_cfg := {
|
||||
bcch_extended := false,
|
||||
|
@ -212,6 +222,33 @@ private function f_init_vty(charstring id) runs on test_CT {
|
|||
f_vty_transceive(BTSVTY, "enable");
|
||||
}
|
||||
|
||||
/* PCU socket may at any time receive a new INFO.ind */
|
||||
private altstep as_pcu_info_ind() runs on test_CT {
|
||||
var PCUIF_send_data sd;
|
||||
[] PCU.receive(t_SD_PCUIF_MSGT(g_pcu_conn_id, PCU_IF_MSG_INFO_IND)) -> value sd {
|
||||
g_pcu_last_info := sd.data;
|
||||
repeat;
|
||||
}
|
||||
}
|
||||
|
||||
private function f_init_pcu(charstring id) runs on test_CT {
|
||||
timer T := 2.0;
|
||||
var PCUIF_send_data sd;
|
||||
map(self:PCU, system:PCU);
|
||||
g_pcu_conn_id := f_pcuif_connect(PCU, mp_pcu_socket);
|
||||
|
||||
T.start;
|
||||
alt {
|
||||
[] PCU.receive(t_SD_PCUIF_MSGT(g_pcu_conn_id, PCU_IF_MSG_INFO_IND)) -> value sd {
|
||||
g_pcu_last_info := sd.data;
|
||||
}
|
||||
[] T.timeout {
|
||||
setverdict(fail, "Timeout waiting for PCU INFO_IND");
|
||||
self.stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* global init function */
|
||||
function f_init(charstring id := "BTS-Test") runs on test_CT {
|
||||
f_init_rsl(id);
|
||||
|
@ -225,6 +262,8 @@ function f_init(charstring id := "BTS-Test") runs on test_CT {
|
|||
f_rsl_bcch_fill(RSL_SYSTEM_INFO_2, ts_SI2_default);
|
||||
f_rsl_bcch_fill(RSL_SYSTEM_INFO_4, ts_SI4_default);
|
||||
|
||||
f_init_pcu(id);
|
||||
|
||||
/* start with a default moderate timing offset equalling TA=2 */
|
||||
f_main_trxc_connect();
|
||||
BB_TRXC.send(ts_TRXC_Send(g_bb_trxc_conn_id, ts_TRXC_FAKE_TIMING(2*256)));
|
||||
|
@ -503,6 +542,15 @@ private function f_rnd_ra_cs() return OCT1 {
|
|||
return ra;
|
||||
}
|
||||
|
||||
/* generate a random RACH for packet-switched */
|
||||
private function f_rnd_ra_ps() return OCT1 {
|
||||
var OCT1 ra;
|
||||
do {
|
||||
ra := f_rnd_octstring(1);
|
||||
} while (not ra_is_ps(ra));
|
||||
return ra;
|
||||
}
|
||||
|
||||
/* Send 1000 RACH requests and check their RA+FN on the RSL side */
|
||||
testcase TC_rach_content() runs on test_CT {
|
||||
f_init(testcasename());
|
||||
|
@ -1790,6 +1838,353 @@ testcase TC_ipa_crcx_sdcch_not_active() runs on test_CT {
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* PCU Socket related tests
|
||||
***********************************************************************/
|
||||
|
||||
private function f_TC_pcu_act_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr, boolean exp_success)
|
||||
runs on test_CT {
|
||||
timer T := 3.0;
|
||||
|
||||
/* we don't expect any RTS.req before PDCH are active */
|
||||
T.start;
|
||||
alt {
|
||||
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(bts_nr))) {
|
||||
setverdict(fail, "PCU RTS.req before PDCH active?");
|
||||
self.stop;
|
||||
}
|
||||
[] PCU.receive { repeat; }
|
||||
[] T.timeout { }
|
||||
}
|
||||
|
||||
/* Send PDCH activate request for known PDCH timeslot */
|
||||
PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_ACT_REQ(bts_nr, trx_nr, ts_nr)));
|
||||
|
||||
/* we now expect RTS.req for this timeslot (only) */
|
||||
T.start;
|
||||
alt {
|
||||
[exp_success] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr))) {
|
||||
setverdict(pass);
|
||||
}
|
||||
[not exp_success] PCU.receive(t_SD_PCUIF(g_pcu_conn_id,
|
||||
tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr))) {
|
||||
setverdict(fail, "Unexpected RTS.req for supposedly failing activation");
|
||||
self.stop;
|
||||
}
|
||||
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ)) {
|
||||
setverdict(fail, "RTS.req for wrong TRX/TS");
|
||||
self.stop;
|
||||
}
|
||||
[] PCU.receive { repeat; }
|
||||
[exp_success] T.timeout {
|
||||
setverdict(fail, "Timeout waiting for PCU RTS.req");
|
||||
}
|
||||
[not exp_success] T.timeout {
|
||||
setverdict(pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function f_TC_pcu_deact_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
|
||||
runs on test_CT {
|
||||
timer T := 3.0;
|
||||
|
||||
/* Send PDCH activate request for known PDCH timeslot */
|
||||
PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_DEACT_REQ(bts_nr, trx_nr, ts_nr)));
|
||||
|
||||
PCU.clear;
|
||||
/* we now expect no RTS.req for this timeslot */
|
||||
T.start;
|
||||
alt {
|
||||
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr))) {
|
||||
setverdict(fail, "Received unexpected PCU RTS.req");
|
||||
self.stop;
|
||||
}
|
||||
[] PCU.receive { repeat; }
|
||||
[] T.timeout {
|
||||
setverdict(pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PDCH activation via PCU socket; check for presence of RTS.req */
|
||||
testcase TC_pcu_act_req() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_act_req(0, 0, 7, true);
|
||||
}
|
||||
|
||||
/* PDCH activation via PCU socket on non-PDCU timeslot */
|
||||
testcase TC_pcu_act_req_wrong_ts() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_act_req(0, 0, 1, false);
|
||||
}
|
||||
|
||||
/* PDCH activation via PCU socket on wrong BTS */
|
||||
testcase TC_pcu_act_req_wrong_bts() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_act_req(23, 0, 7, false);
|
||||
}
|
||||
|
||||
/* PDCH activation via PCU socket on wrong TRX */
|
||||
testcase TC_pcu_act_req_wrong_trx() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_act_req(0, 23, 7, false);
|
||||
}
|
||||
|
||||
/* PDCH deactivation via PCU socket; check for absence of RTS.req */
|
||||
testcase TC_pcu_deact_req() runs on test_CT {
|
||||
f_init();
|
||||
/* Activate PDCH */
|
||||
f_TC_pcu_act_req(0, 0, 7, true);
|
||||
f_sleep(1.0);
|
||||
/* and De-Activate again */
|
||||
f_TC_pcu_deact_req(0, 0, 7);
|
||||
}
|
||||
|
||||
/* Attempt to deactivate a PDCH on a non-PDCH timeslot */
|
||||
testcase TC_pcu_deact_req_wrong_ts() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_deact_req(0, 0, 1);
|
||||
}
|
||||
|
||||
/* Test the PCU->BTS Version and BTS->PCU SI13 handshake */
|
||||
testcase TC_pcu_ver_si13() runs on test_CT {
|
||||
const octetstring si13 := '00010203040506070909'O;
|
||||
var PCUIF_send_data sd;
|
||||
timer T:= 3.0;
|
||||
f_init();
|
||||
|
||||
/* Set SI13 via RSL */
|
||||
f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_13, si13);
|
||||
PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_TXT_IND(0, PCU_VERSION, "BTS_Test v23")));
|
||||
T.start;
|
||||
alt {
|
||||
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_DATA_IND(0, 0, 0, ?, PCU_IF_SAPI_BCCH))) -> value sd {
|
||||
if (substr(sd.data.u.data_ind.data, 0, lengthof(si13)) == si13) {
|
||||
setverdict(pass);
|
||||
} else {
|
||||
repeat;
|
||||
}
|
||||
}
|
||||
[] PCU.receive { repeat; }
|
||||
[] T.timeout {
|
||||
setverdict(fail, "Timeout waiting for SI13");
|
||||
self.stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const octetstring c_PCU_DATA := '000102030405060708090a0b0c0d0e0f10111213141516'O;
|
||||
|
||||
/* helper function to send a PCU DATA.req */
|
||||
private function f_pcu_data_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
|
||||
uint8_t block_nr, uint32_t fn, PCUIF_Sapi sapi, octetstring data)
|
||||
runs on test_CT
|
||||
{
|
||||
PCU.send(t_SD_PCUIF(g_pcu_conn_id,
|
||||
ts_PCUIF_DATA_REQ(bts_nr, trx_nr, ts_nr, block_nr, fn, sapi, data)));
|
||||
}
|
||||
|
||||
/* helper function to wait for RTS.ind for given SAPI on given BTS/TRX/TS and then send */
|
||||
private function f_pcu_wait_rts_and_data_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
|
||||
PCUIF_Sapi sapi, octetstring data)
|
||||
runs on test_CT
|
||||
{
|
||||
var PCUIF_send_data sd;
|
||||
|
||||
timer T := 3.0;
|
||||
T.start;
|
||||
alt {
|
||||
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id,
|
||||
tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr, sapi))) -> value sd {
|
||||
f_pcu_data_req(bts_nr, trx_nr, ts_nr, sd.data.u.rts_req.block_nr,
|
||||
sd.data.u.rts_req.fn, sapi, data);
|
||||
}
|
||||
[] PCU.receive { repeat; }
|
||||
[] T.timeout {
|
||||
setverdict(fail, "Timeout waiting for RTS.ind");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Send DATA.req on invalid BTS */
|
||||
testcase TC_pcu_data_req_wrong_bts() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_act_req(0, 0, 7, true);
|
||||
f_pcu_data_req(23, 0, 7, 0, 0, PCU_IF_SAPI_PDTCH, c_PCU_DATA);
|
||||
/* FIXME: how to check this wasn't actually sent and didn't crash BTS? */
|
||||
f_sleep(10.0);
|
||||
}
|
||||
|
||||
/* Send DATA.req on invalid TRX */
|
||||
testcase TC_pcu_data_req_wrong_trx() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_act_req(0, 0, 7, true);
|
||||
f_pcu_data_req(0, 100, 7, 0, 0, PCU_IF_SAPI_PDTCH, c_PCU_DATA);
|
||||
/* FIXME: how to check this wasn't actually sent and didn't crash BTS? */
|
||||
f_sleep(10.0);
|
||||
}
|
||||
|
||||
/* Send DATA.req on invalid timeslot */
|
||||
testcase TC_pcu_data_req_wrong_ts() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_act_req(0, 0, 7, true);
|
||||
f_pcu_data_req(0, 0, 70, 0, 0, PCU_IF_SAPI_PDTCH, c_PCU_DATA);
|
||||
/* FIXME: how to check this wasn't actually sent and didn't crash BTS? */
|
||||
f_sleep(10.0);
|
||||
}
|
||||
|
||||
/* Send DATA.req on timeslot that hasn't been activated */
|
||||
testcase TC_pcu_data_req_ts_inactive() runs on test_CT {
|
||||
f_init();
|
||||
f_pcu_data_req(0, 0, 7, 0, 0, PCU_IF_SAPI_PDTCH, c_PCU_DATA);
|
||||
/* FIXME: how to check this wasn't actually sent and didn't crash BTS? */
|
||||
f_sleep(2.0);
|
||||
}
|
||||
|
||||
testcase TC_pcu_data_req_pdtch() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_act_req(0, 0, 7, true);
|
||||
f_pcu_wait_rts_and_data_req(0, 0, 7, PCU_IF_SAPI_PDTCH, c_PCU_DATA);
|
||||
/* FIXME: how to check this was actually sent */
|
||||
f_sleep(2.0);
|
||||
}
|
||||
|
||||
testcase TC_pcu_data_req_ptcch() runs on test_CT {
|
||||
f_init();
|
||||
f_TC_pcu_act_req(0, 0, 7, true);
|
||||
f_pcu_wait_rts_and_data_req(0, 0, 7, PCU_IF_SAPI_PTCCH, c_PCU_DATA);
|
||||
/* FIXME: how to check this was actually sent */
|
||||
f_sleep(2.0);
|
||||
}
|
||||
|
||||
/* Send AGCH from PCU; check it appears on Um side */
|
||||
testcase TC_pcu_data_req_agch() runs on test_CT {
|
||||
timer T := 3.0;
|
||||
f_init();
|
||||
f_init_l1ctl();
|
||||
f_l1_tune(L1CTL);
|
||||
|
||||
f_TC_pcu_act_req(0, 0, 7, true);
|
||||
f_pcu_data_req(0, 0, 7, 0, 0, PCU_IF_SAPI_AGCH, c_PCU_DATA);
|
||||
|
||||
T.start;
|
||||
alt {
|
||||
[] L1CTL.receive(t_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, c_PCU_DATA)) {
|
||||
setverdict(pass);
|
||||
}
|
||||
[] L1CTL.receive { repeat; }
|
||||
[] T.timeout {
|
||||
setverdict(fail, "Timeout waiting for PCU-originated AGCH block on Um");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Send IMM.ASS from PCU for PCH; check it appears on Um side */
|
||||
testcase TC_pcu_data_req_imm_ass_pch() runs on test_CT {
|
||||
var octetstring imm_ass := f_rnd_octstring(23);
|
||||
f_init();
|
||||
f_init_l1ctl();
|
||||
f_l1_tune(L1CTL);
|
||||
|
||||
/* append 3 last imsi digits so BTS can compute pagng group */
|
||||
var uint32_t fn := f_PCUIF_tx_imm_ass_pch(PCU, g_pcu_conn_id, imm_ass, '123459987'H);
|
||||
|
||||
timer T := 0.5;
|
||||
T.start;
|
||||
alt {
|
||||
[] L1CTL.receive(t_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, imm_ass)) {
|
||||
/* TODO: verify paging group */
|
||||
setverdict(pass);
|
||||
}
|
||||
[] L1CTL.receive { repeat; }
|
||||
[] T.timeout {
|
||||
setverdict(fail, "Timeout waiting for PCU-originated AGCH block on Um");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Send RACH from Um side, expect it to show up on PCU socket */
|
||||
testcase TC_pcu_rach_content() runs on test_CT {
|
||||
f_init();
|
||||
f_init_l1ctl();
|
||||
f_l1_tune(L1CTL);
|
||||
|
||||
var GsmFrameNumber fn_last := 0;
|
||||
for (var integer i := 0; i < 1000; i := i+1) {
|
||||
var OCT1 ra := f_rnd_ra_ps();
|
||||
var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
|
||||
if (fn == fn_last) {
|
||||
setverdict(fail, "Two RACH in same FN?!?");
|
||||
self.stop;
|
||||
}
|
||||
fn_last := fn;
|
||||
|
||||
timer T := 2.0;
|
||||
T.start;
|
||||
alt {
|
||||
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND(0, oct2int(ra), 0, ?, fn))) {
|
||||
T.stop;
|
||||
}
|
||||
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND)) {
|
||||
setverdict(fail, "Unexpected RACH IND");
|
||||
self.stop;
|
||||
}
|
||||
[] PCU.receive { repeat; }
|
||||
[] T.timeout {
|
||||
setverdict(fail, "Timeout waiting for RACH IND");
|
||||
self.stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
setverdict(pass);
|
||||
}
|
||||
|
||||
private function f_pad_oct(octetstring str, integer len, OCT1 pad) return octetstring {
|
||||
var integer strlen := lengthof(str);
|
||||
for (var integer i := 0; i < len-strlen; i := i+1) {
|
||||
str := str & pad;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Send PAGING via RSL, expect it to shw up on PCU socket */
|
||||
testcase TC_pcu_paging_from_rsl() runs on test_CT {
|
||||
f_init();
|
||||
|
||||
for (var integer i := 0; i < 100; i := i+1) {
|
||||
var MobileL3_CommonIE_Types.MobileIdentityLV mi;
|
||||
timer T := 3.0;
|
||||
if (i < 50) {
|
||||
mi := valueof(ts_MI_TMSI_LV(f_rnd_octstring(4)));
|
||||
} else {
|
||||
mi := valueof(ts_MI_IMSI_LV(f_gen_imsi(i)));
|
||||
}
|
||||
var octetstring mi_enc_lv := enc_MobileIdentityLV(mi);
|
||||
var octetstring mi_enc := substr(mi_enc_lv, 1, lengthof(mi_enc_lv)-1);
|
||||
var octetstring t_mi_lv := f_pad_oct(mi_enc_lv, 9, '00'O);
|
||||
|
||||
/* Send RSL PAGING COMMAND */
|
||||
RSL_CCHAN.send(ts_RSL_UD(ts_RSL_PAGING_CMD(mi_enc, i mod 4)));
|
||||
T.start;
|
||||
alt {
|
||||
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_PAG_REQ(0, t_mi_lv))) {
|
||||
}
|
||||
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_PAG_REQ)) {
|
||||
setverdict(fail, "Unexpected PAGING REQ");
|
||||
self.stop;
|
||||
}
|
||||
[] PCU.receive { repeat; }
|
||||
[] T.timeout {
|
||||
setverdict(fail, "Timeout waiting for PAGING REQ");
|
||||
self.stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
setverdict(pass);
|
||||
}
|
||||
|
||||
|
||||
/* TODO Areas:
|
||||
|
||||
* channel activation
|
||||
|
@ -1817,6 +2212,10 @@ testcase TC_ipa_crcx_sdcch_not_active() runs on test_CT {
|
|||
** type error
|
||||
** sequence error
|
||||
** IE duplicated?
|
||||
* PCU interface
|
||||
** TIME_IND from BTS->PCU
|
||||
** DATA_IND from BTS->PCU
|
||||
** verification of PCU-originated DATA_REQ arrival on Um/MS side
|
||||
|
||||
*/
|
||||
|
||||
|
@ -1853,6 +2252,24 @@ control {
|
|||
execute( TC_ipa_crcx_mdcx_dlcx_not_active() );
|
||||
execute( TC_ipa_crcx_mdcx_mdcx_dlcx_not_active() );
|
||||
execute( TC_ipa_crcx_sdcch_not_active() );
|
||||
|
||||
execute( TC_pcu_act_req() );
|
||||
execute( TC_pcu_act_req_wrong_ts() );
|
||||
execute( TC_pcu_act_req_wrong_bts() );
|
||||
execute( TC_pcu_act_req_wrong_trx() );
|
||||
execute( TC_pcu_deact_req() );
|
||||
execute( TC_pcu_deact_req_wrong_ts() );
|
||||
execute( TC_pcu_ver_si13() );
|
||||
execute( TC_pcu_data_req_wrong_bts() );
|
||||
execute( TC_pcu_data_req_wrong_trx() );
|
||||
execute( TC_pcu_data_req_wrong_ts() );
|
||||
execute( TC_pcu_data_req_ts_inactive() );
|
||||
execute( TC_pcu_data_req_pdtch() );
|
||||
execute( TC_pcu_data_req_ptcch() );
|
||||
execute( TC_pcu_data_req_agch() );
|
||||
execute( TC_pcu_data_req_imm_ass_pch() );
|
||||
execute( TC_pcu_rach_content() );
|
||||
execute( TC_pcu_paging_from_rsl() );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,4 +48,5 @@ FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter
|
|||
FILES+="L3_Templates.ttcn L3_Common.ttcn "
|
||||
FILES+="Native_Functions.ttcn Native_FunctionDefs.cc "
|
||||
FILES+="TRXC_Types.ttcn TRXC_CodecPort.ttcn TRXC_CodecPort_CtrlFunct.ttcn TRXC_CodecPort_CtrlFunctDef.cc "
|
||||
FILES+="PCUIF_Types.ttcn PCUIF_CodecPort.ttcn "
|
||||
gen_links $DIR $FILES
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
module PCUIF_CodecPort {
|
||||
|
||||
import from Osmocom_Types all;
|
||||
import from PCUIF_Types all;
|
||||
import from UD_PortType all;
|
||||
import from UD_Types all;
|
||||
|
||||
type record PCUIF_send_data {
|
||||
PCUIF_Message data,
|
||||
integer id
|
||||
};
|
||||
|
||||
private function PCUIF_to_UD(in PCUIF_send_data pin, out UD_send_data pout) {
|
||||
pout.id := pin.id;
|
||||
pout.data := enc_PCUIF_Message(pin.data);
|
||||
} with { extension "prototype(fast)" };
|
||||
|
||||
private function UD_to_PCUIF(in UD_send_data pin, out PCUIF_send_data pout) {
|
||||
pout.id := pin.id;
|
||||
pout.data := dec_PCUIF_Message(pin.data);
|
||||
} with { extension "prototype(fast)" };
|
||||
|
||||
type port PCUIF_CODEC_PT message {
|
||||
out UD_close, UD_listen, UD_shutdown, UD_connect, PCUIF_send_data;
|
||||
in UD_listen_result, UD_connect_result, UD_connected, PCUIF_send_data;
|
||||
} with { extension "user UD_PT
|
||||
out (
|
||||
UD_close -> UD_close:simple;
|
||||
UD_listen -> UD_listen:simple;
|
||||
UD_shutdown -> UD_shutdown:simple;
|
||||
UD_connect -> UD_connect:simple;
|
||||
PCUIF_send_data -> UD_send_data: function(PCUIF_to_UD)
|
||||
)
|
||||
in (
|
||||
UD_listen_result -> UD_listen_result:simple;
|
||||
UD_connect_result -> UD_connect_result:simple;
|
||||
UD_send_data -> PCUIF_send_data: function(UD_to_PCUIF);
|
||||
UD_connected -> UD_connected:simple
|
||||
)"
|
||||
};
|
||||
|
||||
template PCUIF_send_data t_SD_PCUIF(integer id, template PCUIF_Message pdu) := {
|
||||
data := pdu,
|
||||
id := id
|
||||
}
|
||||
|
||||
template PCUIF_send_data t_SD_PCUIF_MSGT(integer id, template PCUIF_MsgType msg_type,
|
||||
template uint8_t bts_nr := ?) := {
|
||||
data := {
|
||||
msg_type := msg_type,
|
||||
bts_nr := bts_nr,
|
||||
spare := ?,
|
||||
u := ?
|
||||
},
|
||||
id := id
|
||||
}
|
||||
|
||||
function f_pcuif_connect(PCUIF_CODEC_PT pt, charstring sock) return integer {
|
||||
var UD_connect_result res;
|
||||
timer T := 5.0;
|
||||
|
||||
T.start;
|
||||
pt.send(UD_connect:{sock, -1});
|
||||
alt {
|
||||
[] pt.receive(UD_connect_result:?) -> value res {
|
||||
if (ispresent(res.result) and ispresent(res.result.result_code) and
|
||||
res.result.result_code == ERROR) {
|
||||
setverdict(fail, "Error connecting to PCU socket");
|
||||
self.stop;
|
||||
} else {
|
||||
return res.id;
|
||||
}
|
||||
}
|
||||
[] T.timeout {
|
||||
setverdict(fail, "Timeout connecting to PCU socket");
|
||||
self.stop;
|
||||
}
|
||||
}
|
||||
return -23;
|
||||
}
|
||||
|
||||
function f_PCUIF_tx_imm_ass_pch(PCUIF_CODEC_PT pt, integer conn_id, octetstring imm_ass, hexstring imsi,
|
||||
uint8_t bts_nr := 0) return uint32_t {
|
||||
var PCUIF_send_data sd;
|
||||
timer T := 3.0;
|
||||
/* append 3 last imsi digits so BTS can compute pagng group */
|
||||
var hexstring last_digits := substr(imsi, lengthof(imsi)-3, 3);
|
||||
var octetstring prefix := ''O;
|
||||
log("3 last imsi digits: ", last_digits);
|
||||
for (var integer i := 0; i < 3; i := i+1) {
|
||||
prefix := prefix & int2oct(hex2int('30'H) + hex2int(last_digits[i]), 1);
|
||||
}
|
||||
pt.send(t_SD_PCUIF(conn_id,
|
||||
ts_PCUIF_DATA_REQ(bts_nr, 0, 0, 0, 0, PCU_IF_SAPI_PCH, prefix & imm_ass)));
|
||||
T.start;
|
||||
alt {
|
||||
[] pt.receive(t_SD_PCUIF(conn_id,
|
||||
tr_PCUIF_DATA_CNF(bts_nr, 0, 0, PCU_IF_SAPI_PCH))) -> value sd {
|
||||
log("IMM.ASS was sent on fn ", sd.data.u.data_cnf.fn);
|
||||
return sd.data.u.data_cnf.fn;
|
||||
}
|
||||
[] pt.receive { repeat; }
|
||||
[] T.timeout {
|
||||
setverdict(fail, "Timeout waiting for PCU DATA.cnf");
|
||||
self.stop;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,414 @@
|
|||
module PCUIF_Types {
|
||||
|
||||
import from General_Types all;
|
||||
import from Osmocom_Types all;
|
||||
|
||||
/* Osmocom PCU Interface Types, as per osmo-pcu/include/osmocom/pcu/pcuif_proto.h */
|
||||
|
||||
const charstring PCU_SOCK_DEFAULT := "/tmp/pcu_bts";
|
||||
const uint32_t PCU_IF_VERSION := 8;
|
||||
|
||||
type enumerated PCUIF_MsgType {
|
||||
PCU_IF_MSG_DATA_REQ ('00'O),
|
||||
PCU_IF_MSG_DATA_CNF ('01'O),
|
||||
PCU_IF_MSG_DATA_IND ('02'O),
|
||||
PCU_IF_MSG_SUSP_REQ ('03'O),
|
||||
PCU_IF_MSG_RTS_REQ ('10'O),
|
||||
PCU_IF_MSG_DATA_CNF_DT ('11'O),
|
||||
PCU_IF_MSG_RACH_IND ('22'O),
|
||||
PCU_IF_MSG_INFO_IND ('32'O),
|
||||
PCU_IF_MSG_ACT_REQ ('40'O),
|
||||
PCU_IF_MSG_TIME_IND ('52'O),
|
||||
PCU_IF_MSG_PAG_REQ ('60'O),
|
||||
PCU_IF_MSG_TXT_IND ('70'O)
|
||||
} with { variant "FIELDLENGTH(8)" };
|
||||
|
||||
type enumerated PCUIF_Sapi {
|
||||
PCU_IF_SAPI_UNKNOWN ('00'O),
|
||||
PCU_IF_SAPI_RACH ('01'O),
|
||||
PCU_IF_SAPI_AGCH ('02'O),
|
||||
PCU_IF_SAPI_PCH ('03'O),
|
||||
PCU_IF_SAPI_BCCH ('04'O),
|
||||
PCU_IF_SAPI_PDTCH ('05'O),
|
||||
PCU_IF_SAPI_PRACH ('06'O),
|
||||
PCU_IF_SAPI_PTCCH ('07'O),
|
||||
PCU_IF_SAPI_AGCH_DT ('08'O)
|
||||
} with { variant "FIELDLENGTH(8)" };
|
||||
|
||||
type record PCUIF_Flags {
|
||||
boolean bts_active,
|
||||
boolean sysmo_direct_dsp,
|
||||
BIT14 spare,
|
||||
boolean cs1,
|
||||
boolean cs2,
|
||||
boolean cs3,
|
||||
boolean cs4,
|
||||
boolean mcs1,
|
||||
boolean mcs2,
|
||||
boolean mcs3,
|
||||
boolean mcs4,
|
||||
boolean mcs5,
|
||||
boolean mcs6,
|
||||
boolean mcs7,
|
||||
boolean mcs8,
|
||||
boolean mcs9,
|
||||
BIT3 spare2
|
||||
} with { variant "" };
|
||||
|
||||
type enumerated PCUIF_TextType {
|
||||
PCU_VERSION (0),
|
||||
PCU_OML_ALERT (1)
|
||||
} with { variant "FIELDLENGTH(8)" };
|
||||
|
||||
type charstring PCUIF_Text length(128) with { variant "FIELDLENGTH(128)" };
|
||||
|
||||
type record PCUIF_txt_ind {
|
||||
PCUIF_TextType txt_type,
|
||||
PCUIF_Text text
|
||||
} with { variant "" };
|
||||
|
||||
type octetstring OCT162 length(162) with { variant "FIELDLENGTH(162)" };
|
||||
|
||||
type record PCUIF_data {
|
||||
PCUIF_Sapi sapi,
|
||||
uint8_t len,
|
||||
OCT162 data,
|
||||
uint32_t fn,
|
||||
uint16_t arfcn,
|
||||
uint8_t trx_nr,
|
||||
uint8_t ts_nr,
|
||||
uint8_t block_nr,
|
||||
int8_t rssi,
|
||||
uint16_t ber10k,
|
||||
int16_t ta_offs_qbits,
|
||||
int16_t lqual_cb
|
||||
} with { variant "" };
|
||||
|
||||
type record PCUIF_data_cnf_dt {
|
||||
PCUIF_Sapi sapi,
|
||||
OCT4 tlli,
|
||||
uint32_t fn,
|
||||
uint16_t arfcn,
|
||||
uint8_t trx_nr,
|
||||
uint8_t ts_nr,
|
||||
uint8_t block_nr,
|
||||
int8_t rssi,
|
||||
uint16_t ber10k,
|
||||
int16_t ta_offs_qbits,
|
||||
int16_t lqual_cb
|
||||
} with { variant "" };
|
||||
|
||||
type record PCUIF_rts_req {
|
||||
PCUIF_Sapi sapi,
|
||||
OCT3 spare,
|
||||
uint32_t fn,
|
||||
uint16_t arfcn,
|
||||
uint8_t trx_nr,
|
||||
uint8_t ts_nr,
|
||||
uint8_t block_nr
|
||||
} with { variant "" };
|
||||
|
||||
type record PCUIF_rach_ind {
|
||||
PCUIF_Sapi sapi,
|
||||
uint16_t ra,
|
||||
int16_t qta,
|
||||
uint32_t fn,
|
||||
uint16_t arfcn,
|
||||
uint8_t is_11bit,
|
||||
uint8_t burst_type
|
||||
} with { variant "" };
|
||||
|
||||
type record PCUIF_InfoTrx {
|
||||
uint16_t arfcn,
|
||||
BIT8 pdch_mask,
|
||||
OCT1 spare,
|
||||
OCT8 tsc,
|
||||
uint32_t hLayer1
|
||||
} with { variant "" };
|
||||
|
||||
type record PCUIF_info_ind {
|
||||
uint32_t version,
|
||||
PCUIF_Flags flags,
|
||||
record length(8) of PCUIF_InfoTrx trx,
|
||||
uint8_t bsic,
|
||||
|
||||
uint16_t mcc,
|
||||
uint16_t mnc,
|
||||
uint16_t lac,
|
||||
uint16_t rac,
|
||||
|
||||
uint16_t nsei,
|
||||
record length(7) of uint8_t nse_timer,
|
||||
record length(11) of uint8_t cell_timer,
|
||||
|
||||
uint16_t cell_id,
|
||||
uint16_t repeat_time,
|
||||
uint8_t repeat_count,
|
||||
uint16_t bvci,
|
||||
uint8_t t3142,
|
||||
uint8_t t3169,
|
||||
uint8_t t3191,
|
||||
uint8_t t3193_10ms,
|
||||
uint8_t t3195,
|
||||
uint8_t t3101,
|
||||
uint8_t t3103,
|
||||
uint8_t t3105,
|
||||
uint8_t cv_countdown,
|
||||
uint16_t dl_tbf_ext,
|
||||
uint16_t ul_tbf_ext,
|
||||
uint8_t initial_cs,
|
||||
uint8_t initial_mcs,
|
||||
|
||||
record length(2) of uint16_t nsvci,
|
||||
record length(2) of uint16_t local_pprt,
|
||||
record length(2) of uint16_t remote_port,
|
||||
record length(2) of uint32_t remote_ip
|
||||
} with { variant "" }
|
||||
|
||||
type record PCUIF_act_req {
|
||||
uint8_t is_activate,
|
||||
uint8_t trx_nr,
|
||||
uint8_t ts_nr,
|
||||
OCT1 spare
|
||||
} with { variant "" };
|
||||
|
||||
type record PCUIF_time_ind {
|
||||
uint32_t fn
|
||||
} with { variant "" };
|
||||
|
||||
type record PCUIF_pag_req {
|
||||
PCUIF_Sapi sapi,
|
||||
uint8_t chan_needed,
|
||||
OCT9 identity_lv
|
||||
} with { variant "" };
|
||||
|
||||
type record PCUIF_susp_req {
|
||||
OCT4 tlli,
|
||||
OCT6 ra_id,
|
||||
uint8_t cause
|
||||
} with { variant "" };
|
||||
|
||||
|
||||
type union PCUIF_MsgUnion {
|
||||
PCUIF_data data_req,
|
||||
PCUIF_data data_cnf,
|
||||
PCUIF_data_cnf_dt data_cnf_dt,
|
||||
PCUIF_data data_ind,
|
||||
PCUIF_susp_req susp_req,
|
||||
PCUIF_rts_req rts_req,
|
||||
PCUIF_rach_ind rach_ind,
|
||||
PCUIF_txt_ind txt_ind,
|
||||
PCUIF_info_ind info_ind,
|
||||
PCUIF_act_req act_req,
|
||||
PCUIF_time_ind time_ind,
|
||||
PCUIF_pag_req pag_req
|
||||
} with { variant "" };
|
||||
|
||||
type record PCUIF_Message {
|
||||
PCUIF_MsgType msg_type,
|
||||
uint8_t bts_nr,
|
||||
OCT2 spare,
|
||||
PCUIF_MsgUnion u
|
||||
} with { variant (u) "CROSSTAG(
|
||||
data_req, msg_type = PCU_IF_MSG_DATA_REQ;
|
||||
data_cnf, msg_type = PCU_IF_MSG_DATA_CNF;
|
||||
data_cnf_dt, msg_type = PCU_IF_MSG_DATA_CNF_DT;
|
||||
data_ind, msg_type = PCU_IF_MSG_DATA_IND;
|
||||
susp_req, msg_type = PCU_IF_MSG_SUSP_REQ;
|
||||
rts_req, msg_type = PCU_IF_MSG_RTS_REQ;
|
||||
rach_ind, msg_type = PCU_IF_MSG_RACH_IND;
|
||||
txt_ind, msg_type = PCU_IF_MSG_TXT_IND;
|
||||
info_ind, msg_type = PCU_IF_MSG_INFO_IND;
|
||||
act_req, msg_type = PCU_IF_MSG_ACT_REQ;
|
||||
time_ind, msg_type = PCU_IF_MSG_TIME_IND;
|
||||
pag_req, msg_type = PCU_IF_MSG_PAG_REQ)"
|
||||
variant "PADDING(1688)"
|
||||
};
|
||||
|
||||
external function enc_PCUIF_Message(in PCUIF_Message pdu) return octetstring
|
||||
with { extension "prototype(convert) encode(RAW)" };
|
||||
external function dec_PCUIF_Message(in octetstring stream) return PCUIF_Message
|
||||
with { extension "prototype(convert) decode(RAW)" };
|
||||
|
||||
|
||||
template PCUIF_Message tr_PCUIF_RTS_REQ(template uint8_t bts_nr := ?,
|
||||
template uint8_t trx_nr := ?,
|
||||
template uint8_t ts_nr := ?,
|
||||
template PCUIF_Sapi sapi := ?,
|
||||
template uint32_t fn := ?,
|
||||
template uint8_t block_nr := ?
|
||||
) := {
|
||||
msg_type := PCU_IF_MSG_RTS_REQ,
|
||||
bts_nr := bts_nr,
|
||||
spare := ?,
|
||||
u := {
|
||||
rts_req := {
|
||||
sapi := sapi,
|
||||
spare := ?,
|
||||
fn := fn,
|
||||
arfcn := ?,
|
||||
trx_nr := trx_nr,
|
||||
ts_nr := ts_nr,
|
||||
block_nr := block_nr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template (value) PCUIF_Message ts_PCUIF_TXT_IND(uint8_t bts_nr, PCUIF_TextType tt, charstring text) := {
|
||||
msg_type := PCU_IF_MSG_TXT_IND,
|
||||
bts_nr := bts_nr,
|
||||
spare := '0000'O,
|
||||
u := {
|
||||
txt_ind := {
|
||||
txt_type := tt,
|
||||
text := text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template (value) PCUIF_Message ts_PCUIF_ACT_REQ(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr) := {
|
||||
msg_type := PCU_IF_MSG_ACT_REQ,
|
||||
bts_nr := bts_nr,
|
||||
spare := '0000'O,
|
||||
u := {
|
||||
act_req := {
|
||||
is_activate := 1,
|
||||
trx_nr := trx_nr,
|
||||
ts_nr := ts_nr,
|
||||
spare := '00'O
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template (value) PCUIF_Message ts_PCUIF_DEACT_REQ(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr) := {
|
||||
msg_type := PCU_IF_MSG_ACT_REQ,
|
||||
bts_nr := bts_nr,
|
||||
spare := '0000'O,
|
||||
u := {
|
||||
act_req := {
|
||||
is_activate := 0,
|
||||
trx_nr := trx_nr,
|
||||
ts_nr := ts_nr,
|
||||
spare := '00'O
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template PCUIF_Message tr_PCUIF_DATA_IND(template uint8_t bts_nr := ?,
|
||||
template uint8_t trx_nr := ?,
|
||||
template uint8_t ts_nr := ?,
|
||||
template uint8_t block_nr := ?,
|
||||
template PCUIF_Sapi sapi := ?,
|
||||
template OCT162 data := ?) := {
|
||||
msg_type := PCU_IF_MSG_DATA_IND,
|
||||
bts_nr := bts_nr,
|
||||
spare := ?,
|
||||
u := {
|
||||
data_ind := {
|
||||
sapi := sapi,
|
||||
len := ?,
|
||||
data := data,
|
||||
fn := ?,
|
||||
arfcn := ?,
|
||||
trx_nr := trx_nr,
|
||||
ts_nr := ts_nr,
|
||||
block_nr := block_nr,
|
||||
rssi := ?,
|
||||
ber10k := ?,
|
||||
ta_offs_qbits := ?,
|
||||
lqual_cb := ?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template (value) PCUIF_Message ts_PCUIF_DATA_REQ(uint8_t bts_nr, uint8_t trx_nr,
|
||||
uint8_t ts_nr, uint8_t block_nr,
|
||||
uint32_t fn, PCUIF_Sapi sapi,
|
||||
octetstring data) := {
|
||||
msg_type := PCU_IF_MSG_DATA_REQ,
|
||||
bts_nr := bts_nr,
|
||||
spare := '0000'O,
|
||||
u := {
|
||||
data_req := {
|
||||
sapi := sapi,
|
||||
len := lengthof(data),
|
||||
data := data,
|
||||
fn := fn,
|
||||
arfcn := 0, /* unused in BTS */
|
||||
trx_nr := trx_nr,
|
||||
ts_nr := ts_nr,
|
||||
block_nr := block_nr,
|
||||
/* measurement parameters below unused on Tx */
|
||||
rssi := 0,
|
||||
ber10k := 0,
|
||||
ta_offs_qbits := 0,
|
||||
lqual_cb := 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template PCUIF_Message tr_PCUIF_DATA_CNF(template uint8_t bts_nr := ?,
|
||||
template uint8_t trx_nr := ?,
|
||||
template uint8_t ts_nr := ?,
|
||||
template PCUIF_Sapi sapi := ?,
|
||||
template octetstring data := ?) := {
|
||||
msg_type := PCU_IF_MSG_DATA_CNF,
|
||||
bts_nr := bts_nr,
|
||||
spare := ?,
|
||||
u := {
|
||||
data_cnf := {
|
||||
sapi := sapi,
|
||||
len := ?,
|
||||
data := data,
|
||||
fn := ?,
|
||||
arfcn := ?,
|
||||
trx_nr := trx_nr,
|
||||
ts_nr := ts_nr,
|
||||
block_nr := ?,
|
||||
rssi := ?,
|
||||
ber10k := ?,
|
||||
ta_offs_qbits := ?,
|
||||
lqual_cb := ?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template PCUIF_Message tr_PCUIF_RACH_IND(template uint8_t bts_nr := ?,
|
||||
template uint16_t ra := ?,
|
||||
template uint8_t is_11bit := ?,
|
||||
template uint8_t burst_type := ?,
|
||||
template uint32_t fn := ?) := {
|
||||
msg_type := PCU_IF_MSG_RACH_IND,
|
||||
bts_nr := bts_nr,
|
||||
spare := ?,
|
||||
u := {
|
||||
rach_ind := {
|
||||
sapi := PCU_IF_SAPI_RACH,
|
||||
ra := ra,
|
||||
qta := ?,
|
||||
fn := fn,
|
||||
arfcn := ?,
|
||||
is_11bit := is_11bit,
|
||||
burst_type := burst_type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template PCUIF_Message tr_PCUIF_PAG_REQ(template uint8_t bts_nr := ?,
|
||||
template OCT9 id_lv := ?,
|
||||
template uint8_t chan_needed := ?,
|
||||
template PCUIF_Sapi sapi := ?) := {
|
||||
msg_type := PCU_IF_MSG_PAG_REQ,
|
||||
bts_nr := bts_nr,
|
||||
spare := ?,
|
||||
u := {
|
||||
pag_req := {
|
||||
sapi := ?,
|
||||
chan_needed := chan_needed,
|
||||
identity_lv := id_lv
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} with { encode "RAW" variant "BYTEORDER(first)" };
|
Loading…
Reference in New Issue