From 5790d231c229d89f9efb4e1a84dd7902d1335d12 Mon Sep 17 00:00:00 2001 From: "W. Eric Norum" Date: Wed, 3 Oct 2007 23:38:26 +0000 Subject: [PATCH] Add NTP capability (to match vxWorks). --- documentation/RELEASE_NOTES.html | 2 +- src/libCom/osi/os/RTEMS/iocClock.c | 197 ++++++++++++++++++++--------- 2 files changed, 138 insertions(+), 61 deletions(-) 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); } +