diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index c35183b81..1caca05c7 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -38,7 +38,7 @@ the EPICS/RTEMS tutorial.
RTEMS Timing
RTEMS IOCs now work properly as soft timing slaves (i.e. remain
-synchronized master timingIOC).
+synchronized master timingIOC) and as NTP clients.
SEL record (Mantis #295)
diff --git a/src/libCom/osi/os/RTEMS/iocClock.c b/src/libCom/osi/os/RTEMS/iocClock.c
index e4811b73f..d32c5cda9 100644
--- a/src/libCom/osi/os/RTEMS/iocClock.c
+++ b/src/libCom/osi/os/RTEMS/iocClock.c
@@ -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
#include
-
-/*
- * RTEMS
- */
+#include
+#include
#include
-
-/*
- * EPICS
- */
-#define epicsExportSharedSymbols
#include
+#include
+#include
+#include
#include
#include
#include
-/*
- * 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(nticksticksToSkip) {
+ 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);
}
+