Preliminary general time changes.

This commit is contained in:
W. Eric Norum
2008-04-14 19:49:47 +00:00
parent fde879062d
commit 489af50c7a
7 changed files with 489 additions and 43 deletions

View File

@@ -0,0 +1,245 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* iocClock.c */
/* Author: Marty Kraimer Date: 16JUN2000 */
/* This file is originally named as iocClock.c and provide the NTP time
* as default time source if no other time source registered during initialization.
* Now we made some minor change to add this to the time provider list */
/* Sheng Peng @ SNS ORNL 07/2004 */
/* Version 1.1 */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <tickLib.h>
#include <sysLib.h>
#include <sntpcLib.h>
#include <time.h>
#include <errno.h>
#include "epicsTypes.h"
#include "cantProceed.h"
#include "errlog.h"
#include "epicsThread.h"
#include "epicsMutex.h"
#include "epicsTime.h"
#include "envDefs.h"
#define BILLION 1000000000
#define NTPTimeSyncInterval 10.0
#define NTPTIME_DRV_VERSION "NTPTime Driver Version 1.2"
#include "epicsGeneralTime.h"
static void NTPTimeSyncNTP(void);
static int NTPTimeGetCurrent(epicsTimeStamp *pDest);
long NTPTime_Report(int level);
typedef struct NTPTimePvt {
int synced; /* if never synced, we can't use it */
epicsMutexId lock;
epicsTimeStamp clock;
unsigned long lastTick;
epicsUInt32 nanosecondsPerTick;
int tickRate;
int ticksToSkip;
const char *pserverAddr;
}NTPTimePvt;
static NTPTimePvt *pNTPTimePvt = 0;
static int nConsecutiveBad = 0;
extern char* sysBootLine;
static void NTPTimeSyncNTP(void)
{
struct timespec Currtime;
epicsTimeStamp epicsTime;
int status;
int prevStatusBad = 0;
while(1) {
double diffTime;
epicsThreadSleep(NTPTimeSyncInterval);
pNTPTimePvt->tickRate = sysClkRateGet();
status = sntpcTimeGet((char *)pNTPTimePvt->pserverAddr,
pNTPTimePvt->tickRate,&Currtime);
if(status) {
++nConsecutiveBad;
/*wait 1 minute before reporting failure*/
if(nConsecutiveBad<(60/NTPTimeSyncInterval)) continue;
if(!prevStatusBad)
errlogPrintf("NTPTimeSyncWithNTPserver: sntpcTimeGet %s\n",
strerror(errno));
prevStatusBad = 1;
pNTPTimePvt->synced = FALSE;
continue;
}
nConsecutiveBad=0;
if(prevStatusBad) {
errlogPrintf("NTPTimeSyncWithNTPserver: sntpcTimeGet OK\n");
prevStatusBad = 0;
}
epicsTimeFromTimespec(&epicsTime,&Currtime);
epicsMutexMustLock(pNTPTimePvt->lock);
diffTime = epicsTimeDiffInSeconds(&epicsTime,&pNTPTimePvt->clock);
if(diffTime>=0.0) {
pNTPTimePvt->clock = epicsTime;
pNTPTimePvt->ticksToSkip = 0;/* fix bug here */
} else {/*dont go back in time*/
pNTPTimePvt->ticksToSkip = (int) ((-1)*diffTime*pNTPTimePvt->tickRate);/* fix bug here */
}
pNTPTimePvt->lastTick = tickGet();
pNTPTimePvt->synced = TRUE;
epicsMutexUnlock(pNTPTimePvt->lock);
}
}
static long NTPTime_InitOnce(int priority)
{
int status;
struct timespec Currtime;
epicsTimeStamp epicsTime;
pNTPTimePvt = callocMustSucceed(1,sizeof(NTPTimePvt),"NTPTime_Init");
memset(pNTPTimePvt, 0, sizeof(NTPTimePvt));
pNTPTimePvt->synced = FALSE;
pNTPTimePvt->lock = epicsMutexCreate();
pNTPTimePvt->nanosecondsPerTick = BILLION/sysClkRateGet();
pNTPTimePvt->tickRate = sysClkRateGet();
/* look first for environment variable or CONFIG_SITE_ENV default */
pNTPTimePvt->pserverAddr = envGetConfigParamPtr(&EPICS_TS_NTP_INET);
if(!pNTPTimePvt->pserverAddr) { /* if neither, use the boot host */
BOOT_PARAMS bootParms;
static char host_addr[BOOT_ADDR_LEN];
bootStringToStruct(sysBootLine,&bootParms);
/* bootParms.had = host IP address */
strncpy(host_addr,bootParms.had,BOOT_ADDR_LEN);
pNTPTimePvt->pserverAddr = host_addr;
}
if(!pNTPTimePvt->pserverAddr) {
errlogPrintf("No NTP server is defined. Clock does not work\n");
return -1;
}
/* if TIMEZONE not defined, set it from EPICS_TIMEZONE */
if (getenv("TIMEZONE") == NULL) {
const char *timezone = envGetConfigParamPtr(&EPICS_TIMEZONE);
if(timezone == NULL) {
printf("NTPTime_Init: No Time Zone Information\n");
} else {
epicsEnvSet("TIMEZONE",timezone);
}
}
/* try to sync with NTP server once here */
pNTPTimePvt->tickRate = sysClkRateGet();
status = sntpcTimeGet((char *)pNTPTimePvt->pserverAddr,pNTPTimePvt->tickRate,&Currtime);
if(status)
{/* sync failed */
printf("First try to sync with NTP server failed!\n");
}
else
{/* sync OK */
epicsTimeFromTimespec(&epicsTime,&Currtime);
epicsMutexMustLock(pNTPTimePvt->lock);
pNTPTimePvt->clock = epicsTime;
pNTPTimePvt->lastTick = tickGet();
pNTPTimePvt->synced = TRUE;
epicsMutexUnlock(pNTPTimePvt->lock);
printf("First try to sync with NTP server succeed!\n");
}
epicsThreadCreate("NTPTimeSyncNTP",
epicsThreadPriorityHigh,
epicsThreadGetStackSize(epicsThreadStackSmall),
(EPICSTHREADFUNC)NTPTimeSyncNTP,0);
/* register to link list */
generalTimeCurrentTpRegister("NTP", priority, NTPTimeGetCurrent);
return 0;
}
struct InitInfo {
int priority;
long retval;
};
static void NTPTime_InitOnceWrapper(void *arg)
{
struct InitInfo *pargs = (struct InitInfo *)arg;
pargs->retval = NTPTime_InitOnce(pargs->priority);
}
long NTPTime_Init(int priority)
{
struct InitInfo args;
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
args.priority = priority;
epicsThreadOnce(&onceId, NTPTime_InitOnceWrapper, &args);
return args.retval;
}
static int NTPTimeGetCurrent(epicsTimeStamp *pDest)
{
unsigned long currentTick,nticks,nsecs;
if(!pNTPTimePvt->synced) return epicsTimeERROR;
epicsMutexMustLock(pNTPTimePvt->lock);
currentTick = tickGet();
while(currentTick!=pNTPTimePvt->lastTick) {
nticks = (currentTick>pNTPTimePvt->lastTick)
? (currentTick - pNTPTimePvt->lastTick)
: (currentTick + (ULONG_MAX - pNTPTimePvt->lastTick));
if(pNTPTimePvt->ticksToSkip>0) {/*dont go back in time*/
if(nticks<pNTPTimePvt->ticksToSkip) {
/*pNTPTimePvt->ticksToSkip -= nticks;*/ /* fix bug here */
break;
}
nticks -= pNTPTimePvt->ticksToSkip;
pNTPTimePvt->ticksToSkip = 0; /* fix bug here */
}
pNTPTimePvt->lastTick = currentTick;
pNTPTimePvt->tickRate = sysClkRateGet();
nsecs = nticks/pNTPTimePvt->tickRate;
nticks = nticks - nsecs*pNTPTimePvt->tickRate;
pNTPTimePvt->clock.nsec += nticks * pNTPTimePvt->nanosecondsPerTick;
if(pNTPTimePvt->clock.nsec>=BILLION) {
++nsecs;
pNTPTimePvt->clock.nsec -= BILLION;
}
pNTPTimePvt->clock.secPastEpoch += nsecs;
}
*pDest = pNTPTimePvt->clock;
epicsMutexUnlock(pNTPTimePvt->lock);
return(0);
}
long NTPTime_Report(int level)
{
printf(NTPTIME_DRV_VERSION"\n");
if(!pNTPTimePvt)
{/* drvNTPTime is not used, we just report version then quit */
printf("NTP time driver is not initialized yet!\n\n");
}
else
{
printf("\n");
}
return 0;
}

View File

@@ -0,0 +1,14 @@
#ifndef _INC_drvDevNTPTime
#define _INC_drvDevNTPTime
#ifdef __cplusplus
extern "C" {
#endif
long NTPTime_Init(int);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,205 @@
/* Sheng Peng @ SNS ORNL 07/2004 */
/* Version 1.1 */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <vxWorks.h>
#include <bootLib.h>
#include <tickLib.h>
#include <sysLib.h>
#include <logLib.h>
#include <sntpcLib.h>
#include <time.h>
#include <errno.h>
#include <envLib.h>
#include <taskLib.h>
#include "epicsTypes.h"
#include "cantProceed.h"
#include "errlog.h"
#include "epicsThread.h"
#include "osdThread.h"
#include "epicsMutex.h"
#include "epicsTime.h"
#include "epicsTimer.h"
#include "epicsInterrupt.h"
#include "envDefs.h"
#include <dbDefs.h>
#include <devLib.h>
#include <module_types.h>
#define BILLION 1000000000
#define VXWORKS_TO_EPICS_EPOCH 631152000UL
#define VXTIME_DRV_VERSION "vxWorks Ticks Time Driver Version 1.2"
#define SYNC_PERIOD 60.0
#include "epicsGeneralTime.h"
static void VxTimeSyncTime(void *param);
long VxTime_Init(int priority);
static int VxTimeGetCurrent(epicsTimeStamp *pDest);
static void VxTime_StartSync(int junk);
long VxTime_Report(int level);
typedef struct VxTimePvt {
BOOL synced; /* if never synced, we can't use it */
epicsMutexId lock;
epicsTimerId sync_timer;
epicsTimeStamp lastReportedTS;
epicsTimeStamp lastSyncedTS;
struct timespec lastSyncedVxTime;
int priority;
int synced_priority;
}VxTimePvt;
static VxTimePvt *pVxTimePvt = 0;
static void VxTimeSyncTime(void *param)
{
epicsTimeStamp now;
struct timespec ticks_now;
/* Ask for the best time available, not including ourselves */
if (generalTimeGetExceptPriority(&now, &pVxTimePvt->synced_priority, pVxTimePvt->priority) == epicsTimeOK) {
/* It's a good time, we unconditionally sync ourselves to it, as
this driver is the bottom of the heap */
clock_gettime( CLOCK_REALTIME,&ticks_now );
epicsMutexMustLock(pVxTimePvt->lock);
pVxTimePvt->lastSyncedTS = now;
pVxTimePvt->lastSyncedVxTime = ticks_now;
pVxTimePvt->synced = TRUE;
epicsMutexUnlock(pVxTimePvt->lock);
}
/* Restart the timer, to call us again in SYNC_PERIOD seconds */
epicsTimerStartDelay(pVxTimePvt->sync_timer, SYNC_PERIOD);
}
long VxTime_Init(int priority)
{
taskLock();
if(pVxTimePvt) {
taskUnlock();
return OK;
}
pVxTimePvt = callocMustSucceed(1,sizeof(VxTimePvt),"VxTime_Init");
taskUnlock();
bzero((char *)pVxTimePvt, sizeof(VxTimePvt));
pVxTimePvt->synced = FALSE;
pVxTimePvt->lock = epicsMutexCreate();
pVxTimePvt->priority = priority;
/* register to link list */
generalTimeCurrentTpRegister("vxWorks Ticks", priority, VxTimeGetCurrent);
/* Don't start the syncing until the time system is up properly.
* This cannot be done using EPICS initHooks, as they are external
* to libCom, but this code is vxWorks-specific anyway, so use the
* vxWorks primitives. wdLib (watchdogs cannot be used as the called
* routines cannot take semaphores. */
taskSpawn("VxTime Start Sync", 150, VX_FP_TASK,
epicsThreadGetStackSize(epicsThreadStackMedium),
(FUNCPTR) VxTime_StartSync, 0,0,0,0,0,0,0,0,0,0);
return OK;
}
static int VxTimeGetCurrent(epicsTimeStamp *pDest)
{
struct timespec cur_vwtime;
unsigned long diff_sec, diff_nsec;
epicsTimeStamp epicsTime;
double diffTime;
epicsMutexMustLock(pVxTimePvt->lock);
clock_gettime( CLOCK_REALTIME,&cur_vwtime );
if(!pVxTimePvt->synced)
{
if( cur_vwtime.tv_sec < VXWORKS_TO_EPICS_EPOCH )
{ /* Earlier than 1990 is clearly wrong. Set the time to 1/1/90
+ 1 day (to avoid timezone problems) and set the VxWorks
clock to that point */
cur_vwtime.tv_sec = VXWORKS_TO_EPICS_EPOCH + 86400;
cur_vwtime.tv_nsec = 0;
clock_settime( CLOCK_REALTIME, &cur_vwtime);
epicsInterruptContextMessage("****************************"
"***************************************************\n"
"WARNING: VxWorks time not set. Initialised to 2/1/90\n"
"*****************************************************"
"**************************\n");
}
epicsTimeFromTimespec(&epicsTime, &cur_vwtime);
}
else/* synced, need calculation */
{/* the vxWorks time is always monotonic */
if( cur_vwtime.tv_nsec >= pVxTimePvt->lastSyncedVxTime.tv_nsec )
{
diff_sec = cur_vwtime.tv_sec - pVxTimePvt->lastSyncedVxTime.tv_sec;
diff_nsec = cur_vwtime.tv_nsec - pVxTimePvt->lastSyncedVxTime.tv_nsec;
}
else
{
diff_sec = cur_vwtime.tv_sec - pVxTimePvt->lastSyncedVxTime.tv_sec - 1;
diff_nsec = BILLION - pVxTimePvt->lastSyncedVxTime.tv_nsec + cur_vwtime.tv_nsec;
}
epicsTime.nsec = pVxTimePvt->lastSyncedTS.nsec + diff_nsec;
epicsTime.secPastEpoch = pVxTimePvt->lastSyncedTS.secPastEpoch + diff_sec;
if( epicsTime.nsec >= BILLION )
{
epicsTime.nsec -= BILLION;
epicsTime.secPastEpoch ++;
}
}
diffTime = epicsTimeDiffInSeconds(&epicsTime,&pVxTimePvt->lastReportedTS);
if(diffTime >= 0.0)
{/* time is monotonic */
*pDest = epicsTime;
pVxTimePvt->lastReportedTS = epicsTime;
}
else
{/* time never goes back */
*pDest = pVxTimePvt->lastReportedTS;
}
epicsMutexUnlock(pVxTimePvt->lock);
return(0);
}
long VxTime_Report(int level)
{
printf(VXTIME_DRV_VERSION"\n");
if(!pVxTimePvt)
{/* drvVxTime is not used, we just report version then quit */
printf("vxWorks ticks time driver is not initialized yet!\n\n");
}
else
{
printf("%synced. Last time = %lds, %ldns. ",
pVxTimePvt->synced ?"S":"Not s",
pVxTimePvt->lastSyncedVxTime.tv_sec,
pVxTimePvt->lastSyncedVxTime.tv_nsec);
printf("Timer = %p\n", pVxTimePvt->sync_timer);
}
return OK;
}
static void VxTime_StartSync(int junk)
{
/* Wait some time before trying to start the timer up */
taskDelay(10 * sysClkRateGet());
pVxTimePvt->sync_timer = generalTimeCreateSyncTimer(VxTimeSyncTime, 0);
/* Sync the first time in one second, then drop back to less frequently */
epicsTimerStartDelay(pVxTimePvt->sync_timer, 1.0);
}

View File

@@ -0,0 +1,14 @@
#ifndef _INC_drvVxTime
#define _INC_drvVxTime
#ifdef __cplusplus
extern "C" {
#endif
long VxTime_Init(int);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -47,8 +47,6 @@ typedef struct iocClockPvt {
epicsUInt32 nanosecondsPerTick;
int tickRate;
int ticksToSkip;
pepicsTimeGetCurrent getCurrent;
pepicsTimeGetEvent getEvent;
const char *pserverAddr;
}iocClockPvt;
static iocClockPvt *piocClockPvt = 0;
@@ -105,8 +103,6 @@ void iocClockInit()
piocClockPvt->lock = epicsMutexCreate();
piocClockPvt->nanosecondsPerTick = BILLION/sysClkRateGet();
piocClockPvt->tickRate = sysClkRateGet();
piocClockPvt->getCurrent = iocClockGetCurrent;
piocClockPvt->getEvent = iocClockGetEvent;
/* look first for environment variable or CONFIG_SITE_ENV default */
piocClockPvt->pserverAddr = envGetConfigParamPtr(&EPICS_TS_NTP_INET);
if(!piocClockPvt->pserverAddr) { /* if neither, use the boot host */
@@ -141,18 +137,6 @@ void iocClockInit()
return;
}
void iocClockRegister(pepicsTimeGetCurrent getCurrent,
pepicsTimeGetEvent getEvent)
{
if(piocClockPvt) {
printf("iocClockRegister: iocClock already initialized\n");
return;
}
piocClockPvt = callocMustSucceed(1,sizeof(iocClockPvt),"iocClockRegister");
piocClockPvt->getCurrent = getCurrent;
piocClockPvt->getEvent = getEvent;
}
int iocClockGetCurrent(epicsTimeStamp *pDest)
{
unsigned long currentTick,nticks,nsecs;
@@ -194,26 +178,3 @@ int iocClockGetEvent(epicsTimeStamp *pDest, int eventNumber)
return(epicsTimeERROR);
}
int epicsTimeGetCurrent (epicsTimeStamp *pDest)
{
if(!piocClockPvt) {
iocClockInit();
/*wait two seconds for syncNTP to contact network time server*/
epicsThreadSleep(2.0);
}
if(piocClockPvt->getCurrent) return((*piocClockPvt->getCurrent)(pDest));
return(epicsTimeERROR);
}
int epicsTimeGetEvent (epicsTimeStamp *pDest, int eventNumber)
{
if(!piocClockPvt) {
iocClockInit();
/*wait two seconds for syncNTP to contact network time server*/
epicsThreadSleep(2.0);
}
if(piocClockPvt->getEvent)
return((*piocClockPvt->getEvent)(pDest,eventNumber));
return(epicsTimeERROR);
}

View File

@@ -12,9 +12,6 @@
/* Author: Marty Kraimer Date: 16JUN2000 */
#include "epicsTime.h"
typedef int (*pepicsTimeGetCurrent)(epicsTimeStamp *pDest);
typedef int (*pepicsTimeGetEvent)(epicsTimeStamp *pDest,int eventNumber);
#include "epicsGeneralTime.h"
void iocClockInit(void);
void iocClockRegister(pepicsTimeGetCurrent getCurrent,pepicsTimeGetEvent getEvent);

View File

@@ -9,9 +9,19 @@
\*************************************************************************/
#include "epicsTime.h"
#include "drvNTPTime.h"
#include "drvVxTime.h"
#include "epicsGeneralTime.h"
// epicsTimeGetCurrent and epicsTimeGetEvent are implemented in iocClock.c
extern "C" epicsShareFunc int epicsShareAPI osdTimeInit(void)
{
NTPTime_Init(100); /* init NTP first so it can be used to sync VW */
VxTime_Init(LAST_RESORT_PRIORITY);
return epicsTimeOK;
}
// vxWorks localtime_r interface does not match POSIX standards
int epicsTime_localtime ( const time_t *clock, struct tm *result )
{