Browse Source

Version 1.0.0

Rind 8 years ago
parent
commit
2d9355bdf8

BIN
build/Toolchain/arm/libgfatimer.so.1.0.0


BIN
build/Toolchain/arm/libgfatimerd.so.1.0.0


+ 17 - 2
build/Toolchain/gfatimer.h

@@ -16,13 +16,16 @@ typedef enum GfaTimerResolution
 	GTR_Invalid,
 	GTR_10ms,
 	GTR_25ms,
-	GTR_50ms
+	GTR_50ms,
+	GTR_Last
+	
 }GfaTimerResolution;
 
 /////////////////////////////////////////////////////////////////////////////
 
 typedef enum GfaTimerClockPulse
 {
+	GTCP_Invalid = -1,
 	GTCP_250ms,
 	GTCP_500ms,
 	GTCP_750ms,
@@ -30,9 +33,15 @@ typedef enum GfaTimerClockPulse
 	GTCP_1500ms,
 	GTCP_2000ms,
 	GTCP_5000ms,
-	GTCP_10000ms
+	GTCP_10000ms,
+	GTCP_Last
 }GfaTimerClockPulse;
 
+/////////////////////////////////////////////////////////////////////////////
+
+typedef void (*pfnTIMERCALLBACK)(int, void*);
+typedef void (*pfnPULSECALLBACK)(GfaTimerClockPulse, int, void*);
+
 /////////////////////////////////////////////////////////////////////////////
 // initialization (if GfaTimerRelease is not called explicitly, clean up will
 // be done internally, if the process exits gracefully)
@@ -40,6 +49,12 @@ typedef enum GfaTimerClockPulse
 int				GfaTimerInit(int nTimerCount, GfaTimerResolution res);
 void			GfaTimerRelease(void);
 
+void			GfaRegisterTimerCallback(int tnum, pfnTIMERCALLBACK pfnCallback, void *pContext);
+void			GfaUnregisterTimerCallback(int tnum);
+
+void			GfaRegisterClockPulseCallback(GfaTimerClockPulse cp, pfnPULSECALLBACK pfnCallback, void *pContext);
+void			GfaUnregisterClockPulseCallback(GfaTimerClockPulse cp);
+
 /////////////////////////////////////////////////////////////////////////////
 // mondial legacy timer API
 

BIN
build/Toolchain/x86_64/libgfatimer.so.1.0.0


BIN
build/Toolchain/x86_64/libgfatimerd.so.1.0.0


BIN
demo/arm/demo


BIN
demo/arm/demod


+ 140 - 34
demo/main.c

@@ -5,75 +5,181 @@
 #include <string.h>
 #include <gfatimer.h>
 
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct _T_PARAMS
+{
+	unsigned long nTriggers;
+	struct timespec *ptsStart;
+}T_PARAMS, *PT_PARAMS;
+
 #define _NANOSECS_PER_SEC					1000000000
 
+static const int g_cpt[GTCP_Last] = {250, 500, 750, 1000, 1500, 2000, 5000, 10000};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
 static long long _TimeSpecDiffNs(const struct timespec *pts1, const struct timespec *pts2)
 {
 	long long ns1 = (long long)pts1->tv_sec * _NANOSECS_PER_SEC + pts1->tv_nsec;
 	long long ns2 = (long long)pts2->tv_sec * _NANOSECS_PER_SEC + pts2->tv_nsec;
-	return ns2 - ns1;
+	return (ns2 - ns1);
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+// callback are always called in the thread context of the timer thread!
+
+static void _TimerCallback(int tnum, void *pContext)
+{
+	struct timespec tsCur;
+	PT_PARAMS ptp = (PT_PARAMS)pContext;
+	clock_gettime(CLOCK_MONOTONIC, &tsCur);
+	long long elps = _TimeSpecDiffNs(ptp->ptsStart, &tsCur) / 1000000;
+	ptp->nTriggers++;
+
+	printf("Timer[%d] triggerd (%lu) at: %lld ms.\n", tnum, ptp->nTriggers, elps);
+
+	if(ptp->nTriggers < 4)
+		tw_set(tnum,  1000 * ptp->nTriggers); // restrigger timer
+	else
+	{
+		printf("Timer[%d] released!\n", tnum);
+		GfaUnregisterTimerCallback(tnum);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// callback are always called in the thread context of the timer thread!
+
+static void _ClockPulseCallback(GfaTimerClockPulse cp, int state, void *pContext)
+{
+	struct timespec tsCur;
+	PT_PARAMS ptp = (PT_PARAMS)pContext;
+	clock_gettime(CLOCK_MONOTONIC, &tsCur);
+	long long elps = _TimeSpecDiffNs(ptp->ptsStart, &tsCur) / 1000000;
+	
+	switch(cp)
+	{
+	case GTCP_250ms:
+		ptp->nTriggers++;
+		printf("Clock pulse[%dms] triggerd (%s) at: %lld ms.\n", g_cpt[cp], state ? "+" : "-", elps);
+		break;
+	case GTCP_500ms:
+		ptp->nTriggers++;
+		printf("Clock pulse[%dms] triggerd (%s) at: %lld ms.\n", g_cpt[cp], state ? "+" : "-", elps);
+		break;
+	case GTCP_750ms:
+		ptp->nTriggers++;
+		printf("Clock pulse[%dms] triggerd (%s) at: %lld ms.\n", g_cpt[cp], state ? "+" : "-", elps);
+		break;
+	case GTCP_1000ms:
+		ptp->nTriggers++;
+		printf("Clock pulse[%dms] triggerd (%s) at: %lld ms.\n", g_cpt[cp], state ? "+" : "-", elps);
+		break;
+	case GTCP_1500ms:
+		ptp->nTriggers++;
+		printf("Clock pulse[%dms] triggerd (%s) at: %lld ms.\n", g_cpt[cp], state ? "+" : "-", elps);
+		break;
+	case GTCP_2000ms:
+		ptp->nTriggers++;
+		printf("Clock pulse[%dms] triggerd (%s) at: %lld ms.\n", g_cpt[cp], state ? "+" : "-", elps);
+		break;
+	case GTCP_5000ms:
+		ptp->nTriggers++;
+		printf("Clock pulse[%dms] triggerd (%s) at: %lld ms.\n", g_cpt[cp], state ? "+" : "-", elps);
+		break;
+	case GTCP_10000ms:
+		ptp->nTriggers++;
+		printf("Clock pulse[%dms] triggerd (%s) at: %lld ms.\n", g_cpt[cp], state ? "+" : "-", elps);
+		break;
+	default:
+		printf("Clock pulse %d invalid!\n", cp);
+		break;
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
 int main(int argc, char **argv)
 {
-	long long elps1, elps2;
-	int tnum1 = 3, tnum2 = 14, nPulse, nOldPulse = 0;
-	unsigned long tw1 = 1, tw2 = 1;
-	struct timespec tsRes, tsStart, tsEnd1, tsEnd2;
-	memset(&tsEnd1, 0, sizeof(tsEnd1));
-	memset(&tsEnd2, 0, sizeof(tsEnd2));
-
-	if(!GfaTimerInit(32, GTR_25ms))
+	T_PARAMS tp1, tp2, tp3;
+	long long elps;
+	int tnum1 = 0, tnum2 = 2, nPulse, nOldPulse = 0;
+	unsigned long tw = 1;
+	struct timespec tsStart, tsCur, tsEnd;
+
+	memset(&tsCur, 0, sizeof(tsCur));
+	memset(&tsEnd, 0, sizeof(tsEnd));
+	clock_gettime(CLOCK_MONOTONIC, &tsStart);
+
+	/////////////////////////////////////////////////////////////////////////////////////
+
+	if(!GfaTimerInit(32, GTR_50ms))
 	{
 		printf("GfaTimerInit failed!\n");
 		return 1;
 	}
 
+	/////////////////////////////////////////////////////////////////////////////////////
+
+	tp1.nTriggers = 0;
+	tp1.ptsStart = &tsStart;
+	GfaRegisterTimerCallback(tnum2, _TimerCallback, &tp1);
+
+	tp2.nTriggers = 0;
+	tp2.ptsStart = &tsStart;
+	GfaRegisterClockPulseCallback(GTCP_500ms, _ClockPulseCallback, &tp2);
+
+	tp3.nTriggers = 0;
+	tp3.ptsStart = &tsStart;
+	GfaRegisterClockPulseCallback(GTCP_1500ms, _ClockPulseCallback, &tp3);
+
+	/////////////////////////////////////////////////////////////////////////////////////
+
 	tf_set(tnum1);
 	tf_set(tnum2);
-	tw_set(tnum1, 15000);
-	tw_set(tnum2, 10000);
 
-	clock_gettime(CLOCK_MONOTONIC, &tsStart);
+	tw_set(tnum1, 20000);
+	tw_set(tnum2,   500);
 
+	/////////////////////////////////////////////////////////////////////////////////////
+	/////////////////////////////////////////////////////////////////////////////////////
+	
 	do
 	{
 		nPulse = cp_test(GTCP_750ms);
 
 		if(nOldPulse != nPulse)
 		{
+			clock_gettime(CLOCK_MONOTONIC, &tsCur);
+			elps = _TimeSpecDiffNs(&tsStart, &tsCur);
+			printf("    Clock pulse[%dms] polled (%s) at: %lld ms.\n", g_cpt[GTCP_750ms], nPulse ? "+" : "-", elps / 1000000);
 			nOldPulse = nPulse;
-			printf("Pulse 750ms %d\n", nPulse);
-		}
-
-		if(tw1)
-		{
-			if(!(tw1 = tw_read(tnum1)))
-			{
-				clock_gettime(CLOCK_MONOTONIC, &tsEnd1);
-				printf("T%d expired.\n", tnum1);
-			}
 		}
 
-		if(tw2)
+		if(tw && !(tw = tw_read(tnum1)))
 		{
-			if(!(tw2 = tw_read(tnum2)))
-			{
-				clock_gettime(CLOCK_MONOTONIC, &tsEnd2);
-				printf("T%d expired.\n", tnum2);
-			}
+			clock_gettime(CLOCK_MONOTONIC, &tsEnd);
+			printf("    Timer[%d] (polled) expired.\n", tnum1);
 		}
+		
+		// do work ...
 
 		usleep(25000);
-//		printf("T%d: %3lu, T%d: %3lu\n", tnum1, tw1, tnum2, tw2);
 	}
-	while(tw1 || tw2);
+	while(tw);
 
-	elps1 = _TimeSpecDiffNs(&tsStart, &tsEnd1);
-	elps2 = _TimeSpecDiffNs(&tsStart, &tsEnd2);
+	GfaUnregisterTimerCallback(tnum2);
+	GfaUnregisterClockPulseCallback(GTCP_500ms);
+	GfaUnregisterClockPulseCallback(GTCP_1500ms);
+	
+	GfaTimerRelease();
 
-	printf("\nT%d effective: %lld ms.\n", tnum1, elps1 / 1000000);
-	printf("T%d effective: %lld ms.\n", tnum2, elps2 / 1000000);
+	/////////////////////////////////////////////////////////////////////////////////////
 
+	elps = _TimeSpecDiffNs(&tsStart, &tsEnd);
+	printf("\nTimer[%d] (polled) - effective measured time: %lld ms.\n\n", tnum1, elps / 1000000);
 	return 0;
 }

BIN
demo/x86_64/demo


BIN
demo/x86_64/demod


+ 20 - 0
src/gfatimer.cpp

@@ -13,6 +13,26 @@ void GfaTimerRelease(void)
 	g_gfaTimer.Release();
 }
 
+void GfaRegisterTimerCallback(int tnum, pfnTIMERCALLBACK pfnCallback, void *pContext)
+{
+	g_gfaTimer.RegisterTimerCallback(tnum, pfnCallback, pContext);
+}
+
+void GfaRegisterClockPulseCallback(GfaTimerClockPulse cp, pfnPULSECALLBACK pfnCallback, void *pContext)
+{
+	g_gfaTimer.RegisterClockPulseCallback(cp, pfnCallback, pContext);
+}
+
+void GfaUnregisterTimerCallback(int tnum)
+{
+	g_gfaTimer.RegisterTimerCallback(tnum, NULL, NULL);
+}
+
+void GfaUnregisterClockPulseCallback(GfaTimerClockPulse cp)
+{
+	g_gfaTimer.RegisterClockPulseCallback(cp, NULL, NULL);
+}
+
 int tf_test(int tnum)
 {
 	return g_gfaTimer.tf_test(tnum);

+ 17 - 2
src/gfatimer.h

@@ -16,13 +16,16 @@ typedef enum GfaTimerResolution
 	GTR_Invalid,
 	GTR_10ms,
 	GTR_25ms,
-	GTR_50ms
+	GTR_50ms,
+	GTR_Last
+	
 }GfaTimerResolution;
 
 /////////////////////////////////////////////////////////////////////////////
 
 typedef enum GfaTimerClockPulse
 {
+	GTCP_Invalid = -1,
 	GTCP_250ms,
 	GTCP_500ms,
 	GTCP_750ms,
@@ -30,9 +33,15 @@ typedef enum GfaTimerClockPulse
 	GTCP_1500ms,
 	GTCP_2000ms,
 	GTCP_5000ms,
-	GTCP_10000ms
+	GTCP_10000ms,
+	GTCP_Last
 }GfaTimerClockPulse;
 
+/////////////////////////////////////////////////////////////////////////////
+
+typedef void (*pfnTIMERCALLBACK)(int, void*);
+typedef void (*pfnPULSECALLBACK)(GfaTimerClockPulse, int, void*);
+
 /////////////////////////////////////////////////////////////////////////////
 // initialization (if GfaTimerRelease is not called explicitly, clean up will
 // be done internally, if the process exits gracefully)
@@ -40,6 +49,12 @@ typedef enum GfaTimerClockPulse
 int				GfaTimerInit(int nTimerCount, GfaTimerResolution res);
 void			GfaTimerRelease(void);
 
+void			GfaRegisterTimerCallback(int tnum, pfnTIMERCALLBACK pfnCallback, void *pContext);
+void			GfaUnregisterTimerCallback(int tnum);
+
+void			GfaRegisterClockPulseCallback(GfaTimerClockPulse cp, pfnPULSECALLBACK pfnCallback, void *pContext);
+void			GfaUnregisterClockPulseCallback(GfaTimerClockPulse cp);
+
 /////////////////////////////////////////////////////////////////////////////
 // mondial legacy timer API
 

+ 127 - 11
src/timer.cpp

@@ -25,15 +25,16 @@
 
 /////////////////////////////////////////////////////////////////////////////
 
-const int CGfaTimer::m_nPulseFreq[] = {250, 500, 750, 1000, 1500, 2000, 5000, 10000};
+const int CGfaTimer::m_nPulseFreq[GTCP_Last] = {250, 500, 750, 1000, 1500, 2000, 5000, 10000};
 
 /////////////////////////////////////////////////////////////////////////////
 
 CGfaTimer::CGfaTimer(void) : m_pTimer(NULL), m_nTimerCount(0), m_nTimerIncrement(0), m_nClockCount(0), m_nClockPulse(0), m_threadID(_INVALID_THREAD_ID), m_bProcessTimers(false)
 {
 	memset(&m_timInterval, 0, sizeof(m_timInterval));
+	memset(m_ClkPulseCallbackTable, 0, sizeof(m_ClkPulseCallbackTable));
 
-	if(!m_mutex.Create())
+	if(!m_mutex.Create(true))
 	{
 		TRACE("CGfaTimer::CGfaTimer: failed to create mutex!\n");
 		throw -1;
@@ -110,22 +111,77 @@ void CGfaTimer::Release(void)
 {
 	if(m_pTimer)
 	{
+		m_mutex.Lock();
 		if(m_threadID != _INVALID_THREAD_ID)
 		{
 			m_bProcessTimers = false;
+			m_mutex.Unlock();
 			::pthread_join(m_threadID, NULL);
+			m_mutex.Lock();
 			m_threadID = _INVALID_THREAD_ID;
 		}
 
 		m_nTimerCount = m_nTimerIncrement = m_nClockCount = m_nClockPulse = 0;
 		delete [] m_pTimer;
 		m_pTimer = NULL;
+		m_mutex.Unlock();
 		TRACE("CGfaTimer::Release: Timer released.\n");
 	}
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
+void CGfaTimer::RegisterTimerCallback(int tnum, pfnTIMERCALLBACK pfnCallback, void *pContext)
+{
+	_VALIDATE_TIMER_VOID(tnum);
+	if(pfnCallback)
+	{
+		m_mutex.Lock();
+	    m_pTimer[tnum].pfnCallback		= pfnCallback;
+    	m_pTimer[tnum].pContext			= pContext;
+    	m_pTimer[tnum].bCallScheduled	= false;
+		m_mutex.Unlock();
+		TRACE("CGfaTimer::RegisterTimerCallback: Timer %d - callback: %p, context: %p.\n", tnum, pfnCallback, pContext);
+    }
+    else
+	{
+		m_mutex.Lock();
+	    m_pTimer[tnum].pfnCallback		= NULL;
+    	m_pTimer[tnum].pContext			= NULL;
+    	m_pTimer[tnum].bCallScheduled	= false;
+		m_mutex.Unlock();
+		TRACE("CGfaTimer::RegisterTimerCallback: Timer %d - Unregister callback.\n", tnum);
+	}
+}
+
+void CGfaTimer::RegisterClockPulseCallback(GfaTimerClockPulse cp, pfnPULSECALLBACK pfnCallback, void *pContext)
+{
+	if(cp <= GTCP_Invalid || cp >= GTCP_Last)
+	{
+		TRACE("CGfaTimer::RegisterClockPulseCallback: invalid clock pulse %d!\n", cp);
+		return;
+	}
+	
+	if(pfnCallback)
+	{
+		m_mutex.Lock();
+		m_ClkPulseCallbackTable[cp].pfnCallback	= pfnCallback;
+		m_ClkPulseCallbackTable[cp].pContext	= pContext;
+		m_mutex.Unlock();
+		TRACE("CGfaTimer::RegisterClockPulseCallback:  Clock pulse %dms: Register callback: %p, context: %p.\n", CGfaTimer::m_nPulseFreq[cp], pfnCallback, pContext);
+	}
+	else
+	{
+		m_mutex.Lock();
+		m_ClkPulseCallbackTable[cp].pfnCallback	= NULL;
+		m_ClkPulseCallbackTable[cp].pContext	= NULL;
+		m_mutex.Unlock();
+		TRACE("CGfaTimer::RegisterClockPulseCallback: Clock pulse %dms: Unregister callback.\n", CGfaTimer::m_nPulseFreq[cp]);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
 bool CGfaTimer::ValidateTimer(int tnum, const char *pszCaller)
 {
 	if(!m_pTimer)
@@ -218,7 +274,7 @@ void CGfaTimer::tw_set(int tnum, unsigned long val)
 
 int CGfaTimer::cp_test(GfaTimerClockPulse cp)
 {
-	if(cp >= GTCP_250ms && cp <= GTCP_10000ms)
+	if(cp > GTCP_Invalid && cp < GTCP_Last)
 	{
 		return !!(m_nClockPulse & (0x00000001 << cp));
 	}
@@ -248,8 +304,25 @@ void* CGfaTimer::LordOfTheTimers(void *pParam)
 
 	::clock_gettime(CLOCK_MONOTONIC, &tsDueTime);
 
+	/////////////////////////////////////////////////////////////////////////
+	// enter loop
+
 	do
 	{
+		/////////////////////////////////////////////////////////////////////
+
+		CGfaTimer::AddTimeSpecs(tsDueTime, pSelf->m_timInterval, tsDueTime);
+
+		if((nRet = ::clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tsDueTime, NULL)))
+		{
+			while(nRet && (errno == EINTR))
+			{
+				errno = 0;
+				nRet = ::clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tsDueTime, NULL);
+			}
+		}
+		/////////////////////////////////////////////////////////////////////
+
 		for(int i = 0; i < pSelf->m_nTimerCount; i++)
 		{
 			GFA_TIMER &rt = pSelf->m_pTimer[i];
@@ -257,18 +330,29 @@ void* CGfaTimer::LordOfTheTimers(void *pParam)
 			pSelf->m_mutex.Lock();
             if(rt.tf)
             {
-                if(rt.tw >= pSelf->m_nTimerIncrement)
+                if(rt.tw > pSelf->m_nTimerIncrement)
                 	rt.tw -= pSelf->m_nTimerIncrement;
                 else if(rt.tw)
+                {
                 	rt.tw = 0;
+                	if(rt.pfnCallback)
+                		rt.bCallScheduled = true;
+                }
             }
-            else
+            else if(rt.tw)
             {
                 rt.tw = 0;
             }
 			pSelf->m_mutex.Unlock();
 		}
 
+		/////////////////////////////////////////////////////////////////////
+		// process clock pulses
+
+		pSelf->m_mutex.Lock();
+		bool bDoCallbacks = false;
+		unsigned long nPrevClockPulse = pSelf->m_nClockPulse;
+		unsigned long nScheduled;
 		pSelf->m_nClockCount += pSelf->m_nTimerIncrement;
 
 		if(!(pSelf->m_nClockCount % CGfaTimer::m_nPulseFreq[0]))
@@ -276,7 +360,7 @@ void* CGfaTimer::LordOfTheTimers(void *pParam)
 			unsigned long nPulseMask = 1;
 			pSelf->m_nClockPulse ^= nPulseMask;
 
-			for(size_t i = 1; i < _COUNTOF(CGfaTimer::m_nPulseFreq); i++)
+			for(int i = 1; i < GTCP_Last; i++)
 			{
 				nPulseMask <<= 1;
 
@@ -285,18 +369,50 @@ void* CGfaTimer::LordOfTheTimers(void *pParam)
 					pSelf->m_nClockPulse ^= nPulseMask;
 				}
 			}
+
+			bDoCallbacks	= true;
+			nScheduled		= pSelf->m_nClockPulse ^ nPrevClockPulse;
 		}
 
-		CGfaTimer::AddTimeSpecs(tsDueTime, pSelf->m_timInterval, tsDueTime);
+		pSelf->m_mutex.Unlock();
 
-		if((nRet = ::clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tsDueTime, NULL)))
+		/////////////////////////////////////////////////////////////////////
+		// call clock pulse callbacks
+		
+		if(bDoCallbacks)
 		{
-			while(nRet && (errno == EINTR))
+			unsigned long nPulseMask	= 1;
+
+			for(int i = GTCP_250ms; i < GTCP_Last; i++, nPulseMask <<= 1)
 			{
-				errno = 0;
-				nRet = ::clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tsDueTime, NULL);
+				pSelf->m_mutex.Lock();
+				pfnPULSECALLBACK pfnCallback = pSelf->m_ClkPulseCallbackTable[i].pfnCallback;
+				void *pContext = pSelf->m_ClkPulseCallbackTable[i].pContext;
+				int nState = !!(pSelf->m_nClockPulse & nPulseMask);
+				pSelf->m_mutex.Unlock();
+				
+				if(pfnCallback && (nScheduled & nPulseMask))
+				{
+					(*pfnCallback)((GfaTimerClockPulse)i, nState, pContext);
+				}
 			}
 		}
+
+		/////////////////////////////////////////////////////////////////////
+		// process timer callbacks
+
+		for(int i = 0; i < pSelf->m_nTimerCount; i++)
+		{
+			GFA_TIMER &rt = pSelf->m_pTimer[i];
+
+			pSelf->m_mutex.Lock();
+            if(rt.pfnCallback && rt.tf && rt.bCallScheduled && !rt.tw)
+            {
+            	rt.bCallScheduled = false;
+				(*rt.pfnCallback)(i, rt.pContext);
+            }
+			pSelf->m_mutex.Unlock();
+		}
 	}
 	while(pSelf->m_bProcessTimers);
 

+ 14 - 2
src/timer.h

@@ -14,12 +14,21 @@
 
 typedef struct _GFA_TIMER
 {
-//    unsigned long tv;
-    unsigned long tw;
     int tf;
+    unsigned long tw;
+    pfnTIMERCALLBACK pfnCallback;
+    void *pContext;
+    bool bCallScheduled;
 }GFA_TIMER, *LPGFA_TIMER;
 typedef const GFA_TIMER *LPCGFA_TIMER;
 
+typedef struct _GFA_TIMER_PULSE_CALLBACK
+{
+    pfnPULSECALLBACK pfnCallback;
+    void *pContext;
+}GFA_TIMER_PULSE_CALLBACK, *LPGFA_TIMER_PULSE_CALLBACK;
+typedef const GFA_TIMER_PULSE_CALLBACK *LPCGFA_TIMER_PULSE_CALLBACK;
+
 /////////////////////////////////////////////////////////////////////////////
 
 class CGfaTimer
@@ -30,6 +39,8 @@ public:
 
 	int Initialize(int nTimerCount, GfaTimerResolution res);
 	void Release(void);
+	void RegisterTimerCallback(int tnum, pfnTIMERCALLBACK pfnCallback, void *pContext);
+	void RegisterClockPulseCallback(GfaTimerClockPulse cp, pfnPULSECALLBACK pfnCallback, void *pContext);
 
 	int tf_test(int tnum);
 	void tf_set(int tnum);
@@ -56,6 +67,7 @@ private:
     struct timespec m_timInterval;
     bool m_bProcessTimers;
     static const int m_nPulseFreq[];
+    GFA_TIMER_PULSE_CALLBACK m_ClkPulseCallbackTable[GTCP_Last];
 };
 
 /////////////////////////////////////////////////////////////////////////////