firmware/layer1: introduce experimental PDCH support
[osmocom-bb.git] / src / target / firmware / layer1 / mframe_sched.c
blobfac84b43e89c1bbf4ab85071e7ab2ccc4dbd1a55
1 /* GSM Multiframe Scheduler Implementation (on top of TDMA sched) */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
5 * All Rights Reserved
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.
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
27 #include <debug.h>
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 */
41 uint16_t modulo;
42 /* At which number inside the modulo shall we be scheduled */
43 uint16_t frame_nr;
44 /* bit-mask of flags */
45 uint16_t 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
55 /* BCCH Normal */
56 static const struct mframe_sched_item mf_bcch_norm[] = {
57 { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 2 },
58 { .sched_set = NULL }
61 /* BCCH Extended */
62 static const struct mframe_sched_item mf_bcch_ext[] = {
63 { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
64 { .sched_set = NULL }
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 },
78 { .sched_set = NULL }
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 },
86 { .sched_set = NULL }
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 },
97 { .sched_set = NULL }
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 }
227 /* TCH */
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 */
326 #if 0
327 /* 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 },
356 #endif
357 { .sched_set = NULL }
360 /* Test TX */
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)
408 uint8_t cbits;
410 switch (mft) {
411 case MF_TASK_BCCH_NORM:
412 case MF_TASK_BCCH_EXT:
413 cbits = 0x10;
414 break;
415 case MF_TASK_CCCH:
416 case MF_TASK_CCCH_COMB:
417 cbits = 0x12;
418 break;
419 case MF_TASK_SDCCH4_0:
420 cbits = 0x04 + 0;
421 break;
422 case MF_TASK_SDCCH4_1:
423 cbits = 0x04 + 1;
424 break;
425 case MF_TASK_SDCCH4_2:
426 cbits = 0x04 + 2;
427 break;
428 case MF_TASK_SDCCH4_3:
429 cbits = 0x04 + 3;
430 break;
431 case MF_TASK_SDCCH8_0:
432 cbits = 0x08 + 0;
433 break;
434 case MF_TASK_SDCCH8_1:
435 cbits = 0x08 + 1;
436 break;
437 case MF_TASK_SDCCH8_2:
438 cbits = 0x08 + 2;
439 break;
440 case MF_TASK_SDCCH8_3:
441 cbits = 0x08 + 3;
442 break;
443 case MF_TASK_SDCCH8_4:
444 cbits = 0x08 + 4;
445 break;
446 case MF_TASK_SDCCH8_5:
447 cbits = 0x08 + 5;
448 break;
449 case MF_TASK_SDCCH8_6:
450 cbits = 0x08 + 6;
451 break;
452 case MF_TASK_SDCCH8_7:
453 cbits = 0x08 + 7;
454 break;
455 case MF_TASK_TCH_F_EVEN:
456 case MF_TASK_TCH_F_ODD:
457 cbits = 0x01;
458 break;
459 case MF_TASK_TCH_H_0:
460 cbits = 0x02 + 0;
461 break;
462 case MF_TASK_TCH_H_1:
463 cbits = 0x02 + 1;
464 break;
466 /* Osmocom specific extensions */
467 case MF_TASK_GPRS_PDTCH:
468 case MF_TASK_GPRS_PTCCH:
469 cbits = 0x18;
470 break;
471 case MF_TASK_SDCCH4_CBCH:
472 cbits = 0x19;
473 break;
474 case MF_TASK_SDCCH8_CBCH:
475 cbits = 0x1a;
476 break;
478 case MF_TASK_UL_ALL_NB:
479 default:
480 printd("ERROR: cannot express mf_task=%d as "
481 "channel number, using 0x00\n", mft);
482 cbits = 0x00;
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) {
504 uint32_t fn;
505 int rv;
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)
543 unsigned int i;
544 int fn_diff;
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;
552 else
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 */