summaryrefslogtreecommitdiffstats
path: root/library/L1CTL_PortType.ttcn
blob: 2775e1952811e9e9d15c8d0bb85c0211ef296b22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* dual-faced port that wraps an Unixdomain port and encodes/decodes L1CTL */
module L1CTL_PortType {
	import from L1CTL_Types all;
	import from UD_PortType all;
	import from UD_Types all;
	import from Osmocom_Types all;
	import from GSM_Types all;
	import from GSM_RR_Types all;
	import from L1CTL_PortType_CtrlFunct all;

	type record L1CTL_connect {
		charstring	path
	}

	type record L1CTL_connect_result {
		UD_Result_code	result_code optional,
		charstring	err optional
	}

	modulepar {
		charstring	m_l1ctl_sock_path := "/tmp/osmocom_l2";
	}

	function f_L1CTL_getMsgLen(in octetstring stream, inout ro_integer args) return integer {
		var integer stream_len := lengthof(stream);
		var integer len;
		if (stream_len < 2) {
			log("getMsgLen(", stream, ",", args, ")=-1");
			return -1;
		}
		len := 2 + oct2int(substr(stream, 0, 2));
		log("getMsgLen(", stream, ",", args, ")=", len);
		return len;
	}

	function f_L1CTL_FBSB(L1CTL_PT pt, Arfcn arfcn, L1ctlCcchMode ccch_mode := CCCH_MODE_COMBINED) {
		timer T := 5.0;
		for (var integer i := 0; i < 10; i := i+1) {
			pt.send(t_L1CTL_FBSB_REQ(arfcn, t_L1CTL_FBSB_F_ALL, 0, ccch_mode, 63));
			T.start
			alt {
			[] pt.receive(t_L1CTL_FBSB_CONF(0)) { return; };
			[] pt.receive(t_L1CTL_FBSB_CONF(?)) { }
			[i == 9] pt.receive(t_L1CTL_FBSB_CONF(?)) {
				setverdict(fail, "FBSB Failed with non-zero return code");
				};
			[] pt.receive { repeat; };
			[] T.timeout { setverdict(fail, "Timeout in FBSB") };
			}
		}
	}

	function f_L1CTL_RACH(L1CTL_PT pt, uint8_t ra, uint8_t combined := 1, uint16_t offset := 0) return GsmFrameNumber {
		var L1ctlDlMessage rc;
		var GsmFrameNumber fn;
		timer T := 2.0;
		T.start
		pt.send(t_L1CTL_RACH_REQ(ra, combined, offset))
		alt {
			[] pt.receive(t_L1CTL_RACH_CONF) -> value rc { fn := rc.dl_info.frame_nr };
			[] pt.receive { repeat; };
			[] T.timeout { setverdict(fail, "Timeout in RACH") };
		}
		return fn;
	}

	function f_L1CTL_PARAM(L1CTL_PT pt, uint8_t ta, uint8_t tx_power) {
		pt.send(t_L1CTL_PAR_REQ(ta, tx_power));
	}

	function f_L1CTL_WAIT_IMM_ASS(L1CTL_PT pt, uint8_t ra, GsmFrameNumber rach_fn) 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(ra, rach_fn))) {
					log("Received IMM.ASS for our RACH!");
				} 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;
		pt.send(t_L1CTL_TBF_CFG_REQ(is_uplink, tfi_usf));
		alt {
			[] pt.receive(t_L1CTL_TBF_CFG_CONF(is_uplink)) {}
			[] pt.receive { repeat };
			[] T.timeout { setverdict(fail, "Timeout waiting for TBF-CFG.conf") };
		}
		T.stop;
	}

	/* Send DM_EST_REQ from parameters derived from IMM ASS */
	function f_L1CTL_DM_EST_REQ_IA(L1CTL_PT pt, ImmediateAssignment imm_ass) {
		pt.send(t_L1CTL_DM_EST_REQ({ false, imm_ass.chan_desc.arfcn }, imm_ass.chan_desc.chan_nr, imm_ass.chan_desc.tsc));
	}

	function f_connect_reset(L1CTL_PT pt, charstring l1ctl_sock_path := m_l1ctl_sock_path) {
		var f_UD_getMsgLen vl_f := refers(f_L1CTL_getMsgLen);
		f_L1CTL_setGetMsgLen(pt, -1, vl_f, {});
		pt.send(L1CTL_connect:{path:=l1ctl_sock_path});
		pt.receive(L1CTL_connect_result:{result_code := SUCCESS, err:=omit});
		f_L1CTL_setGetMsgLen(pt, 0, vl_f, {});

		pt.send(t_L1ctlResetReq(L1CTL_RES_T_SCHED));
		pt.receive;
	}

	private function L1CTL_to_UD_connect(in L1CTL_connect pin, out UD_connect pout) {
		pout.path := pin.path;
		pout.id := 0;
	} with { extension "prototype(fast)" }

	private function UD_to_L1CTL_connect_result(in UD_connect_result pin, out L1CTL_connect_result pout) {
		pout.result_code := pin.result.result_code;
		pout.err := pin.result.err;
	} with { extension "prototype(fast)" }

	private function L1CTL_to_UD_ul(in L1ctlUlMessage pin, out UD_send_data pout) {
		var L1ctlUlMessageLV msg_lv := { msg := pin };
		pout.data := enc_L1ctlUlMessageLV(msg_lv);
		pout.id := 0;
	} with { extension "prototype(fast)" }

	private function UD_to_L1CTL_dl(in UD_send_data pin, out L1ctlDlMessage pout) {
		var L1ctlDlMessageLV msg_lv := dec_L1ctlDlMessageLV(pin.data);
		pout:= msg_lv.msg;
	} with { extension "prototype(fast)" }

	type port L1CTL_PT message {
		out L1ctlUlMessage
		out L1CTL_connect
		in L1ctlDlMessage
		in L1CTL_connect_result
		in UD_listen_result
		in UD_connected
	} with { extension "user UD_PT
		out(L1ctlUlMessage -> UD_send_data: function(L1CTL_to_UD_ul);
		    L1CTL_connect -> UD_connect: function(L1CTL_to_UD_connect))
		in(UD_send_data -> L1ctlDlMessage: function(UD_to_L1CTL_dl);
		   UD_connect_result -> L1CTL_connect_result: function(UD_to_L1CTL_connect_result);
		   UD_listen_result -> UD_listen_result: simple;
		   UD_connected -> UD_connected: simple
		)" }
}