src: use new libosmogsm and include/osmocom/[gsm|core] path to headers
[osmocom-bb.git] / src / target / firmware / layer1 / sched_gsmtime.c
1 /* GSM-Time One-shot Event 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 <errno.h>
25
26 #include <debug.h>
27 #include <osmocom/core/linuxlist.h>
28
29 #include <layer1/tdma_sched.h>
30 #include <layer1/sched_gsmtime.h>
31
32 static struct sched_gsmtime_event sched_gsmtime_events[16];
33 static LLIST_HEAD(active_evts);
34 static LLIST_HEAD(inactive_evts);
35
36 /* Scheduling of a tdma_sched_item list one-shot at a given GSM time */
37 int sched_gsmtime(const struct tdma_sched_item *si, uint32_t fn, uint16_t p3)
38 {
39         struct llist_head *lh;
40         struct sched_gsmtime_event *evt, *cur;
41
42         printd("sched_gsmtime(si=%p, fn=%u)\n", si, fn);
43
44         /* obtain a free/inactive event structure */
45         if (llist_empty(&inactive_evts))
46                 return -EBUSY;
47         lh = inactive_evts.next;
48         llist_del(lh);
49         evt = llist_entry(lh, struct sched_gsmtime_event, list);
50
51         evt->fn = fn;
52         evt->si = si;
53         evt->p3 = p3;
54
55         /* do a sorted insert into the list, i.e. insert the new
56          * event _before_ the first entry that has a higher fn */
57         llist_for_each_entry(cur, &active_evts, list) {
58                 if (cur->fn > evt->fn) {
59                         llist_add_tail(lh, &cur->list);
60                         return 0;
61                 }
62         }
63
64         /* if we reach here, active_evts is empty _OR_ new event
65          * is after all the other events: append at end of list */
66         llist_add_tail(lh, &active_evts);
67
68         return 0;
69 }
70
71 /* how many TDMA frame ticks should we schedule events ahead? */
72 #define SCHEDULE_AHEAD  2
73
74 /* how long do we need to tell the DSP in advance what we want to do? */
75 #define SCHEDULE_LATENCY        1
76
77 /* execute all GSMTIME one-shot events pending for 'fn' */
78 int sched_gsmtime_execute(uint32_t fn)
79 {
80         struct sched_gsmtime_event *evt, *evt2;
81         int num = 0;
82
83         llist_for_each_entry_safe(evt, evt2, &active_evts, list) {
84                 if (evt->fn == fn + SCHEDULE_AHEAD) {
85                         printd("sched_gsmtime_execute(time=%u): fn=%u si=%p\n", fn, evt->fn, evt->si);
86                         tdma_schedule_set(SCHEDULE_AHEAD-SCHEDULE_LATENCY,
87                                           evt->si, evt->p3);
88                         llist_del(&evt->list);
89                         /* put event back in list of inactive (free) events */
90                         llist_add(&evt->list, &inactive_evts);
91                         num++;
92                 } if (evt->fn > fn + SCHEDULE_AHEAD) {
93                         /* break the loop as our list is ordered */
94                         break;
95                 }
96         }
97         return num;
98 }
99
100 void sched_gsmtime_init(void)
101 {
102         unsigned int i;
103
104         printd("sched_gsmtime_init()\n");
105
106         for (i = 0; i < ARRAY_SIZE(sched_gsmtime_events); i++)
107                 llist_add(&sched_gsmtime_events[i].list, &inactive_evts);
108 }
109
110 void sched_gsmtime_reset(void)
111 {
112         struct sched_gsmtime_event *evt, *evt2;
113
114         llist_for_each_entry_safe(evt, evt2, &active_evts, list) {
115                 llist_del(&evt->list);
116                 /* put event back in list of inactive (free) events */
117                 llist_add(&evt->list, &inactive_evts);
118         }
119 }