blob: ab995389629a35b122df5516d1847e45036f48e0 [file] [log] [blame]
Harald Welted4ba7ff2017-07-17 21:00:48 +02001/* Test Port that stacks on top of L1CTL test port and performs LAPDm encoding/decoding, so the user can send
2 * and receive LAPDm frames in decoded TTCN-3 data types. This is particularly useful for sending/receiving
3 * all kinds of hand-crafted LAPDm frames for testing of the remote LAPDm layer */
4module LAPDm_RAW_PT {
5 import from GSM_Types all;
Harald Welteffcad682017-07-30 22:51:04 +02006 import from GSM_RR_Types all;
Harald Welted4ba7ff2017-07-17 21:00:48 +02007 import from Osmocom_Types all;
8 import from L1CTL_Types all;
9 import from L1CTL_PortType all;
10 import from LAPDm_Types all;
Harald Welte4b6c7722017-08-01 00:07:12 +020011 import from RLCMAC_Types all;
Harald Welted4ba7ff2017-07-17 21:00:48 +020012
13 /* request to tune to a given ARFCN and start BCCH decoding */
14 type record BCCH_tune_req {
15 Arfcn arfcn,
16 boolean combined_ccch
17 }
18
19 /* ask for a dedicated channel to be established */
20 type record DCCH_establish_req {
21 uint8_t ra
22 }
23
24 type record DCCH_establish_res {
25 ChannelDescription chan_desc optional,
26 charstring err optional
27 }
28
Harald Welte4b6c7722017-08-01 00:07:12 +020029 type record TBF_establish_res {
30 charstring err optional
31 }
32
Harald Welted4ba7ff2017-07-17 21:00:48 +020033 type record DCCH_release_req {
34 }
35
36 /* PH-DATA.ind / PH-DATA.req */
37 type record LAPDm_ph_data {
38 boolean sacch,
39 GsmSapi sapi,
40 LapdmFrame lapdm
41 }
42
Harald Welte4b6c7722017-08-01 00:07:12 +020043 type record TBF_establish_req {
44 uint8_t ra
45 }
46
47 /* PH-DATA.ind / PH-DATA.req */
48 type record RLCMAC_ph_data_ind {
49 GprsCodingScheme cs,
Harald Welte7024baa2018-03-02 23:37:51 +010050 uint8_t ts_nr,
51 GsmFrameNumber fn,
Harald Welte4b6c7722017-08-01 00:07:12 +020052 RlcmacDlBlock block
53 }
Harald Welte7024baa2018-03-02 23:37:51 +010054 type record RLCMAC_ph_data_req_dyn {
Harald Welte4b6c7722017-08-01 00:07:12 +020055 uint8_t tbf_id,
56 GprsCodingScheme cs,
57 RlcmacUlBlock block
58 }
Harald Welte7024baa2018-03-02 23:37:51 +010059 type record RLCMAC_ph_data_req_abs {
60 uint8_t tbf_id,
61 GprsCodingScheme cs,
62 uint8_t ts_nr,
63 GsmFrameNumber fn,
64 Arfcn arfcn,
65 RlcmacUlBlock block
66 }
67 type union RLCMAC_ph_data_req {
68 RLCMAC_ph_data_req_dyn dyn,
69 RLCMAC_ph_data_req_abs abs
70 }
Harald Welte4b6c7722017-08-01 00:07:12 +020071
Harald Welted4ba7ff2017-07-17 21:00:48 +020072 /* port from our (internal) point of view */
73 type port LAPDm_SP_PT message {
74 in BCCH_tune_req,
75 DCCH_establish_req,
76 DCCH_release_req,
Harald Welte4b6c7722017-08-01 00:07:12 +020077 TBF_establish_req,
78 RLCMAC_ph_data_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +020079 LAPDm_ph_data;
80 out DCCH_establish_res,
Harald Welte4b6c7722017-08-01 00:07:12 +020081 TBF_establish_res,
82 RLCMAC_ph_data_ind,
Harald Welted4ba7ff2017-07-17 21:00:48 +020083 LAPDm_ph_data;
84 } with {extension "internal"};
85
86 /* port from user (external) point of view */
87 type port LAPDm_PT message {
88 in DCCH_establish_res,
Harald Welte4b6c7722017-08-01 00:07:12 +020089 TBF_establish_res,
90 RLCMAC_ph_data_ind,
Harald Welted4ba7ff2017-07-17 21:00:48 +020091 LAPDm_ph_data;
92 out BCCH_tune_req,
93 DCCH_establish_req,
94 DCCH_release_req,
Harald Welte4b6c7722017-08-01 00:07:12 +020095 TBF_establish_req,
96 RLCMAC_ph_data_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +020097 LAPDm_ph_data;
98 } with {extension "internal"};
99
100 function LAPDmStart() runs on lapdm_CT {
101 f_init();
102 ScanEvents();
103 }
104
105 /* TS 44.004 Figure 5.1 */
106 type enumerated ph_state_enum {
107 PH_STATE_NULL,
108 PH_STATE_BCH,
109 PH_STATE_SEARCHING_BCH,
110 PH_STATE_TUNING_DCH,
Harald Welte4b6c7722017-08-01 00:07:12 +0200111 PH_STATE_DCH,
112 PH_STATE_TBF
Harald Welted4ba7ff2017-07-17 21:00:48 +0200113 }
114
115 type component lapdm_CT {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200116
117 /* L1CTL port towards the bottom */
118 port L1CTL_PT L1CTL;
119 /* Port towards L2 */
120 port LAPDm_SP_PT LAPDM_SP;
121
122 /* physical layer state */
123 var ph_state_enum ph_state := PH_STATE_NULL;
124
125 /* channel description of the currently active DCH */
126 var ChannelDescription chan_desc;
127 };
128
129 /* wrapper function to log state transitions */
130 private function set_ph_state(ph_state_enum new_state) runs on lapdm_CT {
131 log("PH-STATE ", ph_state, " -> ", new_state);
132 ph_state := new_state;
133 }
134
135 private function f_init() runs on lapdm_CT {
Harald Welteb26cfff2017-08-25 09:56:47 +0200136 f_connect_reset(L1CTL);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200137 set_ph_state(PH_STATE_NULL);
138 }
139
140 /* release the dedicated radio channel */
141 private function f_release_dcch() runs on lapdm_CT {
142 L1CTL.send(t_L1CTL_DM_REL_REQ(chan_desc.chan_nr));
Harald Welte4b6c7722017-08-01 00:07:12 +0200143 set_ph_state(PH_STATE_BCH);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200144 }
145
146 /* tune to given ARFCN and start BCCH/CCCH decoding */
147 private function f_tune_bcch(Arfcn arfcn, boolean combined) runs on lapdm_CT {
148 var L1ctlCcchMode mode := CCCH_MODE_NON_COMBINED;
149 if (combined) {
150 mode := CCCH_MODE_COMBINED;
151 }
152
153 if (ph_state == PH_STATE_DCH) {
154 /* release any previous DCH */
155 f_release_dcch();
Harald Welte4b6c7722017-08-01 00:07:12 +0200156 } else if (ph_state == PH_STATE_TBF) {
157 f_release_tbf();
Harald Welted4ba7ff2017-07-17 21:00:48 +0200158 }
159
160 set_ph_state(PH_STATE_SEARCHING_BCH);
161
162 /* send FB/SB req to sync to cell */
163 f_L1CTL_FBSB(L1CTL, arfcn, mode);
164 set_ph_state(PH_STATE_BCH);
165 }
166
167 /* master function establishing a dedicated radio channel */
168 private function f_establish_dcch(uint8_t ra) runs on lapdm_CT {
169 var ImmediateAssignment imm_ass;
170 var GsmFrameNumber rach_fn;
171
172 /* send RACH request and obtain FN at which it was sent */
173 rach_fn := f_L1CTL_RACH(L1CTL, ra);
174 //if (not rach_fn) { return; }
175
176 /* wait for receiving matching IMM ASS */
177 imm_ass := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, rach_fn)
178 //if (not imm_ass) { return; }
179 set_ph_state(PH_STATE_TUNING_DCH);
180
181 /* store/save channel description */
182 chan_desc := imm_ass.chan_desc;
183
184 /* send DM_EST_REQ */
185 f_L1CTL_DM_EST_REQ_IA(L1CTL, imm_ass);
186 set_ph_state(PH_STATE_DCH);
187 }
188
Harald Welte4b6c7722017-08-01 00:07:12 +0200189 /* initialize a tfi_usf array with "not used" value 255 for all TN */
190 function f_TfiUsfArrInit() return TfiUsfArr {
191 var TfiUsfArr tua := { 255, 255, 255, 255, 255, 255, 255, 255 };
192 return tua;
193 }
194
195 /* set TFI/USF value for one given timeslot number (index) */
196 function f_TfiUsfArrSet(inout TfiUsfArr a, in uint8_t idx, in uint8_t tfi_usf) {
197 a[idx] := tfi_usf;
198 }
199
200 /* Match an IMM.ASS for an Uplink TBF with a dynamic allocation */
201 template ImmediateAssignment t_IMM_ASS_TBF_UL_DYN(uint8_t ra, GsmFrameNumber fn) modifies t_IMM_ASS := {
202 ded_or_tbf := { spare := ?, tma := ?, downlink := false, tbf := true},
203 chan_desc := omit,
204 pkt_chan_desc := ?,
205 rest_octets := {
206 presence := '11'B,
207 ll := omit,
208 lh := omit,
209 hl := omit,
210 hh := {
211 presence := '00'B,
212 ul := {
213 presence := '1'B,
214 dynamic := {
215 tfi_assignment := ?,
216 polling := ?,
217 spare := '0'B,
218 usf := ?,
219 usf_granularity := ?,
220 p0_present := ?,
221 p0 := *,
222 pr_mode := *,
223 ch_coding_cmd := ?,
224 tlli_block_chan_coding:= ?,
225 alpha_present := ?,
226 alpha := *,
227 gamma := ?,
228 ta_index_present := ?,
229 ta_index := *,
230 tbf_starting_time_present := ?,
231 tbf_starting_time := *
232 },
233 single := omit
234 },
235 dl := omit
236 }
237 }
238 };
239
Harald Welte7024baa2018-03-02 23:37:51 +0100240 template (value) RLCMAC_ph_data_req ts_PH_DATA_ABS(uint8_t tbf_id, GprsCodingScheme cs,
241 uint8_t ts, uint32_t fn, Arfcn arfcn,
242 RlcmacUlBlock block) := {
243 abs := {
244 tbf_id := tbf_id,
245 cs := CS1, /* FIXME */
246 ts_nr := ts,
247 fn := fn,
248 arfcn := arfcn,
249 block := block
250 }
251 }
252
Harald Welte4b6c7722017-08-01 00:07:12 +0200253 private function f_establish_tbf(uint8_t ra) runs on lapdm_CT {
254 var ImmediateAssignment imm_ass;
255 var GsmFrameNumber rach_fn;
256 var TfiUsfArr tua := f_TfiUsfArrInit();
257
258 /* send RACH request and obtain FN at which it was sent */
259 rach_fn := f_L1CTL_RACH(L1CTL, ra);
260
261 /* wait for receiving matching IMM ASS */
262 imm_ass := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, rach_fn);
263
264 if (match(imm_ass, t_IMM_ASS_TBF_UL_DYN(ra, rach_fn))) {
265 set_ph_state(PH_STATE_TBF);
266
267 /* store/save channel description */
268 //chan_desc := imm_ass.chan_desc;
269
270 /* Important: ARFCN, TN, TSC, USF, USF_GRANULARITY, CH_CODING_CMD */
271 f_TfiUsfArrSet(tua, imm_ass.pkt_chan_desc.tn, imm_ass.rest_octets.hh.ul.dynamic.usf);
272 f_L1CTL_TBF_CFG(L1CTL, true, tua);
273 } else {
274 /* FIXME: single block uplink allocation */
275 log("Failed to match ", t_IMM_ASS_TBF_UL_DYN(ra, rach_fn));
276 log("Non-dynamic UL TBF assignment not supported yet");
277 }
278 }
279
280 private function f_release_tbf() runs on lapdm_CT {
281 var TfiUsfArr tua := f_TfiUsfArrInit();
282 /* send "all timeslots unused" for both UL and DL */
283 f_L1CTL_TBF_CFG(L1CTL, true, tua);
284 f_L1CTL_TBF_CFG(L1CTL, false, tua);
285 /* L1 will then fall back to BCCH/CCCH */
286 set_ph_state(PH_STATE_BCH);
287 }
288
Harald Welted4ba7ff2017-07-17 21:00:48 +0200289 function ScanEvents() runs on lapdm_CT {
290 var L1ctlDlMessage dl;
291 var BCCH_tune_req bt;
292 var LAPDm_ph_data lpd;
Harald Welte4b6c7722017-08-01 00:07:12 +0200293 var RLCMAC_ph_data_ind rpdi;
294 var RLCMAC_ph_data_req rpdr;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200295 var DCCH_establish_req est_req;
296 var DCCH_establish_res est_res;
Harald Welte4b6c7722017-08-01 00:07:12 +0200297 var TBF_establish_req tbf_req;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200298
299 while (true) {
300 if (ph_state == PH_STATE_NULL) {
301 alt {
302 [] LAPDM_SP.receive(BCCH_tune_req:?) -> value bt {
303 f_tune_bcch(bt.arfcn, bt.combined_ccch);
304 }
305
306 [] LAPDM_SP.receive {}
307 [] L1CTL.receive {}
308
309 }
310 } else if (ph_state == PH_STATE_BCH or ph_state == PH_STATE_SEARCHING_BCH) {
311 alt {
312 [] LAPDM_SP.receive(BCCH_tune_req:?) -> value bt {
313 f_tune_bcch(bt.arfcn, bt.combined_ccch);
314 }
315
316 /* forward CCCH SAPI from L1CTL to User */
317 [] L1CTL.receive(t_L1CTL_DATA_IND(t_RslChanNr_BCCH(0))) -> value dl {
318 lpd.sacch := false;
319 lpd.sapi := 0;
320 lpd.lapdm.bbis := dec_LapdmFrameBbis(dl.payload.data_ind.payload);
321 LAPDM_SP.send(lpd);
322 }
323
324 /* forward BCCH SAPI from L1CTL to User */
325 [] L1CTL.receive(t_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
326 lpd.sacch := false;
327 lpd.sapi := 0;
328 lpd.lapdm.bbis := dec_LapdmFrameBbis(dl.payload.data_ind.payload);
329 LAPDM_SP.send(lpd);
330 }
331
332 /* Establish dedicated channel */
333 [] LAPDM_SP.receive(DCCH_establish_req:?) -> value est_req {
334 var DCCH_establish_res res;
335 f_establish_dcch(est_req.ra);
336 if (ph_state == PH_STATE_DCH) {
337 res := { chan_desc, omit };
338 } else {
339 res := { omit, "Unable to esetablish DCCH" };
340 }
341 LAPDM_SP.send(res);
342 }
343
Harald Welte4b6c7722017-08-01 00:07:12 +0200344 /* Establish TBF / packet transfer mode */
345 [] LAPDM_SP.receive(TBF_establish_req:?) -> value tbf_req {
346 var TBF_establish_res res;
347 f_establish_tbf(tbf_req.ra);
348 if (ph_state == PH_STATE_TBF) {
349 res := { err := omit };
350 } else {
351 res := { err := "Unable to establish TBF" };
352 }
353 LAPDM_SP.send(res);
354 }
355
Harald Welted4ba7ff2017-07-17 21:00:48 +0200356 [] LAPDM_SP.receive {}
357 [] L1CTL.receive {}
358
359 }
360
361 } else if (ph_state == PH_STATE_TUNING_DCH or ph_state == PH_STATE_DCH) {
362 alt {
363
364 /* decode any received DATA frames for the dedicated channel and pass them up */
365 [] L1CTL.receive(t_L1CTL_DATA_IND(chan_desc.chan_nr)) -> value dl {
366 if (dl.dl_info.link_id.c == SACCH) {
367 lpd.sacch := true;
368 /* FIXME: how to deal with UI frames in B4 format (lo length!) */
369 } else {
370 lpd.sacch := false;
371 }
372 lpd.sapi := dl.dl_info.link_id.sapi;
373 lpd.lapdm.b := dec_LapdmFrameB(dl.payload.data_ind.payload);
374 LAPDM_SP.send(lpd);
375 }
376
377 /* encode any LAPDm record from user and pass it on to L1CTL */
378 [] LAPDM_SP.receive(LAPDm_ph_data:?) -> value lpd {
379 var octetstring buf;
380 var RslLinkId link_id;
381 if (lpd.sacch) {
382 link_id := valueof(ts_RslLinkID_SACCH(lpd.sapi));
383 } else {
384 link_id := valueof(ts_RslLinkID_DCCH(lpd.sapi));
385 }
386 buf := enc_LapdmFrame(lpd.lapdm);
387 L1CTL.send(t_L1CTL_DATA_REQ(chan_desc.chan_nr, link_id, buf));
388 }
389
390 /* Release dedicated channel */
391 [] LAPDM_SP.receive(DCCH_release_req:?) {
392 /* go back to BCCH */
393 f_release_dcch();
394 }
395
396 [] LAPDM_SP.receive {}
397 [] L1CTL.receive {}
398
399
400 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200401 } else if (ph_state == PH_STATE_TBF) {
402 alt {
403
404 /* decode + forward any blocks from L1 to L23*/
405 [] L1CTL.receive(t_L1CTL_DATA_IND(t_RslChanNr_PDCH(?))) -> value dl {
406 rpdi.block := dec_RlcmacDlBlock(dl.payload.data_ind.payload);
Harald Welte7024baa2018-03-02 23:37:51 +0100407 rpdi.fn := dl.dl_info.frame_nr;
408 rpdi.ts_nr := dl.dl_info.chan_nr.tn;
Harald Welte4b6c7722017-08-01 00:07:12 +0200409 rpdi.cs := CS1; /* FIXME */
410 log("RPDI: ", rpdi);
411 LAPDM_SP.send(rpdi);
412 }
413
414 [] L1CTL.receive { }
415
416 /* encode + forward any blocks from L23 to L1 */
417 [] LAPDM_SP.receive(RLCMAC_ph_data_req:?) -> value rpdr {
418 var octetstring buf;
Harald Welte7024baa2018-03-02 23:37:51 +0100419 if (ischosen(rpdr.dyn)) {
420 buf := enc_RlcmacUlBlock(rpdr.dyn.block);
421 L1CTL.send(t_L1CTL_DATA_TBF_REQ(buf, L1CTL_CS1, rpdr.dyn.tbf_id));
422 } else {
423 buf := enc_RlcmacUlBlock(rpdr.abs.block);
424 L1CTL.send(t_L1CTL_DATA_ABS_REQ(buf, rpdr.abs.arfcn,
425 rpdr.abs.ts_nr, rpdr.abs.fn,
426 L1CTL_CS1, rpdr.abs.tbf_id));
427 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200428 }
429
430 /* FIXME: release TBF mode */
431 [] LAPDM_SP.receive(DCCH_release_req:?) {
432 /* go back to BCCH */
433 f_release_tbf();
434 }
435
436 }
Harald Welted4ba7ff2017-07-17 21:00:48 +0200437 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200438
Harald Welted4ba7ff2017-07-17 21:00:48 +0200439 } /* while (1) */
440 }
441}