fw/l1/mframe_sched: Fix the TCH_A entries to include the MF_F_SACCH flag
[osmocom-bb.git] / src / target / firmware / layer1 / mframe_sched.c
1 /* GSM Multiframe Scheduler Implementation (on top of TDMA sched) */
2
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4  *
5  * All Rights Reserved
6  *
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.
11  *
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.
16  *
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.
20  *
21  */
22
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <debug.h>
28
29 #include <osmocore/gsm_utils.h>
30
31 #include <layer1/prim.h>
32 #include <layer1/sync.h>
33 #include <layer1/tdma_sched.h>
34 #include <layer1/mframe_sched.h>
35
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;
46 };
47
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
54 /* BCCH Normal */
55 static const struct mframe_sched_item mf_bcch_norm[] = {
56         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 2 },
57         { .sched_set = NULL }
58 };
59
60 /* BCCH Extended */
61 static const struct mframe_sched_item mf_bcch_ext[] = {
62         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
63         { .sched_set = NULL }
64 };
65
66 /* Full CCCH in a pure BCCH + CCCH C0T0 */
67 static const struct mframe_sched_item mf_ccch[] = {
68         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
69         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 12 },
70         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 16 },
71         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 22 },
72         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 26 },
73         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 32 },
74         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 36 },
75         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 42 },
76         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 46 },
77         { .sched_set = NULL }
78 };
79
80 /* Full CCCH in a combined CCCH on C0T0 */
81 static const struct mframe_sched_item mf_ccch_comb[] = {
82         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 6 },
83         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 12 },
84         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 16 },
85         { .sched_set = NULL }
86 };
87
88 /* SDCCH/4 in a combined CCCH on C0T0, cannot be FH */
89 static const struct mframe_sched_item mf_sdcch4_0[] = {
90         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 22 },
91         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 22+15 },
92         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 42,
93           .flags = MF_F_SACCH },
94         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 42+15,
95           .flags = MF_F_SACCH },
96         { .sched_set = NULL }
97 };
98 static const struct mframe_sched_item mf_sdcch4_1[] = {
99         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 26 },
100         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 26+15 },
101         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 46,
102           .flags = MF_F_SACCH },
103         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 46+15,
104           .flags = MF_F_SACCH },
105         { .sched_set = NULL }
106 };
107 static const struct mframe_sched_item mf_sdcch4_2[] = {
108         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 32 },
109         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 32+15 },
110         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+42,
111           .flags = MF_F_SACCH },
112         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+42+15,
113           .flags = MF_F_SACCH },
114         { .sched_set = NULL }
115 };
116 static const struct mframe_sched_item mf_sdcch4_3[] = {
117         { .sched_set = NB_QUAD_DL, .modulo = 51, .frame_nr = 36 },
118         { .sched_set = NB_QUAD_UL, .modulo = 51, .frame_nr = 36+15 },
119         { .sched_set = NB_QUAD_DL, .modulo = 2*51, .frame_nr = 51+46,
120           .flags = MF_F_SACCH },
121         { .sched_set = NB_QUAD_UL, .modulo = 2*51, .frame_nr = 51+46+15,
122           .flags = MF_F_SACCH },
123         { .sched_set = NULL }
124 };
125
126 /* SDCCH/8, can be frequency hopping (FH) */
127 static const struct mframe_sched_item mf_sdcch8_0[] = {
128         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 0 },
129         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 0+15 },
130         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 32,
131           .flags = MF_F_SACCH },
132         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 32+15,
133           .flags = MF_F_SACCH },
134         { .sched_set = NULL }
135 };
136 static const struct mframe_sched_item mf_sdcch8_1[] = {
137         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 4 },
138         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 4+15 },
139         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 36,
140           .flags = MF_F_SACCH },
141         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 36+15,
142           .flags = MF_F_SACCH },
143         { .sched_set = NULL }
144 };
145 static const struct mframe_sched_item mf_sdcch8_2[] = {
146         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 8 },
147         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 8+15 },
148         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 40,
149           .flags = MF_F_SACCH },
150         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 40+15,
151           .flags = MF_F_SACCH },
152         { .sched_set = NULL }
153 };
154 static const struct mframe_sched_item mf_sdcch8_3[] = {
155         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 12 },
156         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 12+15 },
157         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 44,
158           .flags = MF_F_SACCH },
159         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 44+15,
160           .flags = MF_F_SACCH },
161         { .sched_set = NULL }
162 };
163 static const struct mframe_sched_item mf_sdcch8_4[] = {
164         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 16 },
165         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 16+15 },
166         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+32,
167           .flags = MF_F_SACCH },
168         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+32+15,
169           .flags = MF_F_SACCH },
170         { .sched_set = NULL }
171 };
172 static const struct mframe_sched_item mf_sdcch8_5[] = {
173         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 20 },
174         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 20+15 },
175         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+36,
176           .flags = MF_F_SACCH },
177         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+36+15,
178           .flags = MF_F_SACCH },
179         { .sched_set = NULL }
180 };
181 static const struct mframe_sched_item mf_sdcch8_6[] = {
182         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 24 },
183         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 24+15 },
184         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+40,
185           .flags = MF_F_SACCH },
186         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+40+15,
187           .flags = MF_F_SACCH },
188         { .sched_set = NULL }
189 };
190 static const struct mframe_sched_item mf_sdcch8_7[] = {
191         { .sched_set = NB_QUAD_FH_DL, .modulo = 51, .frame_nr = 28 },
192         { .sched_set = NB_QUAD_FH_UL, .modulo = 51, .frame_nr = 28+15 },
193         { .sched_set = NB_QUAD_FH_DL, .modulo = 2*51, .frame_nr = 51+44,
194           .flags = MF_F_SACCH },
195         { .sched_set = NB_QUAD_FH_UL, .modulo = 2*51, .frame_nr = 51+44+15,
196           .flags = MF_F_SACCH },
197         { .sched_set = NULL }
198 };
199
200 /* TCH */
201 #define TCH     tch_sched_set
202 #define TCH_A   tch_a_sched_set
203 #define TCH_D   tch_d_sched_set
204
205 static const struct mframe_sched_item mf_tch_f_even[] = {
206         { .sched_set = TCH,   .modulo = 13, .frame_nr =  0 },
207         { .sched_set = TCH,   .modulo = 13, .frame_nr =  1 },
208         { .sched_set = TCH,   .modulo = 13, .frame_nr =  2 },
209         { .sched_set = TCH,   .modulo = 13, .frame_nr =  3 },
210         { .sched_set = TCH,   .modulo = 13, .frame_nr =  4 },
211         { .sched_set = TCH,   .modulo = 13, .frame_nr =  5 },
212         { .sched_set = TCH,   .modulo = 13, .frame_nr =  6 },
213         { .sched_set = TCH,   .modulo = 13, .frame_nr =  7 },
214         { .sched_set = TCH,   .modulo = 13, .frame_nr =  8 },
215         { .sched_set = TCH,   .modulo = 13, .frame_nr =  9 },
216         { .sched_set = TCH,   .modulo = 13, .frame_nr = 10 },
217         { .sched_set = TCH,   .modulo = 13, .frame_nr = 11 },
218         { .sched_set = TCH_A, .modulo = 26, .frame_nr = 12,
219           .flags = MF_F_SACCH },
220         { .sched_set = NULL }
221 };
222
223 static const struct mframe_sched_item mf_tch_f_odd[] = {
224         { .sched_set = TCH,   .modulo = 13, .frame_nr =  0 },
225         { .sched_set = TCH,   .modulo = 13, .frame_nr =  1 },
226         { .sched_set = TCH,   .modulo = 13, .frame_nr =  2 },
227         { .sched_set = TCH,   .modulo = 13, .frame_nr =  3 },
228         { .sched_set = TCH,   .modulo = 13, .frame_nr =  4 },
229         { .sched_set = TCH,   .modulo = 13, .frame_nr =  5 },
230         { .sched_set = TCH,   .modulo = 13, .frame_nr =  6 },
231         { .sched_set = TCH,   .modulo = 13, .frame_nr =  7 },
232         { .sched_set = TCH,   .modulo = 13, .frame_nr =  8 },
233         { .sched_set = TCH,   .modulo = 13, .frame_nr =  9 },
234         { .sched_set = TCH,   .modulo = 13, .frame_nr = 10 },
235         { .sched_set = TCH,   .modulo = 13, .frame_nr = 11 },
236         { .sched_set = TCH_A, .modulo = 26, .frame_nr = 25,
237           .flags = MF_F_SACCH },
238         { .sched_set = NULL }
239 };
240
241 static const struct mframe_sched_item mf_tch_h_0[] = {
242         { .sched_set = TCH,   .modulo = 13, .frame_nr =  0 },
243         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  1 },
244         { .sched_set = TCH,   .modulo = 13, .frame_nr =  2 },
245         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  3 },
246         { .sched_set = TCH,   .modulo = 13, .frame_nr =  4 },
247         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  5 },
248         { .sched_set = TCH,   .modulo = 13, .frame_nr =  6 },
249         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  7 },
250         { .sched_set = TCH,   .modulo = 13, .frame_nr =  8 },
251         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  9 },
252         { .sched_set = TCH,   .modulo = 13, .frame_nr = 10 },
253         { .sched_set = TCH_D, .modulo = 13, .frame_nr = 11 },
254         { .sched_set = TCH_A, .modulo = 26, .frame_nr = 12,
255           .flags = MF_F_SACCH },
256         { .sched_set = NULL }
257 };
258
259 static const struct mframe_sched_item mf_tch_h_1[] = {
260         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  0 },
261         { .sched_set = TCH,   .modulo = 13, .frame_nr =  1 },
262         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  2 },
263         { .sched_set = TCH,   .modulo = 13, .frame_nr =  3 },
264         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  4 },
265         { .sched_set = TCH,   .modulo = 13, .frame_nr =  5 },
266         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  6 },
267         { .sched_set = TCH,   .modulo = 13, .frame_nr =  7 },
268         { .sched_set = TCH_D, .modulo = 13, .frame_nr =  8 },
269         { .sched_set = TCH,   .modulo = 13, .frame_nr =  9 },
270         { .sched_set = TCH_D, .modulo = 13, .frame_nr = 10 },
271         { .sched_set = TCH,   .modulo = 13, .frame_nr = 11 },
272         { .sched_set = TCH_A, .modulo = 26, .frame_nr = 25,
273           .flags = MF_F_SACCH },
274         { .sched_set = NULL }
275 };
276
277 /* Test TX */
278 static const struct mframe_sched_item mf_tx_all_nb[] = {
279         { .sched_set = NB_QUAD_FH_UL, .modulo = 4, .frame_nr = 0 },
280         { .sched_set = NULL }
281 };
282
283 static const struct mframe_sched_item *sched_set_for_task[32] = {
284         [MF_TASK_BCCH_NORM] = mf_bcch_norm,
285         [MF_TASK_BCCH_EXT] = mf_bcch_ext,
286         [MF_TASK_CCCH] = mf_ccch,
287         [MF_TASK_CCCH_COMB] = mf_ccch_comb,
288
289         [MF_TASK_SDCCH4_0] = mf_sdcch4_0,
290         [MF_TASK_SDCCH4_1] = mf_sdcch4_1,
291         [MF_TASK_SDCCH4_2] = mf_sdcch4_2,
292         [MF_TASK_SDCCH4_3] = mf_sdcch4_3,
293
294         [MF_TASK_SDCCH8_0] = mf_sdcch8_0,
295         [MF_TASK_SDCCH8_1] = mf_sdcch8_1,
296         [MF_TASK_SDCCH8_2] = mf_sdcch8_2,
297         [MF_TASK_SDCCH8_3] = mf_sdcch8_3,
298         [MF_TASK_SDCCH8_4] = mf_sdcch8_4,
299         [MF_TASK_SDCCH8_5] = mf_sdcch8_5,
300         [MF_TASK_SDCCH8_6] = mf_sdcch8_6,
301         [MF_TASK_SDCCH8_7] = mf_sdcch8_7,
302
303         [MF_TASK_TCH_F_EVEN] = mf_tch_f_even,
304         [MF_TASK_TCH_F_ODD]  = mf_tch_f_odd,
305         [MF_TASK_TCH_H_0]    = mf_tch_h_0,
306         [MF_TASK_TCH_H_1]    = mf_tch_h_1,
307
308         [MF_TASK_UL_ALL_NB] = mf_tx_all_nb,
309 };
310
311 /* encodes a channel number according to 08.58 Chapter 9.3.1 */
312 uint8_t mframe_task2chan_nr(enum mframe_task mft, uint8_t ts)
313 {
314         uint8_t cbits;
315
316         switch (mft) {
317         case MF_TASK_BCCH_NORM:
318         case MF_TASK_BCCH_EXT:
319                 cbits = 0x10;
320                 break;
321         case MF_TASK_CCCH:
322         case MF_TASK_CCCH_COMB:
323                 cbits = 0x12;
324                 break;
325         case MF_TASK_SDCCH4_0:
326                 cbits = 0x04 + 0;
327                 break;
328         case MF_TASK_SDCCH4_1:
329                 cbits = 0x04 + 1;
330                 break;
331         case MF_TASK_SDCCH4_2:
332                 cbits = 0x04 + 2;
333                 break;
334         case MF_TASK_SDCCH4_3:
335                 cbits = 0x04 + 3;
336                 break;
337         case MF_TASK_SDCCH8_0:
338                 cbits = 0x08 + 0;
339                 break;
340         case MF_TASK_SDCCH8_1:
341                 cbits = 0x08 + 1;
342                 break;
343         case MF_TASK_SDCCH8_2:
344                 cbits = 0x08 + 2;
345                 break;
346         case MF_TASK_SDCCH8_3:
347                 cbits = 0x08 + 3;
348                 break;
349         case MF_TASK_SDCCH8_4:
350                 cbits = 0x08 + 4;
351                 break;
352         case MF_TASK_SDCCH8_5:
353                 cbits = 0x08 + 5;
354                 break;
355         case MF_TASK_SDCCH8_6:
356                 cbits = 0x08 + 6;
357                 break;
358         case MF_TASK_SDCCH8_7:
359                 cbits = 0x08 + 7;
360                 break;
361         case MF_TASK_TCH_F_EVEN:
362         case MF_TASK_TCH_F_ODD:
363                 cbits = 0x01;
364                 break;
365         case MF_TASK_TCH_H_0:
366                 cbits = 0x02 + 0;
367                 break;
368         case MF_TASK_TCH_H_1:
369                 cbits = 0x02 + 1;
370                 break;
371         case MF_TASK_UL_ALL_NB:
372                 /* ERROR: cannot express as channel number */
373                 cbits = 0;
374                 break;
375         }
376
377         return (cbits << 3) | (ts & 0x7);
378 }
379
380 /* how many TDMA frame ticks should we schedule events ahead? */
381 #define SCHEDULE_AHEAD  2
382
383 /* how long do we need to tell the DSP in advance what we want to do? */
384 #define SCHEDULE_LATENCY        1
385
386 /* (test and) schedule one particular sched_item_set by means of the TDMA scheduler */
387 static void mframe_schedule_set(enum mframe_task task_id)
388 {
389         const struct mframe_sched_item *set = sched_set_for_task[task_id];
390         const struct mframe_sched_item *si;
391
392         for (si = set; si->sched_set != NULL; si++) {
393                 unsigned int trigger = si->frame_nr % si->modulo;
394                 unsigned int current = (l1s.current_time.fn + SCHEDULE_AHEAD) % si->modulo;
395                 if (current == trigger) {
396                         uint32_t fn;
397                         int rv;
398
399                         /* Schedule the set */
400                         /* FIXME: what to do with SACCH Flag etc? */
401                         rv = tdma_schedule_set(SCHEDULE_AHEAD-SCHEDULE_LATENCY,
402                                           si->sched_set, task_id | (si->flags<<8));
403
404                         /* Compute the next safe time to queue a DSP command */
405                         fn = l1s.current_time.fn;
406                         ADD_MODULO(fn, rv - 2, GSM_MAX_FN); /* -2 = worst case last dsp command */
407                         if ((fn > l1s.mframe_sched.safe_fn) ||
408                             (l1s.mframe_sched.safe_fn >= GSM_MAX_FN))
409                                 l1s.mframe_sched.safe_fn = fn;
410                 }
411         }
412 }
413
414 /* Enable a specific task */
415 void mframe_enable(enum mframe_task task_id)
416 {
417         l1s.mframe_sched.tasks_tgt |= (1 << task_id);
418 }
419
420 /* Disable a specific task */
421 void mframe_disable(enum mframe_task task_id)
422 {
423         l1s.mframe_sched.tasks_tgt &= ~(1 << task_id);
424 }
425
426 /* Replace the current active set by the new one */
427 void mframe_set(uint32_t tasks)
428 {
429         l1s.mframe_sched.tasks_tgt = tasks;
430 }
431
432 /* Schedule mframe_sched_items according to current MF TASK list */
433 void mframe_schedule(void)
434 {
435         unsigned int i;
436         int fn_diff;
437
438         /* Try to enable/disable task to meet target bitmap */
439         fn_diff = l1s.mframe_sched.safe_fn - l1s.current_time.fn;
440         if ((fn_diff <= 0) || (fn_diff >= (GSM_MAX_FN>>1)) ||
441             (l1s.mframe_sched.safe_fn >= GSM_MAX_FN))
442                 /* If nothing is in the way, enable new tasks */
443                 l1s.mframe_sched.tasks = l1s.mframe_sched.tasks_tgt;
444         else
445                 /* Else, Disable only */
446                 l1s.mframe_sched.tasks &= l1s.mframe_sched.tasks_tgt;
447
448         /* Schedule any active pending set */
449         for (i = 0; i < 32; i++) {
450                 if (l1s.mframe_sched.tasks & (1 << i))
451                         mframe_schedule_set(i);
452         }
453 }
454
455 /* reset the scheduler, disabling all tasks */
456 void mframe_reset(void)
457 {
458         l1s.mframe_sched.tasks = 0;
459         l1s.mframe_sched.tasks_tgt = 0;
460         l1s.mframe_sched.safe_fn = -1UL;        /* Force safe */
461 }
462