diff options
Diffstat (limited to 'pcu/PCUIF_Components.ttcn')
-rw-r--r-- | pcu/PCUIF_Components.ttcn | 240 |
1 files changed, 212 insertions, 28 deletions
diff --git a/pcu/PCUIF_Components.ttcn b/pcu/PCUIF_Components.ttcn index aa2ab422..6e956ba8 100644 --- a/pcu/PCUIF_Components.ttcn +++ b/pcu/PCUIF_Components.ttcn @@ -19,6 +19,11 @@ import from UD_Types all; import from PCUIF_Types all; import from PCUIF_CodecPort all; +import from Osmocom_Types all; +import from General_Types all; +import from RLCMAC_Types all; +import from GSM_RR_Types all; + /* Component communication diagram: * * +-----+ +----------+ +---------+ @@ -119,11 +124,63 @@ template RAW_PCU_Command tr_RAW_PCU_CMD(template RAW_PCU_CommandType cmd := ?, data := data } +/* PCUIF req_data containing decoded rlcmac/rr, for users to be able to match + * directly on receive() + */ +type record BTS_PDTCH_Block { + uint8_t bts_nr, + PCUIF_data raw, + RlcmacDlBlock dl_block optional +}; +type record BTS_PTCCH_Block { + uint8_t bts_nr, + PCUIF_data raw, + PTCCHDownlinkMsg dl_block optional +}; +type record BTS_CCCH_Block { + uint8_t bts_nr, + PCUIF_data raw, + OCT4 msg_id optional, + charstring imsi optional, + GsmRrMessage rr_msg, + boolean confirm optional +}; +template BTS_PDTCH_Block tr_PCUIF_DATA_PDTCH(template uint8_t bts_nr, + template PCUIF_data raw, + template RlcmacDlBlock dl_block := ?) := { + bts_nr := bts_nr, + raw := raw, + dl_block := dl_block +}; +template BTS_PTCCH_Block tr_PCUIF_DATA_PTCCH(template uint8_t bts_nr, + template PCUIF_data raw, + template PTCCHDownlinkMsg dl_block := ?) := { + bts_nr := bts_nr, + raw := raw, + dl_block := dl_block +}; +template BTS_CCCH_Block tr_PCUIF_DATA_RR(template uint8_t bts_nr, + template PCUIF_data raw, + template GsmRrMessage rr_msg := ?, + template OCT4 msg_id := *, + template charstring imsi := *, + template boolean confirm := *) := { + bts_nr := bts_nr, + raw := raw, + msg_id := msg_id, + imsi := imsi, + rr_msg := rr_msg, + confirm := confirm +}; + /* Generic port for messages and events */ type port RAW_PCU_MSG_PT message { inout RAW_PCU_Command; inout RAW_PCU_Event; inout PCUIF_Message; + inout BTS_PDTCH_Block; + inout BTS_PTCCH_Block; + inout BTS_CCCH_Block; } with { extension "internal" }; /* TDMA frame clock generator */ @@ -165,10 +222,12 @@ function f_tdma_ptcch_fn2ss(integer fn) return integer return ss; } -function f_ClckGen_CT_handler() +function f_ClckGen_CT_handler(integer start_fn := 0) runs on RAW_PCU_ClckGen_CT { var integer fn104, fn52, fn13; + fn := start_fn; + while (true) { fn104 := fn mod 104; fn52 := fn mod 52; @@ -261,6 +320,8 @@ type component RAW_PCU_BTS_CT { /* Whether to forward PTCCH/U burst events to the TC */ var boolean cfg_ptcch_burst_fwd := false; + + var PCUIF_info_ind g_info_ind; } /* Queue received messages from Test Case, they will eventually be scheduled and @@ -272,7 +333,11 @@ runs on RAW_PCU_BTS_CT { /* Enqueue DATA.ind and RTS.req messages */ [] TC.receive(tr_PCUIF_MSG(PCU_IF_MSG_DATA_IND, bts_nr)) -> value pcu_msg { - f_PCUIF_MsgQueue_enqueue(pdtch_data_queue, pcu_msg); + if (pcu_msg.u.data_ind.sapi == PCU_IF_SAPI_BCCH) { + PCUIF.send(pcu_msg); /* Forward directly ASAP */ + } else { + f_PCUIF_MsgQueue_enqueue(pdtch_data_queue, pcu_msg); + } repeat; } [] TC.receive(tr_PCUIF_RTS_REQ(bts_nr, sapi := PCU_IF_SAPI_PDTCH)) -> value pcu_msg { @@ -290,6 +355,84 @@ runs on RAW_PCU_BTS_CT { } } +/* Submit empty data on any available TS, to set up initial TDMA clock */ +private function f_tx_first_data_ind(integer bts_nr, PCUIF_info_ind info_ind, integer start_fn) +runs on RAW_PCU_BTS_CT +{ + var PCUIF_Message pcu_msg; + + /* Find an active TS: */ + for (var uint8_t ts_nr := 0; ts_nr < 8; ts_nr := ts_nr + 1) { + for (var integer trx_nr := 0; trx_nr < lengthof(g_info_ind.trx); trx_nr := trx_nr + 1) { + if (g_info_ind.trx[trx_nr].pdch_mask[ts_nr] == '0'B) { + continue; /* TRX+TS not activated */ + } + + /* Send empty DATA.ind to set up FN */ + pcu_msg := valueof(ts_PCUIF_DATA_IND(bts_nr, trx_nr, ts_nr, 0 /* FIXME */, + PCU_IF_SAPI_PDTCH, ''O, start_fn, + g_info_ind.trx[trx_nr].arfcn, + rssi := -80, ber10k := 0, + ta_offs_qbits := 0, lqual_cb := 10)); + PCUIF.send(pcu_msg); + return; + } + } +} + +private function fn2macblock(uint32_t fn) return uint8_t +{ + return (fn mod 52) / 4; +} + +/* Get first message from queue. true if non-empty, false otherwise */ +private function f_tx_data_ind_fn(integer bts_nr, integer fn) +runs on RAW_PCU_BTS_CT +{ + var PCUIF_Message pcu_msg; + var boolean has_msg, use_msg; + + for (var uint8_t ts_nr := 0; ts_nr < 8; ts_nr := ts_nr + 1) { + for (var integer trx_nr := 0; trx_nr < lengthof(g_info_ind.trx); trx_nr := trx_nr + 1) { + //var charstring prefix := "BTS=" & int2str(bts_nr) & ",TRX=" & int2str(trx_nr) & ",TS=" & int2str(ts_nr) & ",FN=" & int2str(fn) & ": "; + if (g_info_ind.trx[trx_nr].pdch_mask[ts_nr] == '0'B) { + //log(prefix, "disabled"); + continue; /* TRX+TS not activated */ + } + + /* Check if we reached time to serve the first DATA.ind message in the queue: */ + has_msg := f_PCUIF_MsgQueue_first(pdtch_data_queue, pcu_msg) and + pcu_msg.u.data_ind.trx_nr == trx_nr and + pcu_msg.u.data_ind.ts_nr == ts_nr; + use_msg := has_msg and (pcu_msg.u.data_ind.fn == 0 or pcu_msg.u.data_ind.fn == fn); + if (use_msg) { + /* Dequeue a DATA.ind message */ + f_PCUIF_MsgQueue_dequeue(pdtch_data_queue, pcu_msg); + /* Patch TDMA frame / block number */ + pcu_msg.u.data_ind.fn := fn; + pcu_msg.u.data_ind.block_nr := fn2macblock(fn); + //log(prefix, "DATA.ind"); + } else if (has_msg and pcu_msg.u.data_ind.fn < fn) { + setverdict(fail, "We are late scheduling the block! ", pcu_msg.u.data_ind.fn, " < ", fn); + mtc.stop; + } else { + /* NOPE.ind: */ + pcu_msg := valueof(ts_PCUIF_DATA_IND(bts_nr, trx_nr, ts_nr, 0 /* FIXME */, + PCU_IF_SAPI_PDTCH, ''O, fn, + g_info_ind.trx[trx_nr].arfcn, + rssi := -80, ber10k := 0, + ta_offs_qbits := 0, lqual_cb := 10)); + //log(prefix, "DATA.ind (len=0)"); + } + + PCUIF.send(pcu_msg); /* Send to the PCU and notify the TC */ + if (use_msg) { + TC.send(ts_RAW_PCU_CLCK_EV(TDMA_EV_PDTCH_BLOCK_SENT, fn)); + } + } + } +} + /* Handle schedule events and manage actions: Send msgs over PCUIF to PCU, * advertise Test Case about sent messages, etc. */ private altstep as_BTS_CT_TDMASched(integer bts_nr) @@ -297,7 +440,6 @@ runs on RAW_PCU_BTS_CT { var PCUIF_Message pcu_msg; var RAW_PCU_Event event; var integer ev_begin_fn; - var integer next_fn; [] CLCK.receive(tr_RAW_PCU_EV(TDMA_EV_PDTCH_BLOCK_BEG)) -> value event { /* If the RTS queue for PDTCH is not empty, send a message */ @@ -306,7 +448,7 @@ runs on RAW_PCU_BTS_CT { /* Patch TDMA frame / block number and send */ pcu_msg.u.rts_req.fn := event.data.tdma_fn; - pcu_msg.u.rts_req.block_nr := 0; /* FIXME! */ + pcu_msg.u.rts_req.block_nr := fn2macblock(event.data.tdma_fn); PCUIF.send(pcu_msg); } @@ -315,29 +457,10 @@ runs on RAW_PCU_BTS_CT { PCUIF.send(ts_PCUIF_TIME_IND(bts_nr, event.data.tdma_fn)); repeat; } - [lengthof(pdtch_data_queue) > 0] CLCK.receive(tr_RAW_PCU_EV(TDMA_EV_PDTCH_BLOCK_END)) -> value event { + [] CLCK.receive(tr_RAW_PCU_EV(TDMA_EV_PDTCH_BLOCK_END)) -> value event { /* FN matching the beginning of current block: */ ev_begin_fn := event.data.tdma_fn - 3; - - /* Check if we reached time to serve the first DATA.ind message in the queue: */ - f_PCUIF_MsgQueue_first(pdtch_data_queue, pcu_msg); - next_fn := pcu_msg.u.data_ind.fn; - if (next_fn != 0 and next_fn != ev_begin_fn) { - if (next_fn < ev_begin_fn) { - setverdict(fail, "We are late scheduling the block! ", next_fn, " < ", ev_begin_fn); - mtc.stop; - } - repeat; - } - /* Dequeue a DATA.ind message */ - f_PCUIF_MsgQueue_dequeue(pdtch_data_queue, pcu_msg); - - /* Patch TDMA frame / block number */ - pcu_msg.u.data_ind.fn := ev_begin_fn; - pcu_msg.u.data_ind.block_nr := 0; /* FIXME! */ - - PCUIF.send(pcu_msg); /* Send to the PCU and notify the TC */ - TC.send(ts_RAW_PCU_CLCK_EV(TDMA_EV_PDTCH_BLOCK_SENT, ev_begin_fn)); + f_tx_data_ind_fn(bts_nr, ev_begin_fn); repeat; } [lengthof(ptcch_rts_queue) > 0] CLCK.receive(tr_RAW_PCU_EV(TDMA_EV_PTCCH_DL_BLOCK)) -> value event { @@ -348,7 +471,7 @@ runs on RAW_PCU_BTS_CT { /* Patch TDMA frame / block number and send */ pcu_msg.u.rts_req.fn := ev_begin_fn; - pcu_msg.u.rts_req.block_nr := 0; /* FIXME! */ + pcu_msg.u.rts_req.block_nr := fn2macblock(ev_begin_fn); PCUIF.send(pcu_msg); repeat; } @@ -361,11 +484,16 @@ runs on RAW_PCU_BTS_CT { [] CLCK.receive(tr_RAW_PCU_CLCK_EV) { repeat; } } -function f_BTS_CT_handler(integer bts_nr, PCUIF_info_ind info_ind) +function f_BTS_CT_handler(integer bts_nr, PCUIF_info_ind info_ind, boolean decode_data_req := false) runs on RAW_PCU_BTS_CT { var PCUIF_Message pcu_msg; var RAW_PCU_Command cmd; var RAW_PCU_Event event; + var BTS_PDTCH_Block pcu_msg_pdtch; + var BTS_PTCCH_Block pcu_msg_ptcch; + var BTS_CCCH_Block pcu_msg_rr; + + g_info_ind := info_ind; /* Init TDMA clock generator (so we can stop and start it) */ vc_CLCK_GEN := RAW_PCU_ClckGen_CT.create("ClckGen-" & int2str(bts_nr)) alive; @@ -387,11 +515,14 @@ runs on RAW_PCU_BTS_CT { u := { info_ind := info_ind } }); + const integer start_fn := 0; + f_tx_first_data_ind(bts_nr, info_ind, start_fn); + /* Notify the test case that we're done with SI13 */ TC.send(ts_RAW_PCU_EV(BTS_EV_SI13_NEGO)); /* Start feeding clock to the PCU */ - vc_CLCK_GEN.start(f_ClckGen_CT_handler()); + vc_CLCK_GEN.start(f_ClckGen_CT_handler(start_fn)); repeat; } /* PCU -> TS becomes active */ @@ -406,6 +537,59 @@ runs on RAW_PCU_BTS_CT { "/TS" & int2str(pcu_msg.u.act_req.ts_nr)); repeat; } + [decode_data_req] PCUIF.receive(tr_PCUIF_DATA_REQ(bts_nr, ?, ?, sapi := PCU_IF_SAPI_PCH_2)) -> value pcu_msg { + var charstring imsi_filter_regexp := "(\d*)"; /* numbers only */ + var PCUIF_pch pch; + + pcu_msg_rr.bts_nr := bts_nr; + pcu_msg_rr.raw := pcu_msg.u.data_req; + + pch := dec_PCUIF_pch(pcu_msg_rr.raw.data); + pcu_msg_rr.msg_id := pch.msg_id; + pcu_msg_rr.imsi := regexp(pch.imsi, imsi_filter_regexp, 0); + pcu_msg_rr.rr_msg := dec_GsmRrMessage(pch.data); + pcu_msg_rr.confirm := pch.confirm; + + TC.send(pcu_msg_rr); + repeat; + } + [decode_data_req] PCUIF.receive(tr_PCUIF_DATA_REQ(bts_nr, ?, ?, sapi := PCU_IF_SAPI_AGCH_2)) -> value pcu_msg { + var PCUIF_agch agch; + + pcu_msg_rr.bts_nr := bts_nr; + pcu_msg_rr.raw := pcu_msg.u.data_req; + + agch := dec_PCUIF_agch(pcu_msg_rr.raw.data); + pcu_msg_rr.imsi := omit; + pcu_msg_rr.msg_id := agch.msg_id; + pcu_msg_rr.rr_msg := dec_GsmRrMessage(agch.data); + pcu_msg_rr.confirm := agch.confirm; + + TC.send(pcu_msg_rr); + repeat; + } + [decode_data_req] PCUIF.receive(tr_PCUIF_DATA_REQ(bts_nr, ?, ?, sapi := PCU_IF_SAPI_PDTCH)) -> value pcu_msg { + pcu_msg_pdtch.bts_nr := bts_nr; + pcu_msg_pdtch.raw := pcu_msg.u.data_req; + if (pcu_msg_pdtch.raw.len != 0) { + pcu_msg_pdtch.dl_block := dec_RlcmacDlBlock(pcu_msg_pdtch.raw.data); + } else { + pcu_msg_pdtch.dl_block := omit; + } + TC.send(pcu_msg_pdtch); + repeat; + } + [decode_data_req] PCUIF.receive(tr_PCUIF_DATA_REQ(bts_nr, ?, ?, sapi := PCU_IF_SAPI_PTCCH)) -> value pcu_msg { + pcu_msg_ptcch.bts_nr := bts_nr; + pcu_msg_ptcch.raw := pcu_msg.u.data_req; + if (pcu_msg_ptcch.raw.len != 0) { + pcu_msg_ptcch.dl_block := dec_PTCCHDownlinkMsg(pcu_msg_ptcch.raw.data); + } else { + pcu_msg_ptcch.dl_block := omit; + } + TC.send(pcu_msg_ptcch); + repeat; + } /* PCU -> test case forwarding (filter by the BTS number) */ [] PCUIF.receive(tr_PCUIF_MSG(?, bts_nr)) -> value pcu_msg { TC.send(pcu_msg); |