blob: fe2d32127083ca00770a5079be4252f2b1dd0716 [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 */
Harald Welte34b5a952019-05-27 11:54:11 +02004
5/* (C) 2017-2018 Harald Welte <laforge@gnumonks.org>
6 * All rights reserved.
7 *
8 * Released under the terms of GNU General Public License, Version 2 or
9 * (at your option) any later version.
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13
Harald Welted4ba7ff2017-07-17 21:00:48 +020014module LAPDm_RAW_PT {
15 import from GSM_Types all;
Harald Welteffcad682017-07-30 22:51:04 +020016 import from GSM_RR_Types all;
Harald Welted4ba7ff2017-07-17 21:00:48 +020017 import from Osmocom_Types all;
18 import from L1CTL_Types all;
19 import from L1CTL_PortType all;
20 import from LAPDm_Types all;
Harald Welte4b6c7722017-08-01 00:07:12 +020021 import from RLCMAC_Types all;
Harald Welted4ba7ff2017-07-17 21:00:48 +020022
23 /* request to tune to a given ARFCN and start BCCH decoding */
24 type record BCCH_tune_req {
25 Arfcn arfcn,
26 boolean combined_ccch
27 }
28
29 /* ask for a dedicated channel to be established */
30 type record DCCH_establish_req {
31 uint8_t ra
32 }
33
34 type record DCCH_establish_res {
35 ChannelDescription chan_desc optional,
36 charstring err optional
37 }
38
Harald Welteb669ee02018-03-09 12:50:02 +010039 type record length(8) of uint8_t TfiList;
40 type record TbfPars {
41 GsmArfcn arfcn optional,
42 /* Temporary Flow Identifier for each TN */
43 TfiList tfi
44 }
45 type record length(8) of TbfPars TbfParsPerTs;
46
47 template TbfPars t_TbfParsInit := {
48 arfcn := omit,
49 tfi := { 255, 255, 255, 255, 255, 255, 255, 255 }
50 }
51
52 type record TBF_UL_establish_res {
53 TbfPars pars optional,
Harald Welte4b6c7722017-08-01 00:07:12 +020054 charstring err optional
55 }
56
Harald Welted4ba7ff2017-07-17 21:00:48 +020057 type record DCCH_release_req {
58 }
59
60 /* PH-DATA.ind / PH-DATA.req */
61 type record LAPDm_ph_data {
62 boolean sacch,
63 GsmSapi sapi,
64 LapdmFrame lapdm
65 }
66
Harald Welteb669ee02018-03-09 12:50:02 +010067 type integer TbfNr (0..7); /* maximum of 8 concurrent TBF per direction */
68 type record TBF_UL_establish_req {
69 TbfNr tbf_nr,
Harald Welte4b6c7722017-08-01 00:07:12 +020070 uint8_t ra
71 }
72
Harald Welteb669ee02018-03-09 12:50:02 +010073 type record TBF_DL_establish_req {
74 TbfNr tbf_nr,
75 TbfPars pars
76 }
77
Harald Welte4b6c7722017-08-01 00:07:12 +020078 /* PH-DATA.ind / PH-DATA.req */
79 type record RLCMAC_ph_data_ind {
80 GprsCodingScheme cs,
Harald Welte7024baa2018-03-02 23:37:51 +010081 uint8_t ts_nr,
82 GsmFrameNumber fn,
Harald Welte4b6c7722017-08-01 00:07:12 +020083 RlcmacDlBlock block
84 }
Harald Welte7024baa2018-03-02 23:37:51 +010085 type record RLCMAC_ph_data_req_dyn {
Harald Welte4b6c7722017-08-01 00:07:12 +020086 uint8_t tbf_id,
87 GprsCodingScheme cs,
88 RlcmacUlBlock block
89 }
Harald Welte7024baa2018-03-02 23:37:51 +010090 type record RLCMAC_ph_data_req_abs {
91 uint8_t tbf_id,
92 GprsCodingScheme cs,
93 uint8_t ts_nr,
94 GsmFrameNumber fn,
95 Arfcn arfcn,
96 RlcmacUlBlock block
97 }
98 type union RLCMAC_ph_data_req {
99 RLCMAC_ph_data_req_dyn dyn,
100 RLCMAC_ph_data_req_abs abs
101 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200102
Harald Welted4ba7ff2017-07-17 21:00:48 +0200103 /* port from our (internal) point of view */
104 type port LAPDm_SP_PT message {
105 in BCCH_tune_req,
106 DCCH_establish_req,
107 DCCH_release_req,
Harald Welteb669ee02018-03-09 12:50:02 +0100108 TBF_UL_establish_req,
109 TBF_DL_establish_req,
Harald Welte4b6c7722017-08-01 00:07:12 +0200110 RLCMAC_ph_data_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200111 LAPDm_ph_data;
112 out DCCH_establish_res,
Harald Welteb669ee02018-03-09 12:50:02 +0100113 TBF_UL_establish_res,
Harald Welte4b6c7722017-08-01 00:07:12 +0200114 RLCMAC_ph_data_ind,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200115 LAPDm_ph_data;
116 } with {extension "internal"};
117
118 /* port from user (external) point of view */
119 type port LAPDm_PT message {
120 in DCCH_establish_res,
Harald Welteb669ee02018-03-09 12:50:02 +0100121 TBF_UL_establish_res,
Harald Welte4b6c7722017-08-01 00:07:12 +0200122 RLCMAC_ph_data_ind,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200123 LAPDm_ph_data;
124 out BCCH_tune_req,
125 DCCH_establish_req,
126 DCCH_release_req,
Harald Welteb669ee02018-03-09 12:50:02 +0100127 TBF_UL_establish_req,
128 TBF_DL_establish_req,
Harald Welte4b6c7722017-08-01 00:07:12 +0200129 RLCMAC_ph_data_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200130 LAPDm_ph_data;
131 } with {extension "internal"};
132
133 function LAPDmStart() runs on lapdm_CT {
134 f_init();
135 ScanEvents();
136 }
137
138 /* TS 44.004 Figure 5.1 */
139 type enumerated ph_state_enum {
140 PH_STATE_NULL,
141 PH_STATE_BCH,
142 PH_STATE_SEARCHING_BCH,
143 PH_STATE_TUNING_DCH,
Harald Welte4b6c7722017-08-01 00:07:12 +0200144 PH_STATE_DCH,
145 PH_STATE_TBF
Harald Welted4ba7ff2017-07-17 21:00:48 +0200146 }
147
148 type component lapdm_CT {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200149
150 /* L1CTL port towards the bottom */
151 port L1CTL_PT L1CTL;
152 /* Port towards L2 */
153 port LAPDm_SP_PT LAPDM_SP;
154
155 /* physical layer state */
156 var ph_state_enum ph_state := PH_STATE_NULL;
157
158 /* channel description of the currently active DCH */
159 var ChannelDescription chan_desc;
Harald Welteb669ee02018-03-09 12:50:02 +0100160
161 var TbfParsPerTs g_tbf_ul;
162 var TbfParsPerTs g_tbf_dl;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200163 };
164
165 /* wrapper function to log state transitions */
166 private function set_ph_state(ph_state_enum new_state) runs on lapdm_CT {
167 log("PH-STATE ", ph_state, " -> ", new_state);
168 ph_state := new_state;
169 }
170
171 private function f_init() runs on lapdm_CT {
Harald Welteb26cfff2017-08-25 09:56:47 +0200172 f_connect_reset(L1CTL);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200173 set_ph_state(PH_STATE_NULL);
174 }
175
176 /* release the dedicated radio channel */
177 private function f_release_dcch() runs on lapdm_CT {
Harald Weltef8df4cb2018-03-10 15:15:08 +0100178 L1CTL.send(ts_L1CTL_DM_REL_REQ(chan_desc.chan_nr));
Harald Welte4b6c7722017-08-01 00:07:12 +0200179 set_ph_state(PH_STATE_BCH);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200180 }
181
182 /* tune to given ARFCN and start BCCH/CCCH decoding */
183 private function f_tune_bcch(Arfcn arfcn, boolean combined) runs on lapdm_CT {
184 var L1ctlCcchMode mode := CCCH_MODE_NON_COMBINED;
185 if (combined) {
186 mode := CCCH_MODE_COMBINED;
187 }
188
189 if (ph_state == PH_STATE_DCH) {
190 /* release any previous DCH */
191 f_release_dcch();
Harald Welte4b6c7722017-08-01 00:07:12 +0200192 } else if (ph_state == PH_STATE_TBF) {
193 f_release_tbf();
Harald Welted4ba7ff2017-07-17 21:00:48 +0200194 }
195
196 set_ph_state(PH_STATE_SEARCHING_BCH);
197
198 /* send FB/SB req to sync to cell */
199 f_L1CTL_FBSB(L1CTL, arfcn, mode);
200 set_ph_state(PH_STATE_BCH);
201 }
202
203 /* master function establishing a dedicated radio channel */
204 private function f_establish_dcch(uint8_t ra) runs on lapdm_CT {
205 var ImmediateAssignment imm_ass;
206 var GsmFrameNumber rach_fn;
207
208 /* send RACH request and obtain FN at which it was sent */
209 rach_fn := f_L1CTL_RACH(L1CTL, ra);
210 //if (not rach_fn) { return; }
211
212 /* wait for receiving matching IMM ASS */
213 imm_ass := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, rach_fn)
214 //if (not imm_ass) { return; }
215 set_ph_state(PH_STATE_TUNING_DCH);
216
217 /* store/save channel description */
218 chan_desc := imm_ass.chan_desc;
219
220 /* send DM_EST_REQ */
221 f_L1CTL_DM_EST_REQ_IA(L1CTL, imm_ass);
222 set_ph_state(PH_STATE_DCH);
223 }
224
Harald Welte4b6c7722017-08-01 00:07:12 +0200225 /* initialize a tfi_usf array with "not used" value 255 for all TN */
226 function f_TfiUsfArrInit() return TfiUsfArr {
227 var TfiUsfArr tua := { 255, 255, 255, 255, 255, 255, 255, 255 };
228 return tua;
229 }
230
231 /* set TFI/USF value for one given timeslot number (index) */
232 function f_TfiUsfArrSet(inout TfiUsfArr a, in uint8_t idx, in uint8_t tfi_usf) {
233 a[idx] := tfi_usf;
234 }
235
236 /* Match an IMM.ASS for an Uplink TBF with a dynamic allocation */
237 template ImmediateAssignment t_IMM_ASS_TBF_UL_DYN(uint8_t ra, GsmFrameNumber fn) modifies t_IMM_ASS := {
238 ded_or_tbf := { spare := ?, tma := ?, downlink := false, tbf := true},
239 chan_desc := omit,
240 pkt_chan_desc := ?,
241 rest_octets := {
242 presence := '11'B,
243 ll := omit,
244 lh := omit,
245 hl := omit,
246 hh := {
247 presence := '00'B,
248 ul := {
249 presence := '1'B,
250 dynamic := {
251 tfi_assignment := ?,
252 polling := ?,
253 spare := '0'B,
254 usf := ?,
255 usf_granularity := ?,
256 p0_present := ?,
257 p0 := *,
258 pr_mode := *,
259 ch_coding_cmd := ?,
260 tlli_block_chan_coding:= ?,
261 alpha_present := ?,
262 alpha := *,
263 gamma := ?,
264 ta_index_present := ?,
265 ta_index := *,
266 tbf_starting_time_present := ?,
267 tbf_starting_time := *
268 },
269 single := omit
270 },
271 dl := omit
272 }
273 }
274 };
275
Harald Welte7024baa2018-03-02 23:37:51 +0100276 template (value) RLCMAC_ph_data_req ts_PH_DATA_ABS(uint8_t tbf_id, GprsCodingScheme cs,
277 uint8_t ts, uint32_t fn, Arfcn arfcn,
278 RlcmacUlBlock block) := {
279 abs := {
280 tbf_id := tbf_id,
281 cs := CS1, /* FIXME */
282 ts_nr := ts,
283 fn := fn,
284 arfcn := arfcn,
285 block := block
286 }
287 }
288
Harald Welte4b6c7722017-08-01 00:07:12 +0200289 private function f_establish_tbf(uint8_t ra) runs on lapdm_CT {
290 var ImmediateAssignment imm_ass;
291 var GsmFrameNumber rach_fn;
292 var TfiUsfArr tua := f_TfiUsfArrInit();
293
294 /* send RACH request and obtain FN at which it was sent */
295 rach_fn := f_L1CTL_RACH(L1CTL, ra);
296
297 /* wait for receiving matching IMM ASS */
298 imm_ass := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, rach_fn);
299
300 if (match(imm_ass, t_IMM_ASS_TBF_UL_DYN(ra, rach_fn))) {
301 set_ph_state(PH_STATE_TBF);
302
303 /* store/save channel description */
304 //chan_desc := imm_ass.chan_desc;
305
306 /* Important: ARFCN, TN, TSC, USF, USF_GRANULARITY, CH_CODING_CMD */
307 f_TfiUsfArrSet(tua, imm_ass.pkt_chan_desc.tn, imm_ass.rest_octets.hh.ul.dynamic.usf);
308 f_L1CTL_TBF_CFG(L1CTL, true, tua);
309 } else {
310 /* FIXME: single block uplink allocation */
311 log("Failed to match ", t_IMM_ASS_TBF_UL_DYN(ra, rach_fn));
312 log("Non-dynamic UL TBF assignment not supported yet");
313 }
314 }
315
316 private function f_release_tbf() runs on lapdm_CT {
317 var TfiUsfArr tua := f_TfiUsfArrInit();
318 /* send "all timeslots unused" for both UL and DL */
319 f_L1CTL_TBF_CFG(L1CTL, true, tua);
320 f_L1CTL_TBF_CFG(L1CTL, false, tua);
321 /* L1 will then fall back to BCCH/CCCH */
322 set_ph_state(PH_STATE_BCH);
323 }
324
Harald Welteb669ee02018-03-09 12:50:02 +0100325 /* Establish TBF / packet transfer mode */
326 private altstep as_tbf_ul_est() runs on lapdm_CT {
327 var TBF_UL_establish_req tbf_ul_req;
328 [] LAPDM_SP.receive(TBF_UL_establish_req:?) -> value tbf_ul_req {
329 var TbfNr tbf_nr := tbf_ul_req.tbf_nr;
330 var TBF_UL_establish_res res;
331 if (isvalue(g_tbf_ul[tbf_nr].arfcn)) {
332 setverdict(fail, "Cannot establish UL TBF ID ", tbf_nr, ": BUSY");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200333 mtc.stop;
Harald Welteb669ee02018-03-09 12:50:02 +0100334 }
335 f_establish_tbf(tbf_ul_req.ra);
336 if (ph_state == PH_STATE_TBF) {
337 g_tbf_ul[tbf_nr] := valueof(t_TbfParsInit); /* FIXME: Actual TFI[s] */
338 log("Established UL TBF ", tbf_nr);
339 res := { pars := g_tbf_ul[tbf_nr], err := omit };
340 } else {
341 res := { pars := omit, err := "Unable to establish UL TBF" };
342 }
343 LAPDM_SP.send(res);
344 }
345 }
346
347 private altstep as_tbf_dl_est() runs on lapdm_CT {
348 var TBF_DL_establish_req tbf_dl_req;
349 [] LAPDM_SP.receive(TBF_DL_establish_req:?) -> value tbf_dl_req {
350 var TbfNr tbf_nr := tbf_dl_req.tbf_nr;
351 if (isvalue(g_tbf_dl[tbf_nr].arfcn)) {
352 setverdict(fail, "Cannot establish DL TBF ID ", tbf_nr, ": BUSY");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200353 mtc.stop;
Harald Welteb669ee02018-03-09 12:50:02 +0100354 }
355 g_tbf_dl[tbf_nr] := tbf_dl_req.pars;
356 f_L1CTL_TBF_CFG(L1CTL, false, tbf_dl_req.pars.tfi);
357 set_ph_state(PH_STATE_TBF);
358 log("Established DL TBF ", tbf_nr, ": ", tbf_dl_req.pars);
359 }
360 }
361
362 private function f_init_tbf() runs on lapdm_CT {
363 var integer i;
364 for (i := 0; i < 8; i := i+1) {
365 g_tbf_ul[i] := valueof(t_TbfParsInit);
366 g_tbf_dl[i] := valueof(t_TbfParsInit);
367 }
368 }
369
Harald Welted4ba7ff2017-07-17 21:00:48 +0200370 function ScanEvents() runs on lapdm_CT {
371 var L1ctlDlMessage dl;
372 var BCCH_tune_req bt;
373 var LAPDm_ph_data lpd;
Harald Welte4b6c7722017-08-01 00:07:12 +0200374 var RLCMAC_ph_data_ind rpdi;
375 var RLCMAC_ph_data_req rpdr;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200376 var DCCH_establish_req est_req;
377 var DCCH_establish_res est_res;
Harald Welteb669ee02018-03-09 12:50:02 +0100378
379 f_init_tbf();
Harald Welted4ba7ff2017-07-17 21:00:48 +0200380
381 while (true) {
382 if (ph_state == PH_STATE_NULL) {
383 alt {
384 [] LAPDM_SP.receive(BCCH_tune_req:?) -> value bt {
385 f_tune_bcch(bt.arfcn, bt.combined_ccch);
386 }
387
388 [] LAPDM_SP.receive {}
389 [] L1CTL.receive {}
390
391 }
392 } else if (ph_state == PH_STATE_BCH or ph_state == PH_STATE_SEARCHING_BCH) {
393 alt {
394 [] LAPDM_SP.receive(BCCH_tune_req:?) -> value bt {
395 f_tune_bcch(bt.arfcn, bt.combined_ccch);
396 }
397
398 /* forward CCCH SAPI from L1CTL to User */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100399 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0))) -> value dl {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200400 lpd.sacch := false;
401 lpd.sapi := 0;
402 lpd.lapdm.bbis := dec_LapdmFrameBbis(dl.payload.data_ind.payload);
403 LAPDM_SP.send(lpd);
404 }
405
406 /* forward BCCH SAPI from L1CTL to User */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100407 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200408 lpd.sacch := false;
409 lpd.sapi := 0;
410 lpd.lapdm.bbis := dec_LapdmFrameBbis(dl.payload.data_ind.payload);
411 LAPDM_SP.send(lpd);
412 }
413
414 /* Establish dedicated channel */
415 [] LAPDM_SP.receive(DCCH_establish_req:?) -> value est_req {
416 var DCCH_establish_res res;
417 f_establish_dcch(est_req.ra);
418 if (ph_state == PH_STATE_DCH) {
419 res := { chan_desc, omit };
420 } else {
421 res := { omit, "Unable to esetablish DCCH" };
422 }
423 LAPDM_SP.send(res);
424 }
425
Harald Welteb669ee02018-03-09 12:50:02 +0100426 [] as_tbf_ul_est();
427 [] as_tbf_dl_est();
Harald Welte4b6c7722017-08-01 00:07:12 +0200428
Harald Welted4ba7ff2017-07-17 21:00:48 +0200429 [] LAPDM_SP.receive {}
430 [] L1CTL.receive {}
431
432 }
433
434 } else if (ph_state == PH_STATE_TUNING_DCH or ph_state == PH_STATE_DCH) {
435 alt {
436
437 /* decode any received DATA frames for the dedicated channel and pass them up */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100438 [] L1CTL.receive(tr_L1CTL_DATA_IND(chan_desc.chan_nr)) -> value dl {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200439 if (dl.dl_info.link_id.c == SACCH) {
440 lpd.sacch := true;
441 /* FIXME: how to deal with UI frames in B4 format (lo length!) */
442 } else {
443 lpd.sacch := false;
444 }
445 lpd.sapi := dl.dl_info.link_id.sapi;
Harald Welted879bd92018-03-12 15:01:23 +0100446 lpd.lapdm.ab := dec_LapdmFrameAB(dl.payload.data_ind.payload);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200447 LAPDM_SP.send(lpd);
448 }
449
450 /* encode any LAPDm record from user and pass it on to L1CTL */
451 [] LAPDM_SP.receive(LAPDm_ph_data:?) -> value lpd {
452 var octetstring buf;
453 var RslLinkId link_id;
454 if (lpd.sacch) {
455 link_id := valueof(ts_RslLinkID_SACCH(lpd.sapi));
Harald Welte9de7f642019-05-30 15:08:57 +0200456 buf := f_pad_oct(enc_LapdmFrame(lpd.lapdm), 21, '2B'O);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200457 } else {
458 link_id := valueof(ts_RslLinkID_DCCH(lpd.sapi));
Harald Welte9de7f642019-05-30 15:08:57 +0200459 buf := f_pad_oct(enc_LapdmFrame(lpd.lapdm), 23, '2B'O);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200460 }
Harald Weltef8df4cb2018-03-10 15:15:08 +0100461 L1CTL.send(ts_L1CTL_DATA_REQ(chan_desc.chan_nr, link_id, buf));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200462 }
463
464 /* Release dedicated channel */
465 [] LAPDM_SP.receive(DCCH_release_req:?) {
466 /* go back to BCCH */
467 f_release_dcch();
468 }
469
470 [] LAPDM_SP.receive {}
471 [] L1CTL.receive {}
472
473
474 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200475 } else if (ph_state == PH_STATE_TBF) {
476 alt {
477
478 /* decode + forward any blocks from L1 to L23*/
Harald Weltef8df4cb2018-03-10 15:15:08 +0100479 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PDCH(?))) -> value dl {
Harald Welte4b6c7722017-08-01 00:07:12 +0200480 rpdi.block := dec_RlcmacDlBlock(dl.payload.data_ind.payload);
Harald Welteb669ee02018-03-09 12:50:02 +0100481 /* FIXME: Filter based on g_tbf_dl */
Harald Welte7024baa2018-03-02 23:37:51 +0100482 rpdi.fn := dl.dl_info.frame_nr;
483 rpdi.ts_nr := dl.dl_info.chan_nr.tn;
Harald Welte4b6c7722017-08-01 00:07:12 +0200484 rpdi.cs := CS1; /* FIXME */
485 log("RPDI: ", rpdi);
486 LAPDM_SP.send(rpdi);
487 }
488
489 [] L1CTL.receive { }
490
491 /* encode + forward any blocks from L23 to L1 */
492 [] LAPDM_SP.receive(RLCMAC_ph_data_req:?) -> value rpdr {
493 var octetstring buf;
Harald Welte7024baa2018-03-02 23:37:51 +0100494 if (ischosen(rpdr.dyn)) {
495 buf := enc_RlcmacUlBlock(rpdr.dyn.block);
Harald Weltef8df4cb2018-03-10 15:15:08 +0100496 L1CTL.send(ts_L1CTL_DATA_TBF_REQ(buf, L1CTL_CS1, rpdr.dyn.tbf_id));
Harald Welte7024baa2018-03-02 23:37:51 +0100497 } else {
498 buf := enc_RlcmacUlBlock(rpdr.abs.block);
Harald Weltef8df4cb2018-03-10 15:15:08 +0100499 L1CTL.send(ts_L1CTL_DATA_ABS_REQ(buf, rpdr.abs.arfcn,
Harald Welte7024baa2018-03-02 23:37:51 +0100500 rpdr.abs.ts_nr, rpdr.abs.fn,
501 L1CTL_CS1, rpdr.abs.tbf_id));
502 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200503 }
504
Harald Welteb669ee02018-03-09 12:50:02 +0100505 [] as_tbf_ul_est();
506 [] as_tbf_dl_est();
507
Harald Welte4b6c7722017-08-01 00:07:12 +0200508 /* FIXME: release TBF mode */
509 [] LAPDM_SP.receive(DCCH_release_req:?) {
510 /* go back to BCCH */
511 f_release_tbf();
Harald Welteb669ee02018-03-09 12:50:02 +0100512 f_init_tbf();
Harald Welte4b6c7722017-08-01 00:07:12 +0200513 }
514
515 }
Harald Welted4ba7ff2017-07-17 21:00:48 +0200516 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200517
Harald Welted4ba7ff2017-07-17 21:00:48 +0200518 } /* while (1) */
519 }
520}