From 883340c7194a07a209ca0e982c6f0f001601b2f2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 28 Feb 2018 18:59:29 +0100 Subject: bts: Add PCU Interface testcases Change-Id: I671b8e2c61705485f46602f648eb5fdc01db12f7 --- bts/BTS_Tests.default | 1 + bts/BTS_Tests.ttcn | 417 +++++++++++++++++++++++++++++++++++++++++++ bts/gen_links.sh | 1 + library/PCUIF_CodecPort.ttcn | 114 ++++++++++++ library/PCUIF_Types.ttcn | 414 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 947 insertions(+) create mode 100644 library/PCUIF_CodecPort.ttcn create mode 100644 library/PCUIF_Types.ttcn diff --git a/bts/BTS_Tests.default b/bts/BTS_Tests.default index 562088b2..fa8d0b0d 100644 --- a/bts/BTS_Tests.default +++ b/bts/BTS_Tests.default @@ -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"; diff --git a/bts/BTS_Tests.ttcn b/bts/BTS_Tests.ttcn index 48ca1fd6..be9b4cc5 100644 --- a/bts/BTS_Tests.ttcn +++ b/bts/BTS_Tests.ttcn @@ -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() ); } diff --git a/bts/gen_links.sh b/bts/gen_links.sh index 253b757f..d9c05ffa 100755 --- a/bts/gen_links.sh +++ b/bts/gen_links.sh @@ -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 diff --git a/library/PCUIF_CodecPort.ttcn b/library/PCUIF_CodecPort.ttcn new file mode 100644 index 00000000..fe428afc --- /dev/null +++ b/library/PCUIF_CodecPort.ttcn @@ -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; +} + + + + +} diff --git a/library/PCUIF_Types.ttcn b/library/PCUIF_Types.ttcn new file mode 100644 index 00000000..e4a314db --- /dev/null +++ b/library/PCUIF_Types.ttcn @@ -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)" }; -- cgit v1.2.3