summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--library/GSM_RR_Types.ttcn51
-rw-r--r--library/L1CTL_PortType.ttcn22
-rw-r--r--library/LAPDm_RAW_PT.ttcn104
-rw-r--r--library/RLCMAC_CSN1_Types.ttcn26
-rw-r--r--library/RLCMAC_Types.ttcn15
-rw-r--r--pcu/PCU_Tests.ttcn81
6 files changed, 279 insertions, 20 deletions
diff --git a/library/GSM_RR_Types.ttcn b/library/GSM_RR_Types.ttcn
index 75be6f8..b1e6809 100644
--- a/library/GSM_RR_Types.ttcn
+++ b/library/GSM_RR_Types.ttcn
@@ -706,6 +706,57 @@ module GSM_RR_Types {
}
};
+ template ImmediateAssignment t_IMM_ASS_TBF_DL(template GprsTlli tlli) := {
+ ded_or_tbf := {
+ spare := ?,
+ tma := ?,
+ downlink := ?,
+ tbf := true
+ },
+ page_mode := ?,
+ chan_desc := omit,
+ pkt_chan_desc := {
+ channel_Type_spare := ?,
+ tn := ?,
+ tsc := ?,
+ presence := ?,
+ zero := *,
+ one := omit
+ },
+ req_ref := ?,
+ timing_advance := ?,
+ mobile_allocation := ?,
+ rest_octets := {
+ presence := '11'B,
+ ll := omit,
+ lh := omit,
+ hl := omit,
+ hh := {
+ presence := '01'B,
+ ul := omit,
+ dl := {
+ tlli := tlli,
+ group1_present := ?,
+ group1 := *,
+ ta_index_present := ?,
+ ta_index := *,
+ tbf_starting_time_present := ?,
+ tbf_starting_time := *,
+ p0_present := ?,
+ p0 := *,
+ pr_mode := *
+ }
+ }
+ }
+ };
+
+ template GsmRrMessage t_RR_IMM_ASS_TBF_DL(template GprsTlli tlli) := {
+ header := t_RrHeader(IMMEDIATE_ASSIGNMENT, ?),
+ payload := {
+ imm_ass := t_IMM_ASS_TBF_DL(tlli)
+ }
+ };
+
} with { encode "RAW" ; variant "FIELDORDER(msb)" }
diff --git a/library/L1CTL_PortType.ttcn b/library/L1CTL_PortType.ttcn
index 2775e19..eadc74a 100644
--- a/library/L1CTL_PortType.ttcn
+++ b/library/L1CTL_PortType.ttcn
@@ -90,6 +90,28 @@ module L1CTL_PortType {
return rr.payload.imm_ass;
}
+ function f_L1CTL_WAIT_IMM_ASS_TBF_DL(L1CTL_PT pt, GprsTlli tlli) return ImmediateAssignment {
+ var L1ctlDlMessage dl;
+ var GsmRrMessage rr;
+ timer T := 10.0;
+ T.start;
+ alt {
+ [] pt.receive(t_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
+ rr := dec_GsmRrMessage(dl.payload.data_ind.payload);
+ log("PCH/AGCN DL RR: ", rr);
+ if (match(rr, t_RR_IMM_ASS_TBF_DL(tlli))) {
+ log("Received IMM.ASS for our TLLI!");
+ } else {
+ repeat;
+ }
+ };
+ [] pt.receive { repeat };
+ [] T.timeout { setverdict(fail, "Timeout waiting for IMM ASS") };
+ }
+ T.stop;
+ return rr.payload.imm_ass;
+ }
+
function f_L1CTL_TBF_CFG(L1CTL_PT pt, boolean is_uplink, TfiUsfArr tfi_usf) {
timer T := 2.0;
T.start;
diff --git a/library/LAPDm_RAW_PT.ttcn b/library/LAPDm_RAW_PT.ttcn
index ab99538..f5d1926 100644
--- a/library/LAPDm_RAW_PT.ttcn
+++ b/library/LAPDm_RAW_PT.ttcn
@@ -26,7 +26,21 @@ module LAPDm_RAW_PT {
charstring err optional
}
- type record TBF_establish_res {
+ type record length(8) of uint8_t TfiList;
+ type record TbfPars {
+ GsmArfcn arfcn optional,
+ /* Temporary Flow Identifier for each TN */
+ TfiList tfi
+ }
+ type record length(8) of TbfPars TbfParsPerTs;
+
+ template TbfPars t_TbfParsInit := {
+ arfcn := omit,
+ tfi := { 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+
+ type record TBF_UL_establish_res {
+ TbfPars pars optional,
charstring err optional
}
@@ -40,10 +54,17 @@ module LAPDm_RAW_PT {
LapdmFrame lapdm
}
- type record TBF_establish_req {
+ type integer TbfNr (0..7); /* maximum of 8 concurrent TBF per direction */
+ type record TBF_UL_establish_req {
+ TbfNr tbf_nr,
uint8_t ra
}
+ type record TBF_DL_establish_req {
+ TbfNr tbf_nr,
+ TbfPars pars
+ }
+
/* PH-DATA.ind / PH-DATA.req */
type record RLCMAC_ph_data_ind {
GprsCodingScheme cs,
@@ -74,11 +95,12 @@ module LAPDm_RAW_PT {
in BCCH_tune_req,
DCCH_establish_req,
DCCH_release_req,
- TBF_establish_req,
+ TBF_UL_establish_req,
+ TBF_DL_establish_req,
RLCMAC_ph_data_req,
LAPDm_ph_data;
out DCCH_establish_res,
- TBF_establish_res,
+ TBF_UL_establish_res,
RLCMAC_ph_data_ind,
LAPDm_ph_data;
} with {extension "internal"};
@@ -86,13 +108,14 @@ module LAPDm_RAW_PT {
/* port from user (external) point of view */
type port LAPDm_PT message {
in DCCH_establish_res,
- TBF_establish_res,
+ TBF_UL_establish_res,
RLCMAC_ph_data_ind,
LAPDm_ph_data;
out BCCH_tune_req,
DCCH_establish_req,
DCCH_release_req,
- TBF_establish_req,
+ TBF_UL_establish_req,
+ TBF_DL_establish_req,
RLCMAC_ph_data_req,
LAPDm_ph_data;
} with {extension "internal"};
@@ -124,6 +147,9 @@ module LAPDm_RAW_PT {
/* channel description of the currently active DCH */
var ChannelDescription chan_desc;
+
+ var TbfParsPerTs g_tbf_ul;
+ var TbfParsPerTs g_tbf_dl;
};
/* wrapper function to log state transitions */
@@ -286,6 +312,51 @@ module LAPDm_RAW_PT {
set_ph_state(PH_STATE_BCH);
}
+ /* Establish TBF / packet transfer mode */
+ private altstep as_tbf_ul_est() runs on lapdm_CT {
+ var TBF_UL_establish_req tbf_ul_req;
+ [] LAPDM_SP.receive(TBF_UL_establish_req:?) -> value tbf_ul_req {
+ var TbfNr tbf_nr := tbf_ul_req.tbf_nr;
+ var TBF_UL_establish_res res;
+ if (isvalue(g_tbf_ul[tbf_nr].arfcn)) {
+ setverdict(fail, "Cannot establish UL TBF ID ", tbf_nr, ": BUSY");
+ self.stop;
+ }
+ f_establish_tbf(tbf_ul_req.ra);
+ if (ph_state == PH_STATE_TBF) {
+ g_tbf_ul[tbf_nr] := valueof(t_TbfParsInit); /* FIXME: Actual TFI[s] */
+ log("Established UL TBF ", tbf_nr);
+ res := { pars := g_tbf_ul[tbf_nr], err := omit };
+ } else {
+ res := { pars := omit, err := "Unable to establish UL TBF" };
+ }
+ LAPDM_SP.send(res);
+ }
+ }
+
+ private altstep as_tbf_dl_est() runs on lapdm_CT {
+ var TBF_DL_establish_req tbf_dl_req;
+ [] LAPDM_SP.receive(TBF_DL_establish_req:?) -> value tbf_dl_req {
+ var TbfNr tbf_nr := tbf_dl_req.tbf_nr;
+ if (isvalue(g_tbf_dl[tbf_nr].arfcn)) {
+ setverdict(fail, "Cannot establish DL TBF ID ", tbf_nr, ": BUSY");
+ self.stop;
+ }
+ g_tbf_dl[tbf_nr] := tbf_dl_req.pars;
+ f_L1CTL_TBF_CFG(L1CTL, false, tbf_dl_req.pars.tfi);
+ set_ph_state(PH_STATE_TBF);
+ log("Established DL TBF ", tbf_nr, ": ", tbf_dl_req.pars);
+ }
+ }
+
+ private function f_init_tbf() runs on lapdm_CT {
+ var integer i;
+ for (i := 0; i < 8; i := i+1) {
+ g_tbf_ul[i] := valueof(t_TbfParsInit);
+ g_tbf_dl[i] := valueof(t_TbfParsInit);
+ }
+ }
+
function ScanEvents() runs on lapdm_CT {
var L1ctlDlMessage dl;
var BCCH_tune_req bt;
@@ -294,7 +365,8 @@ module LAPDm_RAW_PT {
var RLCMAC_ph_data_req rpdr;
var DCCH_establish_req est_req;
var DCCH_establish_res est_res;
- var TBF_establish_req tbf_req;
+
+ f_init_tbf();
while (true) {
if (ph_state == PH_STATE_NULL) {
@@ -341,17 +413,8 @@ module LAPDm_RAW_PT {
LAPDM_SP.send(res);
}
- /* Establish TBF / packet transfer mode */
- [] LAPDM_SP.receive(TBF_establish_req:?) -> value tbf_req {
- var TBF_establish_res res;
- f_establish_tbf(tbf_req.ra);
- if (ph_state == PH_STATE_TBF) {
- res := { err := omit };
- } else {
- res := { err := "Unable to establish TBF" };
- }
- LAPDM_SP.send(res);
- }
+ [] as_tbf_ul_est();
+ [] as_tbf_dl_est();
[] LAPDM_SP.receive {}
[] L1CTL.receive {}
@@ -404,6 +467,7 @@ module LAPDm_RAW_PT {
/* decode + forward any blocks from L1 to L23*/
[] L1CTL.receive(t_L1CTL_DATA_IND(t_RslChanNr_PDCH(?))) -> value dl {
rpdi.block := dec_RlcmacDlBlock(dl.payload.data_ind.payload);
+ /* FIXME: Filter based on g_tbf_dl */
rpdi.fn := dl.dl_info.frame_nr;
rpdi.ts_nr := dl.dl_info.chan_nr.tn;
rpdi.cs := CS1; /* FIXME */
@@ -427,10 +491,14 @@ module LAPDm_RAW_PT {
}
}
+ [] as_tbf_ul_est();
+ [] as_tbf_dl_est();
+
/* FIXME: release TBF mode */
[] LAPDM_SP.receive(DCCH_release_req:?) {
/* go back to BCCH */
f_release_tbf();
+ f_init_tbf();
}
}
diff --git a/library/RLCMAC_CSN1_Types.ttcn b/library/RLCMAC_CSN1_Types.ttcn
index 95b5838..fbd01d4 100644
--- a/library/RLCMAC_CSN1_Types.ttcn
+++ b/library/RLCMAC_CSN1_Types.ttcn
@@ -524,5 +524,31 @@ module RLCMAC_CSN1_Types {
}
}
+ private const ILevel iNone := {
+ presence := '0'B,
+ i_level := omit
+ }
+ private const ChannelQualityReport c_ChQualRep_default := {
+ c_value := 0,
+ rxqual := 0,
+ sign_var := 0,
+ i_levels := { iNone, iNone, iNone, iNone, iNone, iNone, iNone, iNone }
+ }
+ template (value) RlcmacUlCtrlMsg ts_RlcMacUlCtrl_PKT_DL_ACK(uint5_t dl_tfi,
+ AckNackDescription andesc,
+ ChannelQualityReport qual_rep := c_ChQualRep_default) := {
+ msg_type := PACKET_DL_ACK_NACK,
+ u := {
+ dl_ack_nack := {
+ dl_tfi := dl_tfi,
+ ack_nack_desc := andesc,
+ chreq_desc_presence := '0'B,
+ chreq_desc := omit,
+ ch_qual_rep := qual_rep
+ }
+ }
+ }
+
+
} with { encode "RAW"; variant "FIELDORDER(msb)" variant "BYTEORDER(last)" };
diff --git a/library/RLCMAC_Types.ttcn b/library/RLCMAC_Types.ttcn
index 78861ff..3ae1203 100644
--- a/library/RLCMAC_Types.ttcn
+++ b/library/RLCMAC_Types.ttcn
@@ -323,6 +323,21 @@ uint3_t usf) := {
}
}
+ template RlcmacDlBlock tr_RLCMAC_DATA_RRBP := {
+ data := {
+ mac_hdr := {
+ mac_hdr := {
+ payload_type := MAC_PT_RLC_DATA,
+ rrbp := ?,
+ rrbp_valid := true,
+ usf := ?
+ },
+ hdr_ext := ?
+ },
+ blocks := ?
+ }
+ }
+
/* Template for Uplink MAC Control Header */
template UlMacCtrlHeader t_RLCMAC_UlMacCtrlH(template MacPayloadType pt, template boolean retry := false) := {
payload_type := pt,
diff --git a/pcu/PCU_Tests.ttcn b/pcu/PCU_Tests.ttcn
index ef46831..12b63d6 100644
--- a/pcu/PCU_Tests.ttcn
+++ b/pcu/PCU_Tests.ttcn
@@ -16,6 +16,7 @@ module PCU_Tests {
import from LAPDm_RAW_PT all;
import from GPRS_Context all;
import from GPRS_TBF all;
+ import from L1CTL_PortType all;
modulepar {
BssgpConfig mp_gb_cfg := {
@@ -221,12 +222,12 @@ module PCU_Tests {
L1.send(tune_req);
/* FIXME: wait for confirm */
- var TBF_establish_req est_req := { ra := hex2int('7B'H) };
+ var TBF_UL_establish_req est_req := { tbf_nr := 0, ra := hex2int('7B'H) };
L1.send(est_req);
T.start;
/* FIXME: wait for confirm */
alt {
- [] L1.receive(TBF_establish_res:?) {}
+ [] L1.receive(TBF_UL_establish_res:?) {}
[] L1.receive { repeat; }
[] T.timeout {
setverdict(fail, "Timeout establishing UL TBF");
@@ -526,6 +527,82 @@ function f_ul_tbf(inout UlTbfState us) runs on dummy_CT {
f_exit();
}
+ testcase TC_dl_tbf() runs on dummy_CT {
+ g_mmctx.imsi := '262420123456789'H;
+ g_mmctx.tlli := f_random_tlli();
+ f_init();
+
+ f_establish_dl_tbf();
+
+ f_exit();
+ }
+
+ function f_wait_tbf_dl(TbfNr tbf_nr, GprsTlli tlli) runs on dummy_CT return ImmediateAssignment {
+ var LAPDm_ph_data ph_data;
+ var GsmRrMessage rr;
+ timer T := 10.0;
+ T.start;
+ alt {
+ [] L1.receive(LAPDm_ph_data:{sacch:=?,sapi:=0,lapdm:={bbis:=?}}) -> value ph_data {
+ rr := dec_GsmRrMessage(ph_data.lapdm.bbis.payload);
+ log("PCH/AGCH DL RR: ", rr);
+ if (match(rr, t_RR_IMM_ASS_TBF_DL(tlli))) {
+ var TbfPars tbf_pars := valueof(t_TbfParsInit);
+ log("Received IMM.ASS for our TLLI!");
+ tbf_pars.tfi[rr.payload.imm_ass.pkt_chan_desc.tn] :=
+ rr.payload.imm_ass.rest_octets.hh.dl.group1.tfi_assignment;
+ L1.send(TBF_DL_establish_req:{tbf_nr, tbf_pars});
+ } else {
+ repeat;
+ }
+ }
+ [] L1.receive { repeat };
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for IMM ASS")
+ self.stop;
+ }
+ }
+ T.stop;
+ return rr.payload.imm_ass;
+ }
+
+ /* Establish an UL TBF: Tune to ARFCN, send RACH, receive AGCH, enable TBF Rx */
+ function f_establish_dl_tbf() runs on dummy_CT {
+ timer T := 5.0;
+ var BCCH_tune_req tune_req := { { false, 871 }, true };
+ L1.send(tune_req);
+ /* FIXME: wait for confirm */
+
+ /* sending a GMM PDU as DL-UNITDATA should trigger Paging + DL TBF Assignment */
+ tx_gmm('1'B, '01020304'O, c_LLC_SAPI_LLGMM);
+
+ /* Expect an IMM.ASS for PDCH on the AGCH */
+ f_wait_tbf_dl(0, g_mmctx.tlli);
+
+ var RLCMAC_ph_data_ind dl;
+ alt {
+ [] L1.receive(RLCMAC_ph_data_ind:{cs:=?, ts_nr:=?, fn:=?, block:=tr_RLCMAC_DATA_RRBP}) ->
+value dl {
+ var uint6_t tfi := dl.block.data.mac_hdr.hdr_ext.tfi;
+ var GsmFrameNumber ul_fn := f_rrbp_fn(dl.fn, dl.block.data.mac_hdr.mac_hdr.rrbp);
+ var AckNackDescription an_desc := { /* FIXME: compute this based on state */
+ final_ack := '1'B,
+ starting_seq_nr := 0,
+ receive_block_bitmap := '0000000000000000000000000000000000000000000000000000000000000001'B
+ }
+ var RlcmacUlCtrlMsg ctrl_ack;
+ ctrl_ack := valueof(ts_RlcMacUlCtrl_PKT_DL_ACK(tfi, an_desc));
+ var RlcmacUlBlock ul_block := valueof(ts_RLC_UL_CTRL_ACK(ctrl_ack));
+ L1.send(ts_PH_DATA_ABS(0, CS1, dl.ts_nr, ul_fn, {false, 871}, ul_block));
+ log("Sent DL ACK: ", ul_block);
+ }
+ [] L1.receive { repeat; }
+ }
+
+ f_sleep(10.0);
+ }
+
+
control {
execute(TC_selftest_bssgp());
execute(TC_selftest_ns());