Add new LAPDm RAW port
This is a Test Component which sits on top of L1CTL (which in turn is on
top of the Unix Domain Socket Test Porrt). It performs LAPDm message
encoding/decoding, so we can use the regular send() / receive() methods
and associated template matching to send/receive/match LAPDm in a
comfortable way.
diff --git a/lapd/L1CTL_Test.ttcn b/lapd/L1CTL_Test.ttcn
index 3ff063d..e3d149e 100644
--- a/lapd/L1CTL_Test.ttcn
+++ b/lapd/L1CTL_Test.ttcn
@@ -1,119 +1,164 @@
module L1CTL_Test {
import from GSM_Types all;
import from Osmocom_Types all;
- import from L1CTL_Types all;
- import from L1CTL_PortType all;
+ import from LAPDm_RAW_PT all;
import from LAPDm_Types all;
- const octetstring c_ul_param_req := '1300000000000000001d0000'O;
- const octetstring c_ul_data_req := '060a0128284018001d000103490615004001c0000000000000000000000000'O;
- const octetstring c_ul_ccch_mode_req := '1000000002000000'O;
- const octetstring c_ul_reset_req := '0d00000002000000'O;
- const octetstring c_ul_dm_est_req := '050000002800000007000367000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005'O;
- const octetstring c_ul_rach_req := '040000000000000012010008'O;
-
- const octetstring c_dl_data_ind := '03000000900003670015f5613f3f00002d063f0328e36712ead000002b2b2b2b2b2b2b2b2b2b2b'O;
-
type component dummy_CT {
- var charstring l1ctl_sock_path := "/tmp/osmocom_l2";
- port L1CTL_PT L1CTL;
- var ChannelDescription chan_desc;
+ port LAPDm_PT LAPDM;
+ var lapdm_CT lapdm_component;
};
-
function f_init() runs on dummy_CT {
- map(self:L1CTL, system:L1CTL);
- L1CTL.send(L1CTL_connect:{path:=l1ctl_sock_path});
- L1CTL.receive(L1CTL_connect_result:{result_code := SUCCESS, err:=omit});
+ /* create the LAPDm component */
+ lapdm_component := lapdm_CT.create;
+ /* connect our own LAPDM port to the LAPDM Service Provider of the LAPDm component */
+ connect(self:LAPDM, lapdm_component:LAPDM_SP);
+ /* connect the LAPDm compoent's lower-side port to the system L1CTL port (which is internally
+ * connected to the Unix Domain Socket test port */
+ map(lapdm_component:L1CTL, system:L1CTL);
- L1CTL.send(t_L1ctlResetReq(L1CTL_RES_T_SCHED));
- L1CTL.receive;
+ /* start the LAPDm parallel component calling it's local function LAPDmStart */
+ lapdm_component.start(LAPDmStart());
}
- /* a very ppor man's job to check if we can actually still decode the L1CTL binary messages */
- testcase TC_selftest() runs on dummy_CT {
- log("L1CTL_PARAM_REQ: ", dec_L1ctlUlMessage(c_ul_param_req));
- log("L1CTL_DATA_REQ: ", dec_L1ctlUlMessage(c_ul_data_req));
- log("L1CTL_CCCH_MODE_REQ: ", dec_L1ctlUlMessage(c_ul_ccch_mode_req));
- log("L1CTL_RESET_REQ: ", dec_L1ctlUlMessage(c_ul_reset_req));
- log("L1CTL_DM_EST_REQ: ", dec_L1ctlUlMessage(c_ul_dm_est_req));
- log("L1CTL_RACH_REQ: ", dec_L1ctlUlMessage(c_ul_rach_req));
- log("L1CTL_DATA_IND: ", dec_L1ctlDlMessage(c_dl_data_ind));
- setverdict(pass);
- }
-
- /* master function establishing a dedicated radio channel */
+ /* master function establishing a dedicated radio channel (takes care of RACH/IMM.ASS handling) */
function f_establish_dcch() runs on dummy_CT {
- var ImmediateAssignment imm_ass;
- var GsmFrameNumber rach_fn;
- var uint8_t ra := 23;
+ var BCCH_tune_req tune_req := { arfcn := { false, 871 }, combined_ccch := true };
+ var DCCH_establish_req est_req := { ra := 23 };
- /* send FB/SB req to sync to cell */
- f_L1CTL_FBSB(L1CTL, { false, 871 }, CCCH_MODE_COMBINED);
- /* send RACH request and obtain FN at which it was sent */
- rach_fn := f_L1CTL_RACH(L1CTL, ra);
- /* wait for receiving matching IMM ASS */
- imm_ass := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, rach_fn)
- /* send DM_EST_REQ */
- f_L1CTL_DM_EST_REQ_IA(L1CTL, imm_ass);
-
- chan_desc := imm_ass.chan_desc;
+ LAPDM.send(tune_req);
+ LAPDM.send(est_req);
+ LAPDM.receive(DCCH_establish_res:?);
}
- /* send some data over an established dedicated radio channel */
- function f_send_l2(template RslLinkId link_id, octetstring l2_data) runs on dummy_CT {
- L1CTL.send(t_L1CTL_DATA_REQ(chan_desc.chan_nr, link_id, l2_data));
- }
-
- /* send some data over an established dedicated radio channel */
- function f_send_l2_lapdm_b(template RslLinkId link_id, template LapdmFrameB b) runs on dummy_CT {
- var octetstring l2_data := enc_LapdmFrameB(valueof(b));
- L1CTL.send(t_L1CTL_DATA_REQ(chan_desc.chan_nr, link_id, l2_data));
- }
-
-
- function f_recv_l2() runs on dummy_CT return octetstring {
- var L1ctlDlMessage dl;
- var octetstring l2_data;
- timer T := 5.0;
- T.start
- alt {
- [] L1CTL.receive(t_L1CTL_DATA_IND(chan_desc.chan_nr)) -> value dl { l2_data := dl.payload.data_ind.payload };
- [] L1CTL.receive { repeat; };
- [] T.timeout { setverdict(fail, "Timeout waiting for DL data"); };
- }
- return l2_data;
- }
-
- /* release the dedicated radio channel */
+ /* helper function releasing dedicated radio channel physically (no Um signaling!) */
function f_release_dcch() runs on dummy_CT {
- L1CTL.send(t_L1CTL_DM_REL_REQ(chan_desc.chan_nr));
+ var DCCH_release_req rel_req := {};
+ LAPDM.send(rel_req);
}
- template LapdmFrameB LAPDm_SABM(template GsmSapi sapi, template octetstring payload) := {
- addr := tr_LapdmAddr(sapi, false),
- ctrl := t_LapdmCtrlSABM(true),
- len := t_LapdmLengthIndicator(lengthof(payload)),
- payload := payload
+ template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := {
+ sacch := sacch,
+ sapi := sapi,
+ lapdm := frame
+ }
+ /* template for a valid SABM frame */
+ template LapdmFrame LAPDm_B_SABM(template GsmSapi sapi, template octetstring payload) := {
+ b := {
+ addr := tr_LapdmAddr(sapi, false),
+ ctrl := t_LapdmCtrlSABM(true),
+ len := lengthof(payload),
+ m := false,
+ el := 1,
+ payload := payload
+ }
}
- testcase TC_l1ctl() runs on dummy_CT {
- f_init();
+ /* template for a valid UA frame */
+ template LapdmFrame LAPDm_B_UA(template GsmSapi sapi, template octetstring payload) := {
+ b := {
+ addr := tr_LapdmAddr(sapi, false),
+ ctrl := t_LapdmCtrlUA(true),
+ len := lengthof(payload),
+ m := false,
+ el := 1,
+ payload := payload
+ }
+ }
+
+ /* template for a valid UI frame */
+ template LapdmFrame LAPDm_B_UI(template GsmSapi sapi, template octetstring payload) := {
+ b := {
+ addr := tr_LapdmAddr(sapi, true),
+ ctrl := t_LapdmCtrlUI(false),
+ len := lengthof(payload),
+ m := false,
+ el := 1,
+ payload := payload
+ }
+ }
+
+ function f_test_sabm_results_in_ua(uint8_t sapi, boolean use_sacch, octetstring payload) runs on dummy_CT return boolean {
+ var LAPDm_ph_data phd;
+ var boolean result := false;
+ timer T := 5.0;
f_establish_dcch();
-
- f_send_l2_lapdm_b(ts_RslLinkID_DCCH(0), LAPDm_SABM(0, 'FEFE'O));
- f_recv_l2();
-
- //f_send_l2(ts_RslLinkID_DCCH(0), '000102030405060708090a0b0c0d0e0f10111213141516'O);
-
+ LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, payload)));
+ log("====> expecting ", t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload)));
+ T.start
+ alt {
+ [] LAPDM.receive(t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload))) { result := true; }
+ [] LAPDM.receive(t_PH_DATA(sapi, use_sacch, ?)) -> value phd { log("Other msg on DCH: ", phd); repeat; }
+ [] LAPDM.receive(t_PH_DATA(?, ?, ?)) -> value phd { log("Other PH-DATA: ", phd); repeat; }
+ [] T.timeout { setverdict(fail); }
+ }
f_release_dcch();
+ return result;
+ }
+ testcase TC_sabm_ua_dcch_sapi0() runs on dummy_CT {
+ f_init();
+ if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
+ setverdict(fail);
+ }
setverdict(pass);
}
+ testcase TC_sabm_ua_dcch_sapi0_nopayload() runs on dummy_CT {
+ f_init();
+ if (not f_test_sabm_results_in_ua(0, false, ''O)) {
+ setverdict(fail);
+ }
+ setverdict(pass);
+ }
+
+ testcase TC_sabm_ua_dcch_sapi3() runs on dummy_CT {
+ f_init();
+ if (not f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
+ setverdict(fail);
+ }
+ setverdict(pass);
+ }
+
+ testcase TC_sabm_ua_dcch_sapi4() runs on dummy_CT {
+ f_init();
+ if (not f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
+ setverdict(fail);
+ }
+ setverdict(pass);
+ }
+
+
+ testcase TC_foo() runs on dummy_CT {
+/*
+ var LapdmFrame lf := valueof(LAPDm_B_UA(0, ''O));
+ log("ENC UA: ", enc_LapdmFrame(lf));
+ lf := valueof(LAPDm_B_UI(0, ''O));
+ log("ENC UI B: ", enc_LapdmFrame(lf));
+ log("ENC UI B: ", enc_LapdmFrameB(lf.b));
+
+ log("DEC UI AF: ", dec_LapdmAddressField('03'O));
+*/
+ log("DEC UI CU: ", dec_LapdmCtrlU('03'O));
+ log("DEC UI CT: ", dec_LapdmCtrl('03'O));
+
+ log("DEC UA: ", dec_LapdmFrameB('017301'O));
+ log("DEC UI: ", dec_LapdmFrameA('030301'O));
+ log("DEC I: ", dec_LapdmFrameA('030001'O));
+ log("DEC S: ", dec_LapdmFrameA('030101'O));
+ log("DEC: ", dec_LapdmFrameB('030301'O));
+ log("DEC: ", dec_LapdmFrameB('0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O));
+ }
+
control {
- execute(TC_selftest());
- execute(TC_l1ctl());
+ execute(TC_foo());
+ execute(TC_sabm_ua_dcch_sapi0());
+/*
+ execute(TC_sabm_ua_dcch_sapi0_nopayload());
+ execute(TC_sabm_ua_dcch_sapi3());
+ execute(TC_sabm_ua_dcch_sapi4());
+*/
}
}