1 /* GSM Multiframe Scheduler Implementation (on top of TDMA sched) */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <osmocom/gsm/gsm_utils.h>
31 #include <layer1/prim.h>
32 #include <layer1/sync.h>
33 #include <layer1/tdma_sched.h>
34 #include <layer1/mframe_sched.h>
36 /* A multiframe operation which can be scheduled for a multiframe */
37 struct mframe_sched_item
{
38 /* The TDMA scheduler item that shall be scheduled */
39 const struct tdma_sched_item
*sched_set
;
40 /* Which modulo shall be used on the frame number */
42 /* At which number inside the modulo shall we be scheduled */
44 /* bit-mask of flags */
48 /* FIXME: properly clean this up */
49 #define NB_QUAD_DL nb_sched_set
50 #define NB_QUAD_FH_DL NB_QUAD_DL
51 #define NB_QUAD_UL nb_sched_set_ul
52 #define NB_QUAD_FH_UL NB_QUAD_UL
53 #define NEIGH_PM neigh_pm_sched_set
56 static const struct mframe_sched_item mf_bcch_norm
[] = {
57 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 2 },
62 static const struct mframe_sched_item mf_bcch_ext
[] = {
63 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 6 },
67 /* Full CCCH in a pure BCCH + CCCH C0T0 */
68 static const struct mframe_sched_item mf_ccch
[] = {
69 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 6 },
70 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 12 },
71 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 16 },
72 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 22 },
73 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 26 },
74 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 32 },
75 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 36 },
76 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 42 },
77 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 46 },
81 /* Full CCCH in a combined CCCH on C0T0 */
82 static const struct mframe_sched_item mf_ccch_comb
[] = {
83 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 6 },
84 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 12 },
85 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 16 },
89 /* SDCCH/4 in a combined CCCH on C0T0, cannot be FH */
90 static const struct mframe_sched_item mf_sdcch4_0
[] = {
91 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 22 },
92 { .sched_set
= NB_QUAD_UL
, .modulo
= 51, .frame_nr
= 22+15 },
93 { .sched_set
= NB_QUAD_DL
, .modulo
= 2*51, .frame_nr
= 42,
94 .flags
= MF_F_SACCH
},
95 { .sched_set
= NB_QUAD_UL
, .modulo
= 2*51, .frame_nr
= 42+15,
96 .flags
= MF_F_SACCH
},
99 static const struct mframe_sched_item mf_sdcch4_1
[] = {
100 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 26 },
101 { .sched_set
= NB_QUAD_UL
, .modulo
= 51, .frame_nr
= 26+15 },
102 { .sched_set
= NB_QUAD_DL
, .modulo
= 2*51, .frame_nr
= 46,
103 .flags
= MF_F_SACCH
},
104 { .sched_set
= NB_QUAD_UL
, .modulo
= 2*51, .frame_nr
= 46+15,
105 .flags
= MF_F_SACCH
},
106 { .sched_set
= NULL
}
108 static const struct mframe_sched_item mf_sdcch4_2
[] = {
109 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 32 },
110 { .sched_set
= NB_QUAD_UL
, .modulo
= 51, .frame_nr
= 32+15 },
111 { .sched_set
= NB_QUAD_DL
, .modulo
= 2*51, .frame_nr
= 51+42,
112 .flags
= MF_F_SACCH
},
113 { .sched_set
= NB_QUAD_UL
, .modulo
= 2*51, .frame_nr
= 51+42+15,
114 .flags
= MF_F_SACCH
},
115 { .sched_set
= NULL
}
117 static const struct mframe_sched_item mf_sdcch4_3
[] = {
118 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 36 },
119 { .sched_set
= NB_QUAD_UL
, .modulo
= 51, .frame_nr
= 36+15 },
120 { .sched_set
= NB_QUAD_DL
, .modulo
= 2*51, .frame_nr
= 51+46,
121 .flags
= MF_F_SACCH
},
122 { .sched_set
= NB_QUAD_UL
, .modulo
= 2*51, .frame_nr
= 51+46+15,
123 .flags
= MF_F_SACCH
},
124 { .sched_set
= NULL
}
127 /* SDCCH/8, can be frequency hopping (FH) */
128 static const struct mframe_sched_item mf_sdcch8_0
[] = {
129 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 51, .frame_nr
= 0 },
130 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 51, .frame_nr
= 0+15 },
131 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 2*51, .frame_nr
= 32,
132 .flags
= MF_F_SACCH
},
133 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 2*51, .frame_nr
= 32+15,
134 .flags
= MF_F_SACCH
},
135 { .sched_set
= NULL
}
137 static const struct mframe_sched_item mf_sdcch8_1
[] = {
138 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 51, .frame_nr
= 4 },
139 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 51, .frame_nr
= 4+15 },
140 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 2*51, .frame_nr
= 36,
141 .flags
= MF_F_SACCH
},
142 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 2*51, .frame_nr
= 36+15,
143 .flags
= MF_F_SACCH
},
144 { .sched_set
= NULL
}
146 static const struct mframe_sched_item mf_sdcch8_2
[] = {
147 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 51, .frame_nr
= 8 },
148 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 51, .frame_nr
= 8+15 },
149 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 2*51, .frame_nr
= 40,
150 .flags
= MF_F_SACCH
},
151 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 2*51, .frame_nr
= 40+15,
152 .flags
= MF_F_SACCH
},
153 { .sched_set
= NULL
}
155 static const struct mframe_sched_item mf_sdcch8_3
[] = {
156 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 51, .frame_nr
= 12 },
157 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 51, .frame_nr
= 12+15 },
158 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 2*51, .frame_nr
= 44,
159 .flags
= MF_F_SACCH
},
160 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 2*51, .frame_nr
= 44+15,
161 .flags
= MF_F_SACCH
},
162 { .sched_set
= NULL
}
164 static const struct mframe_sched_item mf_sdcch8_4
[] = {
165 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 51, .frame_nr
= 16 },
166 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 51, .frame_nr
= 16+15 },
167 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 2*51, .frame_nr
= 51+32,
168 .flags
= MF_F_SACCH
},
169 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 2*51, .frame_nr
= 51+32+15,
170 .flags
= MF_F_SACCH
},
171 { .sched_set
= NULL
}
173 static const struct mframe_sched_item mf_sdcch8_5
[] = {
174 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 51, .frame_nr
= 20 },
175 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 51, .frame_nr
= 20+15 },
176 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 2*51, .frame_nr
= 51+36,
177 .flags
= MF_F_SACCH
},
178 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 2*51, .frame_nr
= 51+36+15,
179 .flags
= MF_F_SACCH
},
180 { .sched_set
= NULL
}
182 static const struct mframe_sched_item mf_sdcch8_6
[] = {
183 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 51, .frame_nr
= 24 },
184 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 51, .frame_nr
= 24+15 },
185 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 2*51, .frame_nr
= 51+40,
186 .flags
= MF_F_SACCH
},
187 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 2*51, .frame_nr
= 51+40+15,
188 .flags
= MF_F_SACCH
},
189 { .sched_set
= NULL
}
191 static const struct mframe_sched_item mf_sdcch8_7
[] = {
192 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 51, .frame_nr
= 28 },
193 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 51, .frame_nr
= 28+15 },
194 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 2*51, .frame_nr
= 51+44,
195 .flags
= MF_F_SACCH
},
196 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 2*51, .frame_nr
= 51+44+15,
197 .flags
= MF_F_SACCH
},
198 { .sched_set
= NULL
}
201 /* CBCH replaces sub-slot 2 of SDCCH, see GSM 05.02, section 6.4 */
202 static const struct mframe_sched_item mf_sdcch8_cbch
[] = {
203 { .sched_set
= NB_QUAD_FH_DL
, .modulo
= 51, .frame_nr
= 8 },
204 { .sched_set
= NULL
}
206 static const struct mframe_sched_item mf_sdcch4_cbch
[] = {
207 { .sched_set
= NB_QUAD_DL
, .modulo
= 51, .frame_nr
= 32 },
208 { .sched_set
= NULL
}
211 /* Measurement for MF 51 C0 */
212 static const struct mframe_sched_item mf_neigh_pm51_c0t0
[] = {
213 { .sched_set
= NEIGH_PM
, .modulo
= 51, .frame_nr
= 0 },
214 { .sched_set
= NEIGH_PM
, .modulo
= 51, .frame_nr
= 10 },
215 { .sched_set
= NEIGH_PM
, .modulo
= 51, .frame_nr
= 20 },
216 { .sched_set
= NEIGH_PM
, .modulo
= 51, .frame_nr
= 30 },
217 { .sched_set
= NEIGH_PM
, .modulo
= 51, .frame_nr
= 40 },
218 { .sched_set
= NULL
}
221 /* Measurement for MF 51 */
222 static const struct mframe_sched_item mf_neigh_pm51
[] = {
223 { .sched_set
= NEIGH_PM
, .modulo
= 51, .frame_nr
= 50 },
224 { .sched_set
= NULL
}
228 #define TCH tch_sched_set
229 #define TCH_A tch_a_sched_set
230 #define TCH_D tch_d_sched_set
232 static const struct mframe_sched_item mf_tch_f_even
[] = {
233 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 0 },
234 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 1 },
235 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 2 },
236 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 3 },
237 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 4 },
238 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 5 },
239 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 6 },
240 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 7 },
241 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 8 },
242 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 9 },
243 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 10 },
244 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 11 },
245 { .sched_set
= TCH_A
, .modulo
= 26, .frame_nr
= 12,
246 .flags
= MF_F_SACCH
},
247 { .sched_set
= NULL
}
250 static const struct mframe_sched_item mf_tch_f_odd
[] = {
251 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 0 },
252 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 1 },
253 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 2 },
254 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 3 },
255 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 4 },
256 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 5 },
257 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 6 },
258 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 7 },
259 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 8 },
260 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 9 },
261 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 10 },
262 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 11 },
263 { .sched_set
= TCH_A
, .modulo
= 26, .frame_nr
= 25,
264 .flags
= MF_F_SACCH
},
265 { .sched_set
= NULL
}
268 static const struct mframe_sched_item mf_tch_h_0
[] = {
269 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 0 },
270 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 1 },
271 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 2 },
272 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 3 },
273 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 4 },
274 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 5 },
275 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 6 },
276 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 7 },
277 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 8 },
278 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 9 },
279 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 10 },
280 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 11 },
281 { .sched_set
= TCH_A
, .modulo
= 26, .frame_nr
= 12,
282 .flags
= MF_F_SACCH
},
283 { .sched_set
= NULL
}
286 static const struct mframe_sched_item mf_tch_h_1
[] = {
287 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 0 },
288 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 1 },
289 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 2 },
290 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 3 },
291 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 4 },
292 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 5 },
293 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 6 },
294 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 7 },
295 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 8 },
296 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 9 },
297 { .sched_set
= TCH_D
, .modulo
= 13, .frame_nr
= 10 },
298 { .sched_set
= TCH
, .modulo
= 13, .frame_nr
= 11 },
299 { .sched_set
= TCH_A
, .modulo
= 26, .frame_nr
= 25,
300 .flags
= MF_F_SACCH
},
301 { .sched_set
= NULL
}
304 /* Measurement for MF 26 */
305 static const struct mframe_sched_item mf_neigh_pm26_even
[] = {
306 { .sched_set
= NEIGH_PM
, .modulo
= 26, .frame_nr
= 25 },
307 { .sched_set
= NULL
}
309 static const struct mframe_sched_item mf_neigh_pm26_odd
[] = {
310 { .sched_set
= NEIGH_PM
, .modulo
= 26, .frame_nr
= 12 },
311 { .sched_set
= NULL
}
314 /* See 3GPP TS 45.002, table 6 */
315 static const struct mframe_sched_item mf_gprs_pdtch
[] = {
316 { .sched_set
= NB_QUAD_DL
, .modulo
= 13, .frame_nr
= 0 },
317 { .sched_set
= NB_QUAD_DL
, .modulo
= 13, .frame_nr
= 4 },
318 { .sched_set
= NB_QUAD_DL
, .modulo
= 13, .frame_nr
= 8 },
319 /* NOTE: receive only task */
320 { .sched_set
= NULL
}
323 static const struct mframe_sched_item mf_gprs_ptcch
[] = {
324 /* TODO: implement AB_PTCCH_UL for PTCCH/U */
325 /* TODO: implement NB_PTCCH_DL for PTCCH/D */
328 { .sched_set
= NB_PTCCH_DL
, .modulo
= 104, .frame_nr
= 12, .flags
= MF_F_PTCCH
},
329 { .sched_set
= NB_PTCCH_DL
, .modulo
= 104, .frame_nr
= 38, .flags
= MF_F_PTCCH
},
330 { .sched_set
= NB_PTCCH_DL
, .modulo
= 104, .frame_nr
= 64, .flags
= MF_F_PTCCH
},
331 { .sched_set
= NB_PTCCH_DL
, .modulo
= 104, .frame_nr
= 90, .flags
= MF_F_PTCCH
},
333 /* PTCCH/U for TAI 0 .. 3 */
334 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 12 },
335 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 38 },
336 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 64 },
337 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 90 },
339 /* PTCCH/U for TAI 4 .. 7 */
340 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 116 },
341 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 142 },
342 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 168 },
343 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 194 },
345 /* PTCCH/U for TAI 8 .. 11 */
346 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 220 },
347 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 246 },
348 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 272 },
349 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 298 },
351 /* PTCCH/U for TAI 12 .. 15 */
352 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 324 },
353 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 350 },
354 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 376 },
355 { .sched_set
= AB_PTCCH_UL
, .modulo
= 416, .frame_nr
= 402 },
357 { .sched_set
= NULL
}
361 static const struct mframe_sched_item mf_tx_all_nb
[] = {
362 { .sched_set
= NB_QUAD_FH_UL
, .modulo
= 4, .frame_nr
= 0 },
363 { .sched_set
= NULL
}
366 static const struct mframe_sched_item
*sched_set_for_task
[32] = {
367 [MF_TASK_BCCH_NORM
] = mf_bcch_norm
,
368 [MF_TASK_BCCH_EXT
] = mf_bcch_ext
,
369 [MF_TASK_CCCH
] = mf_ccch
,
370 [MF_TASK_CCCH_COMB
] = mf_ccch_comb
,
372 [MF_TASK_SDCCH4_0
] = mf_sdcch4_0
,
373 [MF_TASK_SDCCH4_1
] = mf_sdcch4_1
,
374 [MF_TASK_SDCCH4_2
] = mf_sdcch4_2
,
375 [MF_TASK_SDCCH4_3
] = mf_sdcch4_3
,
377 [MF_TASK_SDCCH8_0
] = mf_sdcch8_0
,
378 [MF_TASK_SDCCH8_1
] = mf_sdcch8_1
,
379 [MF_TASK_SDCCH8_2
] = mf_sdcch8_2
,
380 [MF_TASK_SDCCH8_3
] = mf_sdcch8_3
,
381 [MF_TASK_SDCCH8_4
] = mf_sdcch8_4
,
382 [MF_TASK_SDCCH8_5
] = mf_sdcch8_5
,
383 [MF_TASK_SDCCH8_6
] = mf_sdcch8_6
,
384 [MF_TASK_SDCCH8_7
] = mf_sdcch8_7
,
386 [MF_TASK_SDCCH4_CBCH
] = mf_sdcch4_cbch
,
387 [MF_TASK_SDCCH8_CBCH
] = mf_sdcch8_cbch
,
389 [MF_TASK_TCH_F_EVEN
] = mf_tch_f_even
,
390 [MF_TASK_TCH_F_ODD
] = mf_tch_f_odd
,
391 [MF_TASK_TCH_H_0
] = mf_tch_h_0
,
392 [MF_TASK_TCH_H_1
] = mf_tch_h_1
,
394 [MF_TASK_GPRS_PDTCH
] = mf_gprs_pdtch
,
395 [MF_TASK_GPRS_PTCCH
] = mf_gprs_ptcch
,
397 [MF_TASK_NEIGH_PM51_C0T0
] = mf_neigh_pm51_c0t0
,
398 [MF_TASK_NEIGH_PM51
] = mf_neigh_pm51
,
399 [MF_TASK_NEIGH_PM26E
] = mf_neigh_pm26_even
,
400 [MF_TASK_NEIGH_PM26O
] = mf_neigh_pm26_odd
,
402 [MF_TASK_UL_ALL_NB
] = mf_tx_all_nb
,
405 /* encodes a channel number according to 08.58 Chapter 9.3.1 */
406 uint8_t mframe_task2chan_nr(enum mframe_task mft
, uint8_t ts
)
411 case MF_TASK_BCCH_NORM
:
412 case MF_TASK_BCCH_EXT
:
416 case MF_TASK_CCCH_COMB
:
419 case MF_TASK_SDCCH4_0
:
422 case MF_TASK_SDCCH4_1
:
425 case MF_TASK_SDCCH4_2
:
428 case MF_TASK_SDCCH4_3
:
431 case MF_TASK_SDCCH8_0
:
434 case MF_TASK_SDCCH8_1
:
437 case MF_TASK_SDCCH8_2
:
440 case MF_TASK_SDCCH8_3
:
443 case MF_TASK_SDCCH8_4
:
446 case MF_TASK_SDCCH8_5
:
449 case MF_TASK_SDCCH8_6
:
452 case MF_TASK_SDCCH8_7
:
455 case MF_TASK_TCH_F_EVEN
:
456 case MF_TASK_TCH_F_ODD
:
459 case MF_TASK_TCH_H_0
:
462 case MF_TASK_TCH_H_1
:
466 /* Osmocom specific extensions */
467 case MF_TASK_GPRS_PDTCH
:
468 case MF_TASK_GPRS_PTCCH
:
471 case MF_TASK_SDCCH4_CBCH
:
474 case MF_TASK_SDCCH8_CBCH
:
478 case MF_TASK_UL_ALL_NB
:
480 printd("ERROR: cannot express mf_task=%d as "
481 "channel number, using 0x00\n", mft
);
485 return (cbits
<< 3) | (ts
& 0x7);
488 /* how many TDMA frame ticks should we schedule events ahead? */
489 #define SCHEDULE_AHEAD 2
491 /* how long do we need to tell the DSP in advance what we want to do? */
492 #define SCHEDULE_LATENCY 1
494 /* (test and) schedule one particular sched_item_set by means of the TDMA scheduler */
495 static void mframe_schedule_set(enum mframe_task task_id
)
497 const struct mframe_sched_item
*set
= sched_set_for_task
[task_id
];
498 const struct mframe_sched_item
*si
;
500 for (si
= set
; si
->sched_set
!= NULL
; si
++) {
501 unsigned int trigger
= si
->frame_nr
% si
->modulo
;
502 unsigned int current
= (l1s
.current_time
.fn
+ SCHEDULE_AHEAD
) % si
->modulo
;
503 if (current
== trigger
) {
507 /* Schedule the set */
508 /* FIXME: what to do with SACCH Flag etc? */
509 rv
= tdma_schedule_set(SCHEDULE_AHEAD
-SCHEDULE_LATENCY
,
510 si
->sched_set
, task_id
| (si
->flags
<<8));
512 /* Compute the next safe time to queue a DSP command */
513 fn
= l1s
.current_time
.fn
;
514 ADD_MODULO(fn
, rv
- 2, GSM_MAX_FN
); /* -2 = worst case last dsp command */
515 if ((fn
> l1s
.mframe_sched
.safe_fn
) ||
516 (l1s
.mframe_sched
.safe_fn
>= GSM_MAX_FN
))
517 l1s
.mframe_sched
.safe_fn
= fn
;
522 /* Enable a specific task */
523 void mframe_enable(enum mframe_task task_id
)
525 l1s
.mframe_sched
.tasks_tgt
|= (1 << task_id
);
528 /* Disable a specific task */
529 void mframe_disable(enum mframe_task task_id
)
531 l1s
.mframe_sched
.tasks_tgt
&= ~(1 << task_id
);
534 /* Replace the current active set by the new one */
535 void mframe_set(uint32_t tasks
)
537 l1s
.mframe_sched
.tasks_tgt
= tasks
;
540 /* Schedule mframe_sched_items according to current MF TASK list */
541 void mframe_schedule(void)
546 /* Try to enable/disable task to meet target bitmap */
547 fn_diff
= l1s
.mframe_sched
.safe_fn
- l1s
.current_time
.fn
;
548 if ((fn_diff
<= 0) || (fn_diff
>= (GSM_MAX_FN
>>1)) ||
549 (l1s
.mframe_sched
.safe_fn
>= GSM_MAX_FN
))
550 /* If nothing is in the way, enable new tasks */
551 l1s
.mframe_sched
.tasks
= l1s
.mframe_sched
.tasks_tgt
;
553 /* Else, Disable only */
554 l1s
.mframe_sched
.tasks
&= l1s
.mframe_sched
.tasks_tgt
;
556 /* Schedule any active pending set */
557 for (i
= 0; i
< 32; i
++) {
558 if (l1s
.mframe_sched
.tasks
& (1 << i
))
559 mframe_schedule_set(i
);
563 /* reset the scheduler, disabling all tasks */
564 void mframe_reset(void)
566 l1s
.mframe_sched
.tasks
= 0;
567 l1s
.mframe_sched
.tasks_tgt
= 0;
568 l1s
.mframe_sched
.safe_fn
= -1UL; /* Force safe */