blob: f7c18b58e6e1915f4c1513baeece34c0dd9bb97c [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;
Vadim Yanitskiy150d6d12022-10-20 19:10:04 +070017 import from GSM_RestOctets all;
Harald Welted4ba7ff2017-07-17 21:00:48 +020018 import from Osmocom_Types all;
19 import from L1CTL_Types all;
20 import from L1CTL_PortType all;
21 import from LAPDm_Types all;
Harald Welte4b6c7722017-08-01 00:07:12 +020022 import from RLCMAC_Types all;
Harald Welted4ba7ff2017-07-17 21:00:48 +020023
Vadim Yanitskiy72a76b52023-03-18 00:12:09 +070024 type record length(8) of uint8_t TfiUsfArr;
25
Harald Welted4ba7ff2017-07-17 21:00:48 +020026 /* request to tune to a given ARFCN and start BCCH decoding */
27 type record BCCH_tune_req {
Vadim Yanitskiy1acc7bb2020-11-14 04:24:57 +070028 GsmBandArfcn arfcn,
Harald Welted4ba7ff2017-07-17 21:00:48 +020029 boolean combined_ccch
30 }
31
32 /* ask for a dedicated channel to be established */
33 type record DCCH_establish_req {
34 uint8_t ra
35 }
36
37 type record DCCH_establish_res {
38 ChannelDescription chan_desc optional,
39 charstring err optional
40 }
41
Harald Welte66f07542019-05-30 17:35:31 +020042 /* directly switch to a dedicated channel (without RACH/IMM.ASS */
43 type record DCCH_switch_req {
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070044 ChannelDescription chan_desc,
Vadim Yanitskiyca813922020-09-12 19:08:31 +070045 L1ctlMA ma optional
Harald Welte66f07542019-05-30 17:35:31 +020046 }
47
48 type record DCCH_switch_res {
49 charstring err optional
50 }
51
Harald Welteb669ee02018-03-09 12:50:02 +010052 type record length(8) of uint8_t TfiList;
53 type record TbfPars {
54 GsmArfcn arfcn optional,
55 /* Temporary Flow Identifier for each TN */
56 TfiList tfi
57 }
58 type record length(8) of TbfPars TbfParsPerTs;
59
60 template TbfPars t_TbfParsInit := {
61 arfcn := omit,
62 tfi := { 255, 255, 255, 255, 255, 255, 255, 255 }
63 }
64
65 type record TBF_UL_establish_res {
66 TbfPars pars optional,
Harald Welte4b6c7722017-08-01 00:07:12 +020067 charstring err optional
68 }
69
Harald Welted4ba7ff2017-07-17 21:00:48 +020070 type record DCCH_release_req {
71 }
72
73 /* PH-DATA.ind / PH-DATA.req */
74 type record LAPDm_ph_data {
75 boolean sacch,
76 GsmSapi sapi,
77 LapdmFrame lapdm
78 }
79
Harald Welteb669ee02018-03-09 12:50:02 +010080 type integer TbfNr (0..7); /* maximum of 8 concurrent TBF per direction */
81 type record TBF_UL_establish_req {
82 TbfNr tbf_nr,
Harald Welte4b6c7722017-08-01 00:07:12 +020083 uint8_t ra
84 }
85
Harald Welteb669ee02018-03-09 12:50:02 +010086 type record TBF_DL_establish_req {
87 TbfNr tbf_nr,
88 TbfPars pars
89 }
90
Harald Welte4b6c7722017-08-01 00:07:12 +020091 /* PH-DATA.ind / PH-DATA.req */
92 type record RLCMAC_ph_data_ind {
93 GprsCodingScheme cs,
Harald Welte7024baa2018-03-02 23:37:51 +010094 uint8_t ts_nr,
95 GsmFrameNumber fn,
Harald Welte4b6c7722017-08-01 00:07:12 +020096 RlcmacDlBlock block
97 }
Harald Welte7024baa2018-03-02 23:37:51 +010098 type record RLCMAC_ph_data_req_dyn {
Harald Welte4b6c7722017-08-01 00:07:12 +020099 uint8_t tbf_id,
100 GprsCodingScheme cs,
101 RlcmacUlBlock block
102 }
Harald Welte7024baa2018-03-02 23:37:51 +0100103 type record RLCMAC_ph_data_req_abs {
104 uint8_t tbf_id,
105 GprsCodingScheme cs,
106 uint8_t ts_nr,
107 GsmFrameNumber fn,
Vadim Yanitskiy1acc7bb2020-11-14 04:24:57 +0700108 GsmBandArfcn arfcn,
Harald Welte7024baa2018-03-02 23:37:51 +0100109 RlcmacUlBlock block
110 }
111 type union RLCMAC_ph_data_req {
112 RLCMAC_ph_data_req_dyn dyn,
113 RLCMAC_ph_data_req_abs abs
114 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200115
Harald Welted4ba7ff2017-07-17 21:00:48 +0200116 /* port from our (internal) point of view */
117 type port LAPDm_SP_PT message {
118 in BCCH_tune_req,
119 DCCH_establish_req,
Harald Welte66f07542019-05-30 17:35:31 +0200120 DCCH_switch_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200121 DCCH_release_req,
Harald Welteb669ee02018-03-09 12:50:02 +0100122 TBF_UL_establish_req,
123 TBF_DL_establish_req,
Harald Welte4b6c7722017-08-01 00:07:12 +0200124 RLCMAC_ph_data_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200125 LAPDm_ph_data;
126 out DCCH_establish_res,
Harald Welte66f07542019-05-30 17:35:31 +0200127 DCCH_switch_res,
Harald Welteb669ee02018-03-09 12:50:02 +0100128 TBF_UL_establish_res,
Harald Welte4b6c7722017-08-01 00:07:12 +0200129 RLCMAC_ph_data_ind,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200130 LAPDm_ph_data;
131 } with {extension "internal"};
132
133 /* port from user (external) point of view */
134 type port LAPDm_PT message {
135 in DCCH_establish_res,
Harald Welte66f07542019-05-30 17:35:31 +0200136 DCCH_switch_res,
Harald Welteb669ee02018-03-09 12:50:02 +0100137 TBF_UL_establish_res,
Harald Welte4b6c7722017-08-01 00:07:12 +0200138 RLCMAC_ph_data_ind,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200139 LAPDm_ph_data;
140 out BCCH_tune_req,
141 DCCH_establish_req,
Harald Welte66f07542019-05-30 17:35:31 +0200142 DCCH_switch_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200143 DCCH_release_req,
Harald Welteb669ee02018-03-09 12:50:02 +0100144 TBF_UL_establish_req,
145 TBF_DL_establish_req,
Harald Welte4b6c7722017-08-01 00:07:12 +0200146 RLCMAC_ph_data_req,
Harald Welted4ba7ff2017-07-17 21:00:48 +0200147 LAPDm_ph_data;
148 } with {extension "internal"};
149
150 function LAPDmStart() runs on lapdm_CT {
151 f_init();
152 ScanEvents();
153 }
154
155 /* TS 44.004 Figure 5.1 */
156 type enumerated ph_state_enum {
157 PH_STATE_NULL,
158 PH_STATE_BCH,
159 PH_STATE_SEARCHING_BCH,
160 PH_STATE_TUNING_DCH,
Harald Welte4b6c7722017-08-01 00:07:12 +0200161 PH_STATE_DCH,
162 PH_STATE_TBF
Harald Welted4ba7ff2017-07-17 21:00:48 +0200163 }
164
165 type component lapdm_CT {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200166
167 /* L1CTL port towards the bottom */
168 port L1CTL_PT L1CTL;
169 /* Port towards L2 */
170 port LAPDm_SP_PT LAPDM_SP;
171
172 /* physical layer state */
173 var ph_state_enum ph_state := PH_STATE_NULL;
174
175 /* channel description of the currently active DCH */
176 var ChannelDescription chan_desc;
Harald Welteb669ee02018-03-09 12:50:02 +0100177
Harald Welte1365a4e2019-06-01 23:04:43 +0200178 /* last SACCH downlink L1 header we received */
179 var uint5_t ms_power_lvl := 0;
180 var uint8_t timing_adv := 0;
181
Harald Welteb669ee02018-03-09 12:50:02 +0100182 var TbfParsPerTs g_tbf_ul;
183 var TbfParsPerTs g_tbf_dl;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200184 };
185
186 /* wrapper function to log state transitions */
187 private function set_ph_state(ph_state_enum new_state) runs on lapdm_CT {
188 log("PH-STATE ", ph_state, " -> ", new_state);
189 ph_state := new_state;
190 }
191
192 private function f_init() runs on lapdm_CT {
Harald Welteb26cfff2017-08-25 09:56:47 +0200193 f_connect_reset(L1CTL);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200194 set_ph_state(PH_STATE_NULL);
195 }
196
197 /* release the dedicated radio channel */
198 private function f_release_dcch() runs on lapdm_CT {
Harald Weltef8df4cb2018-03-10 15:15:08 +0100199 L1CTL.send(ts_L1CTL_DM_REL_REQ(chan_desc.chan_nr));
Harald Welte4b6c7722017-08-01 00:07:12 +0200200 set_ph_state(PH_STATE_BCH);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200201 }
202
203 /* tune to given ARFCN and start BCCH/CCCH decoding */
Vadim Yanitskiy1acc7bb2020-11-14 04:24:57 +0700204 private function f_tune_bcch(GsmBandArfcn arfcn, boolean combined)
205 runs on lapdm_CT {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200206 var L1ctlCcchMode mode := CCCH_MODE_NON_COMBINED;
207 if (combined) {
208 mode := CCCH_MODE_COMBINED;
209 }
210
211 if (ph_state == PH_STATE_DCH) {
212 /* release any previous DCH */
213 f_release_dcch();
Harald Welte4b6c7722017-08-01 00:07:12 +0200214 } else if (ph_state == PH_STATE_TBF) {
215 f_release_tbf();
Harald Welted4ba7ff2017-07-17 21:00:48 +0200216 }
217
218 set_ph_state(PH_STATE_SEARCHING_BCH);
219
220 /* send FB/SB req to sync to cell */
221 f_L1CTL_FBSB(L1CTL, arfcn, mode);
222 set_ph_state(PH_STATE_BCH);
223 }
224
225 /* master function establishing a dedicated radio channel */
226 private function f_establish_dcch(uint8_t ra) runs on lapdm_CT {
227 var ImmediateAssignment imm_ass;
228 var GsmFrameNumber rach_fn;
229
230 /* send RACH request and obtain FN at which it was sent */
231 rach_fn := f_L1CTL_RACH(L1CTL, ra);
232 //if (not rach_fn) { return; }
233
234 /* wait for receiving matching IMM ASS */
235 imm_ass := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, rach_fn)
236 //if (not imm_ass) { return; }
237 set_ph_state(PH_STATE_TUNING_DCH);
238
239 /* store/save channel description */
240 chan_desc := imm_ass.chan_desc;
241
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +0700242 /* send DM_EST_REQ, TODO: Mobile Allocation */
Harald Welted4ba7ff2017-07-17 21:00:48 +0200243 f_L1CTL_DM_EST_REQ_IA(L1CTL, imm_ass);
244 set_ph_state(PH_STATE_DCH);
245 }
246
Harald Welte66f07542019-05-30 17:35:31 +0200247 /* switching directly to a dedicated channel *without RACH/IMM-ASS */
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +0700248 private function f_switch_dcch(in DCCH_switch_req sw_req) runs on lapdm_CT {
Harald Welte66f07542019-05-30 17:35:31 +0200249 set_ph_state(PH_STATE_TUNING_DCH);
250 /* store/save channel description */
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +0700251 chan_desc := sw_req.chan_desc;
252
253 /* tune the L1 to the indicated channel */
254 if (chan_desc.h) {
255 L1CTL.send(ts_L1CTL_DM_EST_REQ_H1(chan_desc.chan_nr,
256 chan_desc.tsc,
257 chan_desc.maio_hsn.hsn,
258 chan_desc.maio_hsn.maio,
259 sw_req.ma));
260 } else {
261 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(chan_desc.chan_nr,
262 chan_desc.tsc,
263 chan_desc.arfcn));
264 }
265
Harald Welte66f07542019-05-30 17:35:31 +0200266 set_ph_state(PH_STATE_DCH);
267 }
268
Harald Welte4b6c7722017-08-01 00:07:12 +0200269 /* initialize a tfi_usf array with "not used" value 255 for all TN */
270 function f_TfiUsfArrInit() return TfiUsfArr {
271 var TfiUsfArr tua := { 255, 255, 255, 255, 255, 255, 255, 255 };
272 return tua;
273 }
274
275 /* set TFI/USF value for one given timeslot number (index) */
276 function f_TfiUsfArrSet(inout TfiUsfArr a, in uint8_t idx, in uint8_t tfi_usf) {
277 a[idx] := tfi_usf;
278 }
279
Harald Welte7024baa2018-03-02 23:37:51 +0100280 template (value) RLCMAC_ph_data_req ts_PH_DATA_ABS(uint8_t tbf_id, GprsCodingScheme cs,
Vadim Yanitskiy1acc7bb2020-11-14 04:24:57 +0700281 uint8_t ts, uint32_t fn,
282 GsmBandArfcn arfcn,
Harald Welte7024baa2018-03-02 23:37:51 +0100283 RlcmacUlBlock block) := {
284 abs := {
285 tbf_id := tbf_id,
286 cs := CS1, /* FIXME */
287 ts_nr := ts,
288 fn := fn,
289 arfcn := arfcn,
290 block := block
291 }
292 }
293
Vadim Yanitskiyc9b2ba22019-09-09 16:02:10 +0200294 private function f_establish_tbf(uint8_t ra) runs on lapdm_CT return boolean {
295 var template GsmRrMessage imm_ass_rr;
Harald Welte4b6c7722017-08-01 00:07:12 +0200296 var ImmediateAssignment imm_ass;
Vadim Yanitskiyc9b2ba22019-09-09 16:02:10 +0200297 var PacketUlAssign pkt_ul_ass;
Harald Welte4b6c7722017-08-01 00:07:12 +0200298 var GsmFrameNumber rach_fn;
299 var TfiUsfArr tua := f_TfiUsfArrInit();
300
301 /* send RACH request and obtain FN at which it was sent */
302 rach_fn := f_L1CTL_RACH(L1CTL, ra);
303
304 /* wait for receiving matching IMM ASS */
305 imm_ass := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, rach_fn);
306
Vadim Yanitskiyc9b2ba22019-09-09 16:02:10 +0200307 /* make sure we got *Packet* (Uplink) Immediate Assignment */
308 imm_ass_rr := tr_IMM_TBF_ASS(dl := false, ra := ra, fn := rach_fn,
309 rest := tr_IaRestOctets_ULAss(?));
310 if (not match(imm_ass, imm_ass_rr.payload.imm_ass)) {
311 log("Failed to match Packet Immediate Assignment");
312 return false;
313 }
314
315 /* decapsulate PacketUlAssign for further matching */
316 pkt_ul_ass := imm_ass.rest_octets.hh.pa.uldl.ass.ul;
317
318 /* Dynamic Block Allocation */
319 if (match(pkt_ul_ass, tr_PacketUlDynAssign)) {
Harald Welte4b6c7722017-08-01 00:07:12 +0200320 set_ph_state(PH_STATE_TBF);
321
322 /* store/save channel description */
323 //chan_desc := imm_ass.chan_desc;
324
325 /* Important: ARFCN, TN, TSC, USF, USF_GRANULARITY, CH_CODING_CMD */
Vadim Yanitskiyc9b2ba22019-09-09 16:02:10 +0200326 f_TfiUsfArrSet(tua, imm_ass.pkt_chan_desc.tn, pkt_ul_ass.dynamic.usf);
Vadim Yanitskiy72a76b52023-03-18 00:12:09 +0700327 // FIXME: f_L1CTL_TBF_CFG(L1CTL, true, tua);
Vadim Yanitskiyc9b2ba22019-09-09 16:02:10 +0200328 return true;
329 /* FIXME: Single Block Allocation */
330 } else if (match(pkt_ul_ass, tr_PacketUlSglAssign)) {
Harald Welte4b6c7722017-08-01 00:07:12 +0200331 log("Non-dynamic UL TBF assignment not supported yet");
Vadim Yanitskiyc9b2ba22019-09-09 16:02:10 +0200332 return false;
333 } else {
334 log("Failed to match Uplink Block Allocation: ", pkt_ul_ass);
335 return false;
Harald Welte4b6c7722017-08-01 00:07:12 +0200336 }
337 }
338
339 private function f_release_tbf() runs on lapdm_CT {
340 var TfiUsfArr tua := f_TfiUsfArrInit();
341 /* send "all timeslots unused" for both UL and DL */
Vadim Yanitskiy72a76b52023-03-18 00:12:09 +0700342 // FIXME: f_L1CTL_TBF_CFG(L1CTL, true, tua);
343 // FIXME: f_L1CTL_TBF_CFG(L1CTL, false, tua);
Harald Welte4b6c7722017-08-01 00:07:12 +0200344 /* L1 will then fall back to BCCH/CCCH */
345 set_ph_state(PH_STATE_BCH);
346 }
347
Harald Welteb669ee02018-03-09 12:50:02 +0100348 /* Establish TBF / packet transfer mode */
349 private altstep as_tbf_ul_est() runs on lapdm_CT {
350 var TBF_UL_establish_req tbf_ul_req;
351 [] LAPDM_SP.receive(TBF_UL_establish_req:?) -> value tbf_ul_req {
352 var TbfNr tbf_nr := tbf_ul_req.tbf_nr;
353 var TBF_UL_establish_res res;
354 if (isvalue(g_tbf_ul[tbf_nr].arfcn)) {
355 setverdict(fail, "Cannot establish UL TBF ID ", tbf_nr, ": BUSY");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200356 mtc.stop;
Harald Welteb669ee02018-03-09 12:50:02 +0100357 }
358 f_establish_tbf(tbf_ul_req.ra);
359 if (ph_state == PH_STATE_TBF) {
360 g_tbf_ul[tbf_nr] := valueof(t_TbfParsInit); /* FIXME: Actual TFI[s] */
361 log("Established UL TBF ", tbf_nr);
362 res := { pars := g_tbf_ul[tbf_nr], err := omit };
363 } else {
364 res := { pars := omit, err := "Unable to establish UL TBF" };
365 }
366 LAPDM_SP.send(res);
367 }
368 }
369
370 private altstep as_tbf_dl_est() runs on lapdm_CT {
371 var TBF_DL_establish_req tbf_dl_req;
372 [] LAPDM_SP.receive(TBF_DL_establish_req:?) -> value tbf_dl_req {
373 var TbfNr tbf_nr := tbf_dl_req.tbf_nr;
374 if (isvalue(g_tbf_dl[tbf_nr].arfcn)) {
375 setverdict(fail, "Cannot establish DL TBF ID ", tbf_nr, ": BUSY");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200376 mtc.stop;
Harald Welteb669ee02018-03-09 12:50:02 +0100377 }
378 g_tbf_dl[tbf_nr] := tbf_dl_req.pars;
Vadim Yanitskiy72a76b52023-03-18 00:12:09 +0700379 // FIXME: f_L1CTL_TBF_CFG(L1CTL, false, tbf_dl_req.pars.tfi);
Harald Welteb669ee02018-03-09 12:50:02 +0100380 set_ph_state(PH_STATE_TBF);
381 log("Established DL TBF ", tbf_nr, ": ", tbf_dl_req.pars);
382 }
383 }
384
385 private function f_init_tbf() runs on lapdm_CT {
386 var integer i;
387 for (i := 0; i < 8; i := i+1) {
388 g_tbf_ul[i] := valueof(t_TbfParsInit);
389 g_tbf_dl[i] := valueof(t_TbfParsInit);
390 }
391 }
392
Harald Welted4ba7ff2017-07-17 21:00:48 +0200393 function ScanEvents() runs on lapdm_CT {
Vadim Yanitskiyaf0aae62023-03-18 06:49:18 +0700394 var L1ctlMessage dl;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200395 var BCCH_tune_req bt;
396 var LAPDm_ph_data lpd;
Harald Welte4b6c7722017-08-01 00:07:12 +0200397 var RLCMAC_ph_data_ind rpdi;
398 var RLCMAC_ph_data_req rpdr;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200399 var DCCH_establish_req est_req;
Harald Welte66f07542019-05-30 17:35:31 +0200400 var DCCH_switch_req sw_req;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200401 var DCCH_establish_res est_res;
Harald Welteb669ee02018-03-09 12:50:02 +0100402
403 f_init_tbf();
Harald Welted4ba7ff2017-07-17 21:00:48 +0200404
405 while (true) {
406 if (ph_state == PH_STATE_NULL) {
407 alt {
408 [] LAPDM_SP.receive(BCCH_tune_req:?) -> value bt {
409 f_tune_bcch(bt.arfcn, bt.combined_ccch);
410 }
411
412 [] LAPDM_SP.receive {}
413 [] L1CTL.receive {}
414
415 }
416 } else if (ph_state == PH_STATE_BCH or ph_state == PH_STATE_SEARCHING_BCH) {
417 alt {
418 [] LAPDM_SP.receive(BCCH_tune_req:?) -> value bt {
419 f_tune_bcch(bt.arfcn, bt.combined_ccch);
420 }
421
422 /* forward CCCH SAPI from L1CTL to User */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100423 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0))) -> value dl {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200424 lpd.sacch := false;
425 lpd.sapi := 0;
426 lpd.lapdm.bbis := dec_LapdmFrameBbis(dl.payload.data_ind.payload);
427 LAPDM_SP.send(lpd);
428 }
429
430 /* forward BCCH SAPI from L1CTL to User */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100431 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
Harald Welted4ba7ff2017-07-17 21:00:48 +0200432 lpd.sacch := false;
433 lpd.sapi := 0;
434 lpd.lapdm.bbis := dec_LapdmFrameBbis(dl.payload.data_ind.payload);
435 LAPDM_SP.send(lpd);
436 }
437
438 /* Establish dedicated channel */
439 [] LAPDM_SP.receive(DCCH_establish_req:?) -> value est_req {
440 var DCCH_establish_res res;
441 f_establish_dcch(est_req.ra);
442 if (ph_state == PH_STATE_DCH) {
443 res := { chan_desc, omit };
444 } else {
445 res := { omit, "Unable to esetablish DCCH" };
446 }
447 LAPDM_SP.send(res);
448 }
Harald Welte66f07542019-05-30 17:35:31 +0200449 [] LAPDM_SP.receive(DCCH_switch_req:?) -> value sw_req {
450 var DCCH_switch_res res;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +0700451 f_switch_dcch(sw_req);
Harald Welte66f07542019-05-30 17:35:31 +0200452 if (ph_state == PH_STATE_DCH) {
453 res := { omit };
454 } else {
455 res := { "Unable to switch to DCCH" };
456 }
457 LAPDM_SP.send(res);
458 }
459
Harald Welted4ba7ff2017-07-17 21:00:48 +0200460
Harald Welteb669ee02018-03-09 12:50:02 +0100461 [] as_tbf_ul_est();
462 [] as_tbf_dl_est();
Harald Welte4b6c7722017-08-01 00:07:12 +0200463
Harald Welted4ba7ff2017-07-17 21:00:48 +0200464 [] LAPDM_SP.receive {}
465 [] L1CTL.receive {}
466
467 }
468
469 } else if (ph_state == PH_STATE_TUNING_DCH or ph_state == PH_STATE_DCH) {
470 alt {
471
472 /* decode any received DATA frames for the dedicated channel and pass them up */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100473 [] L1CTL.receive(tr_L1CTL_DATA_IND(chan_desc.chan_nr)) -> value dl {
Harald Welte1365a4e2019-06-01 23:04:43 +0200474 var octetstring l2;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200475 if (dl.dl_info.link_id.c == SACCH) {
476 lpd.sacch := true;
Harald Welte1365a4e2019-06-01 23:04:43 +0200477 var octetstring l1 := substr(dl.payload.data_ind.payload, 0, 2);
478 l2 := substr(dl.payload.data_ind.payload, 2,
479 lengthof(dl.payload.data_ind.payload)-2);
480 ms_power_lvl := oct2int(l1[0] and4b '1F'O);
481 timing_adv := oct2int(l1[1]);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200482 /* FIXME: how to deal with UI frames in B4 format (lo length!) */
483 } else {
484 lpd.sacch := false;
Harald Welte1365a4e2019-06-01 23:04:43 +0200485 l2 := dl.payload.data_ind.payload;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200486 }
487 lpd.sapi := dl.dl_info.link_id.sapi;
Harald Welte1365a4e2019-06-01 23:04:43 +0200488 lpd.lapdm.ab := dec_LapdmFrameAB(l2);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200489 LAPDM_SP.send(lpd);
490 }
491
492 /* encode any LAPDm record from user and pass it on to L1CTL */
493 [] LAPDM_SP.receive(LAPDm_ph_data:?) -> value lpd {
494 var octetstring buf;
495 var RslLinkId link_id;
496 if (lpd.sacch) {
497 link_id := valueof(ts_RslLinkID_SACCH(lpd.sapi));
Harald Welte9de7f642019-05-30 15:08:57 +0200498 buf := f_pad_oct(enc_LapdmFrame(lpd.lapdm), 21, '2B'O);
Harald Welte1365a4e2019-06-01 23:04:43 +0200499 var SacchL1Header l1h := valueof(ts_SacchL1Header(ms_power_lvl,
Vadim Yanitskiy68c4cff2022-07-30 23:45:02 +0700500 timing_adv));
Harald Welte1365a4e2019-06-01 23:04:43 +0200501 L1CTL.send(ts_L1CTL_DATA_REQ_SACCH(chan_desc.chan_nr, link_id,
502 l1h, buf));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200503 } else {
504 link_id := valueof(ts_RslLinkID_DCCH(lpd.sapi));
Harald Welte9de7f642019-05-30 15:08:57 +0200505 buf := f_pad_oct(enc_LapdmFrame(lpd.lapdm), 23, '2B'O);
Harald Welte1365a4e2019-06-01 23:04:43 +0200506 L1CTL.send(ts_L1CTL_DATA_REQ(chan_desc.chan_nr, link_id, buf));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200507 }
Harald Welted4ba7ff2017-07-17 21:00:48 +0200508 }
509
510 /* Release dedicated channel */
511 [] LAPDM_SP.receive(DCCH_release_req:?) {
512 /* go back to BCCH */
513 f_release_dcch();
514 }
515
516 [] LAPDM_SP.receive {}
517 [] L1CTL.receive {}
518
519
520 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200521 } else if (ph_state == PH_STATE_TBF) {
522 alt {
523
524 /* decode + forward any blocks from L1 to L23*/
Harald Weltef8df4cb2018-03-10 15:15:08 +0100525 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PDCH(?))) -> value dl {
Harald Welte4b6c7722017-08-01 00:07:12 +0200526 rpdi.block := dec_RlcmacDlBlock(dl.payload.data_ind.payload);
Harald Welteb669ee02018-03-09 12:50:02 +0100527 /* FIXME: Filter based on g_tbf_dl */
Harald Welte7024baa2018-03-02 23:37:51 +0100528 rpdi.fn := dl.dl_info.frame_nr;
529 rpdi.ts_nr := dl.dl_info.chan_nr.tn;
Harald Welte4b6c7722017-08-01 00:07:12 +0200530 rpdi.cs := CS1; /* FIXME */
531 log("RPDI: ", rpdi);
532 LAPDM_SP.send(rpdi);
533 }
534
535 [] L1CTL.receive { }
536
537 /* encode + forward any blocks from L23 to L1 */
538 [] LAPDM_SP.receive(RLCMAC_ph_data_req:?) -> value rpdr {
539 var octetstring buf;
Harald Welte7024baa2018-03-02 23:37:51 +0100540 if (ischosen(rpdr.dyn)) {
541 buf := enc_RlcmacUlBlock(rpdr.dyn.block);
Vadim Yanitskiy72a76b52023-03-18 00:12:09 +0700542 // FIXME: L1CTL.send(ts_L1CTL_DATA_TBF_REQ(buf, L1CTL_CS1, rpdr.dyn.tbf_id));
Harald Welte7024baa2018-03-02 23:37:51 +0100543 } else {
544 buf := enc_RlcmacUlBlock(rpdr.abs.block);
Vadim Yanitskiy72a76b52023-03-18 00:12:09 +0700545 // FIXME: L1CTL.send(ts_L1CTL_DATA_ABS_REQ(buf, rpdr.abs.arfcn,
546 // rpdr.abs.ts_nr, rpdr.abs.fn,
547 // L1CTL_CS1, rpdr.abs.tbf_id));
Harald Welte7024baa2018-03-02 23:37:51 +0100548 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200549 }
550
Harald Welteb669ee02018-03-09 12:50:02 +0100551 [] as_tbf_ul_est();
552 [] as_tbf_dl_est();
553
Harald Welte4b6c7722017-08-01 00:07:12 +0200554 /* FIXME: release TBF mode */
555 [] LAPDM_SP.receive(DCCH_release_req:?) {
556 /* go back to BCCH */
557 f_release_tbf();
Harald Welteb669ee02018-03-09 12:50:02 +0100558 f_init_tbf();
Harald Welte4b6c7722017-08-01 00:07:12 +0200559 }
560
561 }
Harald Welted4ba7ff2017-07-17 21:00:48 +0200562 }
Harald Welte4b6c7722017-08-01 00:07:12 +0200563
Harald Welted4ba7ff2017-07-17 21:00:48 +0200564 } /* while (1) */
565 }
566}