1 /* GSM-Time One-shot Event 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.
27 #include <osmocom/core/linuxlist.h>
29 #include <layer1/tdma_sched.h>
30 #include <layer1/sched_gsmtime.h>
32 static struct sched_gsmtime_event sched_gsmtime_events[16];
33 static LLIST_HEAD(active_evts);
34 static LLIST_HEAD(inactive_evts);
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)
39 struct llist_head *lh;
40 struct sched_gsmtime_event *evt, *cur;
42 printd("sched_gsmtime(si=%p, fn=%u)\n", si, fn);
44 /* obtain a free/inactive event structure */
45 if (llist_empty(&inactive_evts))
47 lh = inactive_evts.next;
49 evt = llist_entry(lh, struct sched_gsmtime_event, list);
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);
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);
71 /* how many TDMA frame ticks should we schedule events ahead? */
72 #define SCHEDULE_AHEAD 2
74 /* how long do we need to tell the DSP in advance what we want to do? */
75 #define SCHEDULE_LATENCY 1
77 /* execute all GSMTIME one-shot events pending for 'fn' */
78 int sched_gsmtime_execute(uint32_t fn)
80 struct sched_gsmtime_event *evt, *evt2;
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,
88 llist_del(&evt->list);
89 /* put event back in list of inactive (free) events */
90 llist_add(&evt->list, &inactive_evts);
92 } if (evt->fn > fn + SCHEDULE_AHEAD) {
93 /* break the loop as our list is ordered */
100 void sched_gsmtime_init(void)
104 printd("sched_gsmtime_init()\n");
106 for (i = 0; i < ARRAY_SIZE(sched_gsmtime_events); i++)
107 llist_add(&sched_gsmtime_events[i].list, &inactive_evts);
110 void sched_gsmtime_reset(void)
112 struct sched_gsmtime_event *evt, *evt2;
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);