Add NTP capability (to match vxWorks).

This commit is contained in:
W. Eric Norum
2007-10-03 23:38:26 +00:00
parent 52ab7f6d6b
commit 5790d231c2
2 changed files with 138 additions and 61 deletions

View File

@@ -38,7 +38,7 @@ the EPICS/RTEMS tutorial.</p>
<h4>RTEMS Timing</h4>
<p>RTEMS IOCs now work properly as soft timing slaves (i.e. remain
synchronized master timingIOC).</p>
synchronized master timingIOC) and as NTP clients.</p>
<h4>SEL record (Mantis #295)</h4>

View File

@@ -1,116 +1,193 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* 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.
\*************************************************************************/
/*
* $Id$
*
* Author: W. Eric Norum
*/
/* iocClock.c */
/* Author: Marty Kraimer Date: 16JUN2000 */
/*l Modified by Eric Norum to work with RTEMS */
/*
* ANSI C
*/
#include <time.h>
#include <limits.h>
/*
* RTEMS
*/
#include <string.h>
#include <errno.h>
#include <rtems.h>
/*
* EPICS
*/
#define epicsExportSharedSymbols
#include <epicsStdio.h>
#include <epicsThread.h>
#include <epicsMutex.h>
#include <epicsTime.h>
#include <cantProceed.h>
#include <iocClock.h>
#include <errlog.h>
/*
* RTEMS time begins January 1, 1988 (local time).
* EPICS time begins January 1, 1990 (GMT).
*/
#define EPICS_EPOCH_SEC_PAST_RTEMS_EPOCH ((366+365)*86400)
#define BILLION 1000000000
#define iocClockSyncRate 10.0
static int iocClockGetCurrent(epicsTimeStamp *pDest);
static int iocClockGetEvent(epicsTimeStamp *pDest, int eventNumber);
typedef struct iocClockPvt {
epicsMutexId lock;
epicsTimeStamp clock;
unsigned long lastTick;
epicsUInt32 nanosecondsPerTick;
int tickRate;
int ticksToSkip;
pepicsTimeGetCurrent getCurrent;
pepicsTimeGetEvent getEvent;
}iocClockPvt;
static iocClockPvt *piocClockPvt = 0;
static int nConsecutiveBad = 0;
void
iocClockInit(void)
static int
tickGet(void)
{
rtems_interval t;
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &t);
return t;
}
static int
sysClkRateGet(void)
{
rtems_interval t;
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &t);
return t;
}
static void syncNTP(void)
{
struct timespec Currtime;
epicsTimeStamp epicsTime;
int status;
int prevStatusBad = 0;
int firstTime=1;
while(1) {
double diffTime;
if(!firstTime)epicsThreadSleep(iocClockSyncRate);
firstTime = 0;
status = rtems_bsdnet_get_ntp(-1, NULL, &Currtime);
if(status) {
++nConsecutiveBad;
/*wait 1 minute before reporting failure*/
if(nConsecutiveBad<(60/iocClockSyncRate)) continue;
if(!prevStatusBad)
errlogPrintf("iocClockSyncWithNTPserver: sntpcTimeGet %s\n",
strerror(errno));
prevStatusBad = 1;
continue;
}
nConsecutiveBad=0;
if(prevStatusBad) {
errlogPrintf("iocClockSyncWithNTPserver: sntpcTimeGet OK\n");
prevStatusBad = 0;
}
epicsTimeFromTimespec(&epicsTime,&Currtime);
epicsMutexMustLock(piocClockPvt->lock);
diffTime = epicsTimeDiffInSeconds(&epicsTime,&piocClockPvt->clock);
if(diffTime>=0.0) {
piocClockPvt->clock = epicsTime;
} else {/*dont go back in time*/
piocClockPvt->ticksToSkip = (int) (diffTime*piocClockPvt->tickRate);
}
piocClockPvt->lastTick = tickGet();
epicsMutexUnlock(piocClockPvt->lock);
}
}
void iocClockInit()
{
if(piocClockPvt) return;
piocClockPvt = (iocClockPvt *)callocMustSucceed(1,sizeof(iocClockPvt),"iocClockInit");
piocClockPvt = callocMustSucceed(1,sizeof(iocClockPvt),"iocClockInit");
piocClockPvt->lock = epicsMutexCreate();
piocClockPvt->nanosecondsPerTick = BILLION/sysClkRateGet();
piocClockPvt->tickRate = sysClkRateGet();
piocClockPvt->getCurrent = iocClockGetCurrent;
piocClockPvt->getEvent = iocClockGetEvent;
epicsThreadCreate("syncNTP",
epicsThreadPriorityHigh,
epicsThreadGetStackSize(epicsThreadStackSmall),
(EPICSTHREADFUNC)syncNTP,0);
return;
}
void
iocClockRegister(pepicsTimeGetCurrent getCurrent, pepicsTimeGetEvent getEvent)
void iocClockRegister(pepicsTimeGetCurrent getCurrent,
pepicsTimeGetEvent getEvent)
{
if(piocClockPvt)
printf("iocClockRegister: iocClock already initialized -- overriding --\n");
printf("iocClockRegister: iocClock already initialized -- overriding\n");
else
piocClockPvt = (iocClockPvt *)callocMustSucceed(1,sizeof(iocClockPvt),"iocClockRegister");
piocClockPvt = callocMustSucceed(1,sizeof(iocClockPvt),"iocClockRegister");
piocClockPvt->getCurrent = getCurrent;
piocClockPvt->getEvent = getEvent;
}
static int
iocClockGetCurrent(epicsTimeStamp *pDest)
int iocClockGetCurrent(epicsTimeStamp *pDest)
{
struct timeval curtime;
rtems_interval t;
rtems_status_code sc;
unsigned long currentTick,nticks,nsecs;
for (;;) {
sc = rtems_clock_get (RTEMS_CLOCK_GET_TIME_VALUE, &curtime);
if (sc == RTEMS_SUCCESSFUL)
break;
else if (sc != RTEMS_NOT_DEFINED)
return epicsTimeERROR;
sc = rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &t);
if (sc != RTEMS_SUCCESSFUL)
return epicsTimeERROR;
rtems_task_wake_after (t);
epicsMutexMustLock(piocClockPvt->lock);
currentTick = tickGet();
while(currentTick!=piocClockPvt->lastTick) {
nticks = (currentTick>piocClockPvt->lastTick)
? (currentTick - piocClockPvt->lastTick)
: (currentTick + (ULONG_MAX - piocClockPvt->lastTick));
if(piocClockPvt->ticksToSkip>0) {/*dont go back in time*/
if(nticks<piocClockPvt->ticksToSkip) {
piocClockPvt->ticksToSkip -= nticks;
break;
}
nticks -= piocClockPvt->ticksToSkip;
}
piocClockPvt->lastTick = currentTick;
nsecs = nticks/piocClockPvt->tickRate;
nticks = nticks - nsecs*piocClockPvt->tickRate;
piocClockPvt->clock.nsec += nticks * piocClockPvt->nanosecondsPerTick;
if(piocClockPvt->clock.nsec>=BILLION) {
++nsecs;
piocClockPvt->clock.nsec -= BILLION;
}
piocClockPvt->clock.secPastEpoch += nsecs;
}
pDest->nsec = curtime.tv_usec * 1000;
pDest->secPastEpoch = curtime.tv_sec - EPICS_EPOCH_SEC_PAST_RTEMS_EPOCH;
return epicsTimeOK;
*pDest = piocClockPvt->clock;
epicsMutexUnlock(piocClockPvt->lock);
return(0);
}
static int
iocClockGetEvent(epicsTimeStamp *pDest, int eventNumber)
int iocClockGetEvent(epicsTimeStamp *pDest, int eventNumber)
{
if (eventNumber==epicsTimeEventCurrentTime)
return iocClockGetCurrent(pDest);
if (eventNumber==epicsTimeEventCurrentTime) {
*pDest = piocClockPvt->clock;
return(0);
}
return(epicsTimeERROR);
}
int
epicsTimeGetCurrent (epicsTimeStamp *pDest)
int epicsTimeGetCurrent (epicsTimeStamp *pDest)
{
if(!piocClockPvt)
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)
int epicsTimeGetEvent (epicsTimeStamp *pDest, int eventNumber)
{
if(!piocClockPvt)
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);
}