aboutsummaryrefslogtreecommitdiffstats
path: root/pcu/PCUIF_Components.ttcn
diff options
context:
space:
mode:
Diffstat (limited to 'pcu/PCUIF_Components.ttcn')
-rw-r--r--pcu/PCUIF_Components.ttcn240
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);