1/* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18#ifndef OSCL_TIMER_H_INCLUDED
19#define OSCL_TIMER_H_INCLUDED
20
21#ifndef OSCL_BASE_H_INCLUDED
22#include "oscl_base.h"
23#endif
24
25#ifndef OSCLCONFIG_UTIL_H_INCLUDED
26#include "osclconfig_util.h"
27#endif
28
29#ifndef OSCL_VECTOR_H_INCLUDED
30#include "oscl_vector.h"
31#endif
32
33#ifndef OSCL_TICKCOUNT_H_INCLUDED
34#include "oscl_tickcount.h"
35#endif
36
37#ifndef OSCL_RAND_H_INCLUDED
38#include "oscl_rand.h"
39#endif
40
41#ifndef OSCL_SCHEDULER_AO_H_INCLUDED
42#include "oscl_scheduler_ao.h"
43#endif
44
45
46/**
47 * The observer class to receive timeout callbacks
48 */
49class OsclTimerObserver
50{
51    public:
52        /**
53         * This function will be called when the timer associated
54         * with this observer is executed
55         *
56         * @param timerID The ID given at timer request.
57         * @param timeoutInfo
58         *                Any extra info given at timer request.
59         */
60        virtual void TimeoutOccurred(int32 timerID, int32 timeoutInfo) = 0;
61
62        virtual ~OsclTimerObserver() {}
63};
64
65/**
66 * A timer class for scheduling one or more timeout events.
67 * The timeout event will trigger a callback to an observer
68 * class.
69 */
70template<class Alloc>
71class OsclTimer ;
72
73class CallbackTimerObserver
74{
75    public:
76        virtual void TimerBaseElapsed() = 0;
77        virtual ~CallbackTimerObserver() {}
78};
79
80template<class Alloc>
81class CallbackTimer: public OsclTimerObject
82{
83    public:
84        CallbackTimer(CallbackTimerObserver& aContainer, const char *name, int32 aPriority = OsclActiveObject::EPriorityNominal)
85                : OsclTimerObject(aPriority, name)
86        {
87            iContainer = &aContainer;
88            AddToScheduler();
89        }
90        ~CallbackTimer()
91        {
92            RemoveFromScheduler();
93        }
94        void Run()
95        {
96            if (Status() == OSCL_REQUEST_ERR_NONE)
97                iContainer->TimerBaseElapsed();
98        }
99    private:
100        CallbackTimerObserver *iContainer;
101};
102
103
104template<class Alloc>
105class OsclTimer : public CallbackTimerObserver
106{
107    public:
108
109        typedef CallbackTimer<Alloc> callback_timer_type;
110
111        /**
112         * Constructor
113         *
114         * @param frequency The frequency of the timer in cycles/second.  A value of
115         *                  1 means the timer will cycle in 1 second intervals.
116         */
117        OsclTimer(const char *name, uint32 frequency = 1, int32 priority = OsclActiveObject::EPriorityNominal);
118        virtual ~OsclTimer();
119
120        /**
121         * Set the global observer.  Each timer can request a local
122         * observer, which if set overrides the global observer.
123         *
124         * @param obs    observer object.
125         */
126        void SetObserver(OsclTimerObserver *obs)
127        {
128            iObserver = obs;
129        }
130        /**
131         * Set the frequency of the timer in cycles/second.
132         *
133         * @param frequency A value of 1 means the timer will cycle in one second
134         *                  intervals, 1000 means millisecond intervals, etc.
135         */
136        void SetFrequency(uint32 frequency);
137
138        /**
139         * Set the exact frequency of the timer in microsecond.
140         *
141         * @param frequency A value of 1 means the timer will cycle in one microsecond
142         *                  intervals, 1000 means millisecond intervals, etc.
143         */
144        void SetExactFrequency(uint32 frequency);
145
146        /**
147         * Request a timer
148         *
149         * @param timerID used to identify the timer for cancellation.  This value
150         *                will be returned as part of the timeout event.
151         * @param timeoutInfo
152         *                for user info.  Returned to the observer on a timeout event
153         * @param cycles  the number of cycles to wait before a timeout event.  If
154         *                the timer frequency is 1 and the cycles are set to 2, then
155         *                the timeout event will occur in 2 seconds.
156         * @param obs     a local observer object to be called on a timeout event.
157         *                This observer overides the global observer if set.
158         */
159        void Request(int32 timerID, int32 timeoutInfo, int32 cycles, OsclTimerObserver *obs = 0, bool recurring = 0);
160        /**
161         * Cancel a timer
162         *
163         * @param timerID used to identify the timer to cancel.
164         * @param timeoutInfo
165         *                if not set to -1, this value will be used as additional
166         *                matching criteria to cancel a timer.
167         */
168        void Cancel(int32 timerID, int32 timeoutInfo = -1);
169        /**
170         * Cancel all pending timers.
171         */
172        void Clear();
173
174    private:
175        //Note: the timer needs to be a new'd object so that
176        //the CBase construction zeros the memory.
177        callback_timer_type *iTimer;
178
179        typedef struct  _TimerEntry
180        {
181            int32 iCounter ;
182            int32 iTimerID ;
183            int32 iParam ;
184            OsclTimerObserver *iObserver;
185            bool iRecurring;
186            int32 iOrigCounter;
187        } TimerEntry;
188
189        typedef TimerEntry                    entry_type;
190        typedef Oscl_Vector<entry_type*, Alloc> entries_type;
191        typedef typename entries_type::iterator entries_type_iterator;
192
193        OsclTimerObserver *iObserver;
194        entries_type iEntries;
195        entries_type iEntriesWaitingToAdd;
196        entries_type iEntriesWaitingToCancel;
197        Oscl_TAlloc<entry_type, Alloc> iEntryAllocator;
198
199        bool iInCallback;
200
201        uint32 iCyclePeriod;
202        uint32 iTickCountPeriod;
203        uint32 iExpectedTimeout;
204
205    protected:
206        void TimerBaseElapsed();
207        friend class CallbackTimer<Alloc>;
208};
209
210template<class Alloc>
211OsclTimer<Alloc>::OsclTimer(const char *name, uint32 frequency, int32 priority) :
212        iObserver(0)
213        , iInCallback(false)
214        , iTickCountPeriod(0)
215        , iExpectedTimeout(0)
216{
217    //use the allocator with placement 'new'
218    Alloc alloc;
219    iTimer = OSCL_PLACEMENT_NEW(alloc.ALLOCATE(sizeof(CallbackTimer<Alloc>)), CallbackTimer<Alloc>(*this, name, priority));
220    SetFrequency(frequency);
221}
222
223template<class Alloc>
224OsclTimer<Alloc>::~OsclTimer()
225{
226    // Make sure we're cancelled
227    if (iTimer)
228        iTimer->Cancel();
229    if (iTimer)
230    {
231        iTimer->OSCL_TEMPLATED_DESTRUCTOR_CALL(callback_timer_type, CallbackTimer);
232        Alloc alloc;
233        alloc.deallocate(iTimer);
234    }
235    iTimer = NULL;
236
237    for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
238    {
239        iEntryAllocator.deallocate(*it);
240    }
241}
242
243template<class Alloc>
244void OsclTimer<Alloc>::SetFrequency(uint32 frequency)
245{
246    // timer takes microseconds
247    iCyclePeriod = 1000000 / frequency;
248    // get tick count period
249    iTickCountPeriod = OsclTickCount::TickCountPeriod();
250}
251
252template<class Alloc>
253void OsclTimer<Alloc>::SetExactFrequency(uint32 frequency)
254{
255    // timer takes microseconds
256    iCyclePeriod = frequency;
257    // get tick count period
258    iTickCountPeriod = OsclTickCount::TickCountPeriod();
259}
260
261// Request a timer
262template<class Alloc>
263void OsclTimer<Alloc>::Request(int32 timerID, int32 param, int32 cycles, OsclTimerObserver *obs, bool recurring)
264{
265
266    // add to list of timers
267    entry_type *entry = iEntryAllocator.ALLOCATE(1);
268    entry->iTimerID = timerID;
269    entry->iParam = param;
270    entry->iCounter = cycles;
271    entry->iObserver = obs;
272    entry->iRecurring = recurring;
273    entry->iOrigCounter = entry->iCounter;
274
275    // if the request is called inside of a callback, then we must add it later
276    if (iInCallback)
277    {
278        iEntriesWaitingToAdd.push_back(entry);
279        return;
280    }
281
282    iEntries.push_back(entry);
283
284    if (iTimer)
285    {
286        iTimer->RunIfNotReady(iCyclePeriod);
287    }
288
289    if (iExpectedTimeout == 0)
290    {
291        iExpectedTimeout = (OsclTickCount::TickCount() * iTickCountPeriod) + iCyclePeriod;
292    }
293}
294
295// Cancel a timer
296template<class Alloc>
297void OsclTimer<Alloc>::Cancel(int32 timerID, int32 param)
298{
299
300    if (iInCallback)
301    {
302        // add to list of timers
303        entry_type *entry = iEntryAllocator.ALLOCATE(1);
304        entry->iTimerID = timerID;
305        entry->iParam = param;
306
307        iEntriesWaitingToCancel.push_back(entry);
308        return;
309    }
310
311    // remove from list of timers
312    for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
313    {
314        if ((*it)->iTimerID == timerID)
315        {
316            // make sure the param matches unless it is not specified (-1)
317            if ((*it)->iParam == param || param == -1)
318            {
319                iEntryAllocator.deallocate(*it);
320                iEntries.erase(it);
321                return;
322            }
323        }
324    }
325}
326
327// Clear all waiting timers
328template<class Alloc>
329void OsclTimer<Alloc>::Clear()
330{
331    for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
332    {
333        iEntryAllocator.deallocate(*it);
334    }
335    iEntries.clear();
336}
337
338template<class Alloc>
339void OsclTimer<Alloc>::TimerBaseElapsed()
340{
341    uint8 expiredFound = 0;
342
343    {
344        // call all whose timers have expired
345        for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
346        {
347            entry_type *entry = (*it);
348            if (--(entry->iCounter) <= 0)
349            {
350                if (!entry->iRecurring) expiredFound = 1;
351                if (entry->iRecurring) entry->iCounter = entry->iOrigCounter;
352
353                // use local observer if it exists, otherwise use global observer
354                OsclTimerObserver *obs = (entry->iObserver ? entry->iObserver : iObserver);
355                if (obs)
356                {
357                    iInCallback = true;
358                    obs->TimeoutOccurred(entry->iTimerID, entry->iParam);
359                    iInCallback = false;
360                }
361            }
362        }
363    }
364
365    // remove from list all whose timers have expired
366    while (expiredFound)
367    {
368        expiredFound = 0;
369        for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
370        {
371            entry_type *entry = (*it);
372            if (entry->iCounter <= 0)
373            {
374                expiredFound = 1;
375                iEntryAllocator.deallocate(entry);
376                iEntries.erase(it);
377                break;
378            }
379        }
380    }
381
382    {
383        // if any timers were cancelled in the callback, process them now
384        for (entries_type_iterator it = iEntriesWaitingToCancel.begin(); it != iEntriesWaitingToCancel.end(); it++)
385        {
386            entry_type *entry = (*it);
387            Cancel(entry->iTimerID, entry->iParam);
388            iEntryAllocator.deallocate(entry);
389        }
390        iEntriesWaitingToCancel.clear();
391    }
392
393    {
394        // if any timers were requested in the callback, process them now
395        for (entries_type_iterator it = iEntriesWaitingToAdd.begin(); it != iEntriesWaitingToAdd.end(); it++)
396        {
397            entry_type *entry = (*it);
398            Request(entry->iTimerID, entry->iParam, entry->iCounter, entry->iObserver);
399            iEntryAllocator.deallocate(entry);
400        }
401        iEntriesWaitingToAdd.clear();
402    }
403
404    if (!iEntries.empty())
405    {
406        // adjust for the jitter
407        uint32 time = OsclTickCount::TickCount() * iTickCountPeriod;
408        int32 jitter = time - iExpectedTimeout;
409        int32 waitperiod = iCyclePeriod - jitter;
410
411        // currently there is some problem on the phone if we send
412        // in real-time rather than with a slower (growing delay) H.223 mux output
413        // if jitter is too large in either direction, start over
414        if ((uint)OSCL_ABS(jitter) > iCyclePeriod)
415        {
416            iExpectedTimeout = time;
417        }
418        else
419        {
420            iExpectedTimeout += iCyclePeriod;
421        }
422
423        waitperiod = OSCL_MAX(waitperiod, 0);
424
425        if (iTimer)
426        {
427            iTimer->RunIfNotReady(waitperiod);
428        }
429    }
430    else
431    {
432        iExpectedTimeout = 0;
433    }
434}
435
436
437
438#endif
439