120 lines
3.4 KiB
C
120 lines
3.4 KiB
C
/* GSM-Time One-shot Event Scheduler Implementation (on top of TDMA sched) */
|
|
|
|
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <errno.h>
|
|
|
|
#include <debug.h>
|
|
#include <osmocom/core/linuxlist.h>
|
|
|
|
#include <layer1/tdma_sched.h>
|
|
#include <layer1/sched_gsmtime.h>
|
|
|
|
static struct sched_gsmtime_event sched_gsmtime_events[16];
|
|
static LLIST_HEAD(active_evts);
|
|
static LLIST_HEAD(inactive_evts);
|
|
|
|
/* Scheduling of a tdma_sched_item list one-shot at a given GSM time */
|
|
int sched_gsmtime(const struct tdma_sched_item *si, uint32_t fn, uint16_t p3)
|
|
{
|
|
struct llist_head *lh;
|
|
struct sched_gsmtime_event *evt, *cur;
|
|
|
|
printd("sched_gsmtime(si=%p, fn=%u)\n", si, fn);
|
|
|
|
/* obtain a free/inactive event structure */
|
|
if (llist_empty(&inactive_evts))
|
|
return -EBUSY;
|
|
lh = inactive_evts.next;
|
|
llist_del(lh);
|
|
evt = llist_entry(lh, struct sched_gsmtime_event, list);
|
|
|
|
evt->fn = fn;
|
|
evt->si = si;
|
|
evt->p3 = p3;
|
|
|
|
/* do a sorted insert into the list, i.e. insert the new
|
|
* event _before_ the first entry that has a higher fn */
|
|
llist_for_each_entry(cur, &active_evts, list) {
|
|
if (cur->fn > evt->fn) {
|
|
llist_add_tail(lh, &cur->list);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* if we reach here, active_evts is empty _OR_ new event
|
|
* is after all the other events: append at end of list */
|
|
llist_add_tail(lh, &active_evts);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* how many TDMA frame ticks should we schedule events ahead? */
|
|
#define SCHEDULE_AHEAD 2
|
|
|
|
/* how long do we need to tell the DSP in advance what we want to do? */
|
|
#define SCHEDULE_LATENCY 1
|
|
|
|
/* execute all GSMTIME one-shot events pending for 'fn' */
|
|
int sched_gsmtime_execute(uint32_t fn)
|
|
{
|
|
struct sched_gsmtime_event *evt, *evt2;
|
|
int num = 0;
|
|
|
|
llist_for_each_entry_safe(evt, evt2, &active_evts, list) {
|
|
if (evt->fn == fn + SCHEDULE_AHEAD) {
|
|
printd("sched_gsmtime_execute(time=%u): fn=%u si=%p\n", fn, evt->fn, evt->si);
|
|
tdma_schedule_set(SCHEDULE_AHEAD-SCHEDULE_LATENCY,
|
|
evt->si, evt->p3);
|
|
llist_del(&evt->list);
|
|
/* put event back in list of inactive (free) events */
|
|
llist_add(&evt->list, &inactive_evts);
|
|
num++;
|
|
} if (evt->fn > fn + SCHEDULE_AHEAD) {
|
|
/* break the loop as our list is ordered */
|
|
break;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
void sched_gsmtime_init(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
printd("sched_gsmtime_init()\n");
|
|
|
|
for (i = 0; i < ARRAY_SIZE(sched_gsmtime_events); i++)
|
|
llist_add(&sched_gsmtime_events[i].list, &inactive_evts);
|
|
}
|
|
|
|
void sched_gsmtime_reset(void)
|
|
{
|
|
struct sched_gsmtime_event *evt, *evt2;
|
|
|
|
llist_for_each_entry_safe(evt, evt2, &active_evts, list) {
|
|
llist_del(&evt->list);
|
|
/* put event back in list of inactive (free) events */
|
|
llist_add(&evt->list, &inactive_evts);
|
|
}
|
|
}
|