📄 rvtimestamp.c
字号:
/***********************************************************************
Filename : rvtimestamp.c
Description: high resoulution timestamp functions
************************************************************************
Copyright (c) 2001 RADVISION Inc. and RADVISION Ltd.
************************************************************************
NOTICE:
This document contains information that is confidential and proprietary
to RADVISION Inc. and RADVISION Ltd.. No part of this document may be
reproduced in any form whatsoever without written prior approval by
RADVISION Inc. or RADVISION Ltd..
RADVISION Inc. and RADVISION Ltd. reserve the right to revise this
publication and make changes without obligation to notify any person of
such revisions or changes.
***********************************************************************/
#include "rvtimestamp.h"
#include "rvstdio.h"
/* Required OS Specific headers files */
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_LINUX)
#include <string.h>
#include <stdio.h>
#include <asm/timex.h>
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_EMBLINUX)
#include <sys/time.h>
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_UNIXWARE)
#include <sys/time.h>
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_NORMAL) || (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_TIMESTAMP)
#include <vxWorks.h>
#include <sysLib.h>
#include <tickLib.h>
#include <limits.h>
#include <wdLib.h>
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_PSOS)
#include <psos.h>
#include <limits.h>
#include <psoscfg.h>
extern pSOS_CT PsosCfg; /* pSOS config table declared by pRISM+ */
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_OSE)
#include <ose.h>
#include <limits.h>
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_NUCLEUS)
#include <nucleus.h>
#include <target.h>
#include <limits.h>
#endif
/* OS specific declarations and variables */
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_WIN32) || (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_LINUX)
static RvInt64 RvTickHz; /* Clock frequency (cycles/second) - set by Init */
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_POSIX)
static RvInt64 RvStartingTime; /* Starting time we're using */
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_NORMAL)
static int RvTimeCheckWrap(int param); /* Wrap check function declaration */
static RvInt64 RvTickHz; /* Clock frequency (cycles/second) - set by Init */
static volatile RvInt32 RvWrapCount; /* how many times the hires counter has wrapped */
static volatile RvUint32 RvLastTick; /* Last clock tick value read checking for wrap */
#define WRAP_TICKS RV_UINT32_MAX /* How many clock ticks per wrap */
static WDOG_ID RvWrapTimer; /* Watchdog timer that will call wrap check */
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_TIMESTAMP)
static int RvTimeCheckWrap(int param); /* Wrap check function declaration */
static RvInt64 RvTickHz; /* Clock frequency (cycles/second) - set by Init */
static volatile RvInt64 RvHiresCount; /* total timer count as of last wrap */
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_PSOS)
static RvInt64 RvTickHz; /* Clock frequency (cycles/second) - set by Init */
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_OSE)
static RvInt64 RvTickPeriod; /* clock tick rate in nanoseconds */
static volatile RvInt32 RvWrapCount; /* how many times the hires counter has wrapped */
static volatile OSTICK RvLastTick; /* Last clock tick value read checking for wrap */
#define WRAP_TICKS RV_UINT32_MAX /* How many clock ticks per wrap */
#define WRAP_MS_MAX (WRAP_TICKS/2 - 1) /* Safe maximum milliseconds to delay between checks */
static OSTIME RvWrapcheckMs; /* Number of milliseconds to delay between wrap checking */
static PROCESS RvWrapTimer; /* Background process that will call wrap check */
static PROCESS RvWrapCheck; /* Interrupt process that will do the wrap check */
OSENTRYPOINT RvTimeCheckWrap; /* Wrap check function declaration (interrupt) */
OSENTRYPOINT RvTimeCheckWait; /* Check wait function declaration (background) */
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_NUCLEUS)
static RvInt64 RvTickHz; /* Clock frequency (cycles/second) - set by Init */
static volatile RvInt32 RvWrapCount; /* how many times the hires counter has wrapped */
static volatile UNSIGNED RvLastTick; /* Last clock tick value read checking for wrap */
#define WRAP_TICKS RV_UINT32_MAX /* How many clock ticks per wrap */
static NU_TIMER RvWrapTimer; /* Timer that will call wrap check */
static VOID RvTimeCheckWrap(UNSIGNED param); /* Wrap check function declaration */
#elif (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_USER_DEFINED)
/* Call user defined functions to allow attachment to hardware timer */
static void RvTimeCheckWrap(void); /* function called when counter wraps */
static RvInt64 RvTickHz; /* Clock frequency (cycles/second) - set by Init */
static volatile RvInt64 RvHiresCount; /* total timer count as of last wrap */
/* Functions user must define and link to. */
extern RvInt64 RvUserTimestampFreq(void); /* returns # of ticks per second of timer. */
extern void RvUserTimestampConnect(void (*)(void)); /* Set function to be called when timer wraps. */
extern void RvUserTimestampEnable(void); /* Activates timer. */
extern void RvUserTimestampDisable(void); /* Deactivates timer. */
extern RvInt64 RvUserTimestampPeriod(void); /* Retuns number of ticks it takes for timer to wrap. */
extern RvInt64 RvUserTimestampGet(void); /* Gets the current value of the timer. */
#endif
/* Lets make error codes a little easier to type */
#define RvTimestampErrorCode(_e) RvErrorCode(RV_ERROR_LIBCODE_CCORE, RV_CCORE_MODULE_TIMESTAMP, (_e))
/* Initialize stuff needed for some OS's to save time. Must */
/* be called and completed before any other calls are made. */
RvStatus RvTimestampInit(void)
{
RvStatus result;
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_LINUX)
FILE *cpuinfo;
char linebuf[132], *cptr1, *cptr2;
RvBool has_tsc, found_mhz;
long scale, temp;
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_POSIX)
struct timespec tp;
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_WIN32)
LARGE_INTEGER Frequency;
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_NORMAL)
int wrapcheck_time;
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_OSE)
OSTIME systick;
unsigned long wrapcheck_time;
RvUint64 wrapcheck_us;
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_NUCLEUS)
UNSIGNED wrapcheck_time;
#endif
result = RV_OK;
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_LINUX)
/* The only way to find out if the high performance timer (tsc) */
/* is present and it's frequency is to read it from the file */
/* /proc/cpuinfo which is generated by the kernel at boot time. */
has_tsc = RV_FALSE; /* mark when we have found if tsc is present */
found_mhz = RV_FALSE; /* mark when we have found and set the cpu speed */
RvTickHz = RvInt64Const(100000000); /* just to prevent accidental divide by zero */
cpuinfo = fopen("/proc/cpuinfo", "r");
if(cpuinfo == NULL)
return RvTimestampErrorCode(RV_TIMESTAMP_ERROR_NOCPUINFO);
while(fgets(linebuf, sizeof(linebuf), cpuinfo) != NULL) {
/* check for MHz line which will give clock (and tsc) speed */
if(strncmp(linebuf, "cpu MHz", 7) == 0) {
/* line contains cpu speed info, parse it into RvTickHz */
cptr1 = strchr(linebuf, ':'); /* find start of data field */
if (cptr1 != NULL) {
cptr1++; /* skip ":" seperator */
cptr2= strchr(cptr1, '.'); /* find decimal point */
if(cptr2 != NULL) { /* it had better be there */
*cptr2 = '\0'; /* split number into parts */
cptr2++; /* move to start of decimal */
temp = strtol(cptr1, NULL, 0); /* read whole number */
if(temp > 0) { /* sanity check */
RvTickHz = RvInt64Const(1000000) * (RvInt64)temp;
/* now add variable lengh fraction amount */
scale = 100000L; /* scale of next digit */
while((scale > 0L) && (isdigit(*cptr2) != 0)) {
temp = (long)(*cptr2 - '0');
RvTickHz += (RvInt64)(temp * scale);
scale = scale / 10L;
cptr2++;
}
found_mhz = RV_TRUE;
}
}
}
} /* end of cpu MHz check/parse */
/* check for "flags" line which lists tsc if it is present */
if(strncmp(linebuf, "flags", 5) == 0) {
cptr1 = strchr(linebuf, ':'); /* find start of data field */
if (cptr1 != NULL) {
cptr2 = strstr(cptr1, " tsc"); /* see if tsc is there */
if(cptr2 != NULL) has_tsc = RV_TRUE;
}
}
} /* end of file read loop */
fclose(cpuinfo);
if(has_tsc == RV_FALSE)
result = RvTimestampErrorCode(RV_TIMESTAMP_ERROR_NOTSC);
if(found_mhz == RV_FALSE)
result = RvTimestampErrorCode(RV_TIMESTAMP_ERROR_NOMHZ);
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_POSIX)
clock_gettime(CLOCK_REALTIME, &tp);
RvStartingTime = tp.tv_sec;
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_WIN32)
if(QueryPerformanceFrequency(&Frequency) == 0) {
RvTickHz = RvInt64Const(100000000); /* just to prevent accidental divide by zero */
result = RvTimestampErrorCode(RV_TIMESTAMP_ERROR_ZEROSPEED);
} else RvTickHz = (RvInt64)Frequency.QuadPart;
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_TIMESTAMP)
RvHiresCount = RvInt64Const(0);
RvTickHz = (RvInt64)sysTimestampFreq();
if(RvTickHz > RvInt64Const(0)) {
sysTimestampConnect(RvTimeCheckWrap, 0);
sysTimestampEnable(); /* start and reset timestamp timer */
} else {
RvTickHz = RvInt64Const(100); /* just to prevent accidental divide by zero */
result = RvTimestampErrorCode(RV_TIMESTAMP_ERROR_ZEROSPEED);
}
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_NORMAL)
RvWrapCount = 0;
RvLastTick = tickGet();
RvTickHz = (RvInt64)sysClkRateGet();
if(RvTickHz > RvInt64Const(0)) {
RvWrapTimer = wdCreate();
wrapcheck_time = WRAP_TICKS / 4 + WRAP_TICKS / 8;
wdStart(RvWrapTimer, wrapcheck_time, RvTimeCheckWrap, wrapcheck_time);
} else {
RvTickHz = RvInt64Const(100); /* just to prevent accidental divide by zero */
result = RvTimestampErrorCode(RV_TIMESTAMP_ERROR_ZEROSPEED);
}
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_PSOS)
RvTickHz = (RvInt64)PsosCfg.kc_ticks2sec;
if(RvTickHz <= RvInt64Const(0)) {
RvTickHz = RvInt64Const(100); /* just to prevent accidental divide by zero */
result = RvTimestampErrorCode(RV_TIMESTAMP_ERROR_ZEROSPEED);
}
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_OSE)
RvWrapCount = 0;
RvLastTick = get_systime(NULL);
systick = system_tick();
RvTickPeriod = (RvInt64)systick * 1000LL;
if(RvTickPeriod > RvInt64Const(0)) {
wrapcheck_time = WRAP_TICKS / 4 + WRAP_TICKS / 8; /* time in ticks */
wrapcheck_us = (RvUint64)wrapcheck_time * (RvUint64)systick; /* time in microsec */
if(wrapcheck_us >=((RvUint64)WRAP_MS_MAX * RvUint64Const(1000))) {
RvWrapcheckMs = WRAP_MS_MAX; /* delays are in ms and we don't want to chance wrapping that */
} else RvWrapcheckMs = (OSTIME)(wrapcheck_us / RvUint64Const(1000));
RvWrapCheck = create_process(OS_INT_PROC, "Timecheck", RvTimeCheckWrap, 200, 0, 0, 0, NULL, (OSVECTOR)(-1), 0);
RvWrapTimer = create_process(OS_BG_PROC, "Timewrap", RvTimeCheckWait, 200, 0, 0, 0, NULL, (OSVECTOR)(-1), 0);
start(RvWrapTimer);
} else {
RvTickPeriod = RvInt64Const(1000000);
result = RvTimestampErrorCode(RV_TIMESTAMP_ERROR_ZEROSPEED);
}
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_NUCLEUS)
RvWrapCount = 0;
RvLastTick = NU_Retrieve_Clock();
RvTickHz = (RvInt64)TICKS_PER_SECOND;
if(RvTickHz > RvInt64Const(0)) {
wrapcheck_time = WRAP_TICKS / 4 + WRAP_TICKS / 8;
NU_Create_Timer(&RvWrapTimer, "Timewrap", RvTimeCheckWrap, wrapcheck_time, wrapcheck_time, wrapcheck_time, NU_ENABLE_TIMER);
} else {
RvTickHz = RvInt64Const(100); /* just to prevent accidental divide by zero */
result = RvTimestampErrorCode(RV_TIMESTAMP_ERROR_ZEROSPEED);
}
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_USER_DEFINED)
RvHiresCount = RvInt64Const(0);
RvTickHz = (RvInt64)RvUserTimestampFreq();
if(RvTickHz > RvInt64Const(0)) {
RvUserTimestampConnect(RvTimeCheckWrap);
RvUserTimestampEnable(); /* start and reset timestamp timer */
} else {
RvTickHz = RvInt64Const(100); /* just to prevent accidental divide by zero */
result = RvTimestampErrorCode(RV_TIMESTAMP_ERROR_ZEROSPEED);
}
#endif
return result;
}
/* Have to stop wrap check on systems that require it */
RvStatus RvTimestampEnd(void)
{
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_TIMESTAMP)
sysTimestampDisable();
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_NORMAL)
wdCancel(RvWrapTimer);
wdDelete(RvWrapTimer);
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_OSE)
stop(RvWrapTimer);
kill_proc(RvWrapTimer);
kill_proc(RvWrapCheck);
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_NUCLEUS)
NU_Control_Timer(&RvWrapTimer, NU_DISABLE_TIMER);
NU_Delete_Timer(&RvWrapTimer);
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_USER_DEFINED)
RvUserTimestampDisable();
#endif
return RV_OK;
}
/* ****** RvTimeCheckWrap() *******/
/* On any OS where the hires counter may wrap, periodically */
/* Check and track the number of wraps. This must be called */
/* from and ISR or task that can't be pre-empted by anything */
/* that might get a high resolution timestamp. */
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_TIMESTAMP)
/* Called for us by timestamp driver when wrap occurs */
static int RvTimeCheckWrap(int param)
{
RvHiresCount += (RvInt64)sysTimestampPeriod();
return 0;
}
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_VXWORKS_NORMAL)
/* Called as watchdog routine periodically */
static int RvTimeCheckWrap(int param)
{
ULONG cur_tick;
cur_tick = tickGet();
if(cur_tick < RvLastTick)
RvWrapCount += 1;
RvLastTick = cur_tick;
wdStart(RvWrapTimer, param, RvTimeCheckWrap, param);
return 0;
}
#endif
#if (RV_TIMESTAMP_TYPE == RV_TIMESTAMP_OSE)
/* This is horrible but OSE gives us no other choice */
/* Do the actual check in interrupt process, not tied to any */
/* hardware, which gets signaled by the background process. */
/* This insures that the check and update are not interrupted. */
/* It requires including ose_i.h instead of ose.h but that would */
/* require a seperate file. Since we only call get_systime */
/* it doesn't hurt anything. */
OS_PROCESS(RvTimeCheckWrap)
{
OSTICK cur_tick;
cur_tick = get_systime(NULL);
if(cur_tick < RvLastTick)
RvWrapCount += 1;
RvLastTick = cur_tick;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -