General Time, from Peter Denison, Eric Norum and many others...
This commit is contained in:
@@ -37,6 +37,7 @@ LIBSRCS += devSASoft.c
|
||||
LIBSRCS += devSiSoft.c
|
||||
LIBSRCS += devSoSoft.c
|
||||
LIBSRCS += devWfSoft.c
|
||||
LIBSRCS += devGeneralTime.c
|
||||
|
||||
LIBSRCS += devAoSoftCallback.c
|
||||
LIBSRCS += devBoSoftCallback.c
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
/***************************************************************************
|
||||
* File: devGeneralTime.c
|
||||
* Author: Sheng Peng
|
||||
* Institution: Oak Ridge National Laboratory / SNS Project
|
||||
* Date: 07/2004
|
||||
* Version: 1.2
|
||||
*
|
||||
* EPICS device layer support for general EPICS timestamp support
|
||||
*
|
||||
* Integrated into base by Peter Denison, Diamond Light Source
|
||||
****************************************************************************/
|
||||
|
||||
/* Include header files */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <dbCommon.h>
|
||||
#include <dbDefs.h>
|
||||
#include <dbScan.h>
|
||||
#include <dbAccess.h>
|
||||
#include <recSup.h>
|
||||
#include <recGbl.h>
|
||||
#include <devSup.h>
|
||||
#include <devLib.h>
|
||||
#include <drvSup.h>
|
||||
|
||||
#include <alarm.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
#include <aiRecord.h>
|
||||
#include <boRecord.h>
|
||||
#include <longinRecord.h>
|
||||
#include <stringinRecord.h>
|
||||
|
||||
#include "epicsGeneralTime.h"
|
||||
|
||||
int GENERALTIME_DEV_DEBUG=0;
|
||||
|
||||
/* define function flags */
|
||||
typedef enum {
|
||||
GTIM_AI_CURRENT,
|
||||
GTIM_BO_RSTERRCNT,
|
||||
GTIM_LI_GETERRCNT,
|
||||
GTIM_SI_BESTTCP,
|
||||
GTIM_SI_BESTTEP
|
||||
} GTIMFUNC;
|
||||
|
||||
|
||||
/* define parameter check for convinence */
|
||||
#define CHECK_AIPARM(PARM,VAL)\
|
||||
if (!strncmp(pai->inp.value.instio.string,(PARM),strlen((PARM)))) {\
|
||||
pai->dpvt=(void *)VAL;\
|
||||
return (0);\
|
||||
}
|
||||
#define CHECK_BOPARM(PARM,VAL)\
|
||||
if (!strncmp(pbo->out.value.instio.string,(PARM),strlen((PARM)))) {\
|
||||
pbo->dpvt=(void *)VAL;\
|
||||
paramOK=1;\
|
||||
}
|
||||
#define CHECK_LIPARM(PARM,VAL)\
|
||||
if (!strncmp(pli->inp.value.instio.string,(PARM),strlen((PARM)))) {\
|
||||
pli->dpvt=(void *)VAL;\
|
||||
return (0);\
|
||||
}
|
||||
#define CHECK_SIPARM(PARM,VAL)\
|
||||
if (!strncmp(psi->inp.value.instio.string,(PARM),strlen((PARM)))) {\
|
||||
psi->dpvt=(void *)VAL;\
|
||||
return (0);\
|
||||
}
|
||||
|
||||
/* function prototypes */
|
||||
static long init(int pass);
|
||||
|
||||
static long init_ai(struct aiRecord *pai);
|
||||
static long read_ai(struct aiRecord *pai);
|
||||
|
||||
static long init_bo(struct boRecord *pbo);
|
||||
static long write_bo(struct boRecord *pbo);
|
||||
|
||||
static long init_li(struct longinRecord *pli);
|
||||
static long read_li(struct longinRecord *pli);
|
||||
|
||||
static long init_si(struct stringinRecord *psi);
|
||||
static long read_si(struct stringinRecord *psi);
|
||||
|
||||
/* global struct for devSup */
|
||||
typedef struct {
|
||||
long number;
|
||||
DEVSUPFUN report;
|
||||
DEVSUPFUN init;
|
||||
DEVSUPFUN init_record;
|
||||
DEVSUPFUN get_ioint_info;
|
||||
DEVSUPFUN read_write;
|
||||
DEVSUPFUN special_linconv;} GTIM_DEV_SUP_SET;
|
||||
|
||||
GTIM_DEV_SUP_SET devAiGeneralTime= {6, NULL, init, init_ai, NULL, read_ai, NULL};
|
||||
GTIM_DEV_SUP_SET devBoGeneralTime= {6, NULL, NULL, init_bo, NULL, write_bo, NULL};
|
||||
GTIM_DEV_SUP_SET devLiGeneralTime= {6, NULL, NULL, init_li, NULL, read_li, NULL};
|
||||
GTIM_DEV_SUP_SET devSiGeneralTime= {6, NULL, NULL, init_si, NULL, read_si, NULL};
|
||||
|
||||
epicsExportAddress(dset, devAiGeneralTime);
|
||||
epicsExportAddress(dset, devBoGeneralTime);
|
||||
epicsExportAddress(dset, devLiGeneralTime);
|
||||
epicsExportAddress(dset, devSiGeneralTime);
|
||||
|
||||
/* function implementation */
|
||||
|
||||
static long init(int pass)
|
||||
{
|
||||
if(pass) return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long init_ai( struct aiRecord *pai)
|
||||
{
|
||||
if (pai->inp.type!=INST_IO)
|
||||
{
|
||||
recGblRecordError(S_db_badField, (void *)pai,
|
||||
"devAiGeneralTime Init_record, Illegal INP");
|
||||
pai->pact=TRUE;
|
||||
return (S_db_badField);
|
||||
}
|
||||
|
||||
CHECK_AIPARM("TIME", GTIM_AI_CURRENT)
|
||||
/* reach here, bad parm */
|
||||
recGblRecordError(S_db_badField, (void *)pai,
|
||||
"devAiGeneralTime Init_record, bad parm");
|
||||
pai->pact=TRUE;
|
||||
return (S_db_badField);
|
||||
}
|
||||
|
||||
static long read_ai(struct aiRecord *pai)
|
||||
{
|
||||
int status=-1;
|
||||
double temp;
|
||||
|
||||
switch ((int)pai->dpvt)
|
||||
{
|
||||
case GTIM_AI_CURRENT:
|
||||
status=generalTimeGetCurrentDouble(&temp);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if (status==0)
|
||||
{
|
||||
pai->val=temp;
|
||||
pai->udf=FALSE;
|
||||
return 2;/******** not convert ****/
|
||||
}
|
||||
else
|
||||
{
|
||||
pai->udf=TRUE;
|
||||
recGblSetSevr(pai,READ_ALARM,INVALID_ALARM);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*********bo record **********/
|
||||
static long init_bo(struct boRecord *pbo)
|
||||
{
|
||||
int paramOK=0;
|
||||
|
||||
if (pbo->out.type!=INST_IO)
|
||||
{
|
||||
recGblRecordError(S_db_badField, (void *)pbo,
|
||||
"devBoGeneralTime Init_record, Illegal OUT");
|
||||
pbo->pact=TRUE;
|
||||
return (S_db_badField);
|
||||
}
|
||||
CHECK_BOPARM("RSTERRCNT", GTIM_BO_RSTERRCNT)
|
||||
if (!paramOK)
|
||||
{
|
||||
recGblRecordError(S_db_badField, (void *)pbo,
|
||||
"devBoGeneralTime Init_record, bad parm");
|
||||
pbo->pact=TRUE;
|
||||
return (S_db_badField);
|
||||
}
|
||||
|
||||
pbo->mask=0; /** when convert rval from val,keep them same **/
|
||||
|
||||
return 2; /** don't convert rval to val **/
|
||||
}
|
||||
|
||||
static long write_bo(struct boRecord *pbo)
|
||||
{
|
||||
switch ((int)pbo->dpvt)
|
||||
{
|
||||
case GTIM_BO_RSTERRCNT:
|
||||
generalTimeResetErrorCounts();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*******longin record *************/
|
||||
static long init_li(struct longinRecord *pli)
|
||||
{
|
||||
if (pli->inp.type!=INST_IO)
|
||||
{
|
||||
recGblRecordError(S_db_badField, (void *)pli,
|
||||
"devLiGeneralTime Init_record, Illegal INP");
|
||||
pli->pact=TRUE;
|
||||
return (S_db_badField);
|
||||
}
|
||||
CHECK_LIPARM("GETERRCNT", GTIM_LI_GETERRCNT)
|
||||
/* reach here, bad parm */
|
||||
recGblRecordError(S_db_badField, (void *)pli,
|
||||
"devLiGeneralTime Init_record, bad parm");
|
||||
pli->pact=TRUE;
|
||||
return (S_db_badField);
|
||||
}
|
||||
|
||||
static long read_li(struct longinRecord *pli)
|
||||
{
|
||||
switch ((int)pli->dpvt)
|
||||
{
|
||||
case GTIM_LI_GETERRCNT:
|
||||
pli->val=generalTimeGetErrorCounts();
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/********** stringin record **********/
|
||||
static long init_si(struct stringinRecord *psi)
|
||||
{
|
||||
if (psi->inp.type!=INST_IO)
|
||||
{
|
||||
recGblRecordError(S_db_badField, (void *)psi,
|
||||
"devSiGeneralTime Init_record, Illegal INP");
|
||||
psi->pact=TRUE;
|
||||
return (S_db_badField);
|
||||
}
|
||||
CHECK_SIPARM("BESTTCP", GTIM_SI_BESTTCP)
|
||||
CHECK_SIPARM("BESTTEP", GTIM_SI_BESTTEP)
|
||||
/* reach here, bad parm */
|
||||
recGblRecordError(S_db_badField, (void *)psi,
|
||||
"devSiGeneralTime Init_record, bad parm");
|
||||
psi->pact=TRUE;
|
||||
return (S_db_badField);
|
||||
}
|
||||
|
||||
static long read_si(struct stringinRecord *psi)
|
||||
{
|
||||
switch ((int)psi->dpvt)
|
||||
{
|
||||
case GTIM_SI_BESTTCP:
|
||||
generalTimeGetBestTcp(psi->val);
|
||||
break;
|
||||
case GTIM_SI_BESTTEP:
|
||||
generalTimeGetBestTep(psi->val);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -33,3 +33,8 @@ device(mbboDirect,CONSTANT,devMbboDirectSoftCallback,"Async Soft Channel")
|
||||
device(stringout,CONSTANT,devSoSoftCallback,"Async Soft Channel")
|
||||
|
||||
device(stringin,INST_IO,devTimestampSI,"Soft Timestamp")
|
||||
|
||||
device(ai, INST_IO,devAiGeneralTime,"General Time")
|
||||
device(bo, INST_IO,devBoGeneralTime,"General Time")
|
||||
device(longin, INST_IO,devLiGeneralTime,"General Time")
|
||||
device(stringin,INST_IO,devSiGeneralTime,"General Time")
|
||||
|
||||
+9
-5
@@ -174,6 +174,7 @@ INC += osdThread.h
|
||||
|
||||
INC += epicsThread.h
|
||||
INC += epicsTime.h
|
||||
INC += epicsGeneralTime.h
|
||||
INC += osdTime.h
|
||||
INC += epicsSignal.h
|
||||
INC += osiProcess.h
|
||||
@@ -197,6 +198,9 @@ SRCS += epicsEvent.cpp
|
||||
SRCS += epicsTime.cpp
|
||||
SRCS += epicsMessageQueue.cpp
|
||||
|
||||
INC += generalTimeSup.h
|
||||
SRCS += epicsGeneralTime.c
|
||||
|
||||
SRCS += osdSock.c
|
||||
SRCS += osdSockAddrReuse.cpp
|
||||
SRCS += osiSock.c
|
||||
@@ -244,12 +248,12 @@ SRC_DIRS += $(LIBCOM)/tsDefs
|
||||
INC += tsDefs.h
|
||||
SRCS += tsDefs.c
|
||||
|
||||
SRCS_vxWorks += osiNTPTime.c
|
||||
SRCS_RTEMS += osiNTPTime.c
|
||||
# Time provider, in osi/os/default
|
||||
SRCS_vxWorks += osdSysTime.c
|
||||
SRCS_RTEMS += osdSysTime.c
|
||||
# These files are in osi/os/vxWorks
|
||||
# IOC Time of Day clock
|
||||
INC_vxWorks += iocClock.h
|
||||
SRCS_vxWorks += iocClock.c
|
||||
INC_RTEMS += iocClock.h
|
||||
SRCS_RTEMS += iocClock.c
|
||||
# Special reboot hook
|
||||
SRCS_vxWorks += atReboot.cpp
|
||||
# For old vxWorks applications
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "osiUnistd.h"
|
||||
#include "logClient.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsGeneralTime.h"
|
||||
#include "libComRegister.h"
|
||||
|
||||
|
||||
@@ -291,6 +292,22 @@ static void epicsThreadResumeCallFunc(const iocshArgBuf *args)
|
||||
}
|
||||
}
|
||||
|
||||
/* generalTimeReport */
|
||||
static const iocshArg generalTimeReportArg0 = { "interest_level", iocshArgArgv};
|
||||
static const iocshArg * const generalTimeReportArgs[1] = { &generalTimeReportArg0 };
|
||||
static const iocshFuncDef generalTimeReportFuncDef = {"generalTimeReport",1,generalTimeReportArgs};
|
||||
static void generalTimeReportCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
generalTimeReport(args[0].ival);
|
||||
}
|
||||
|
||||
/* lastResortEventProviderInstall */
|
||||
static const iocshFuncDef lastResortEventProviderInstallFuncDef = {"lastResortEventProviderInstall", 0, NULL};
|
||||
static void lastResortEventProviderInstallCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
lastResortEventProviderInstall();
|
||||
}
|
||||
|
||||
void epicsShareAPI libComRegister(void)
|
||||
{
|
||||
iocshRegister(&dateFuncDef, dateCallFunc);
|
||||
@@ -314,4 +331,7 @@ void epicsShareAPI libComRegister(void)
|
||||
iocshRegister(&epicsMutexShowAllFuncDef,epicsMutexShowAllCallFunc);
|
||||
iocshRegister(&epicsThreadSleepFuncDef,epicsThreadSleepCallFunc);
|
||||
iocshRegister(&epicsThreadResumeFuncDef,epicsThreadResumeCallFunc);
|
||||
|
||||
iocshRegister(&generalTimeReportFuncDef,generalTimeReportCallFunc);
|
||||
iocshRegister(&lastResortEventProviderInstallFuncDef, lastResortEventProviderInstallCallFunc);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,527 @@
|
||||
/***************************************************************************
|
||||
* File: epicsGeneralTime.c
|
||||
* Author: Sheng Peng
|
||||
* Institution: Oak Ridge National Laboratory / SNS Project
|
||||
* Date: 07/2004
|
||||
* Version: 1.3
|
||||
*
|
||||
* EPICS general timestamp support
|
||||
* integration into EPICS Base by Peter Denison, Diamond Light Source
|
||||
*
|
||||
* Copyright (c) 2008 Diamond Light Source Ltd
|
||||
* Copyright (c) 2004 Oak Ridge National Laboratory
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <epicsTypes.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsMessageQueue.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsTime.h>
|
||||
#include <epicsInterrupt.h>
|
||||
#include <osiSock.h>
|
||||
#include <ellLib.h>
|
||||
#include <errlog.h>
|
||||
#include <cantProceed.h>
|
||||
|
||||
#include <envDefs.h>
|
||||
|
||||
#include "generalTimeSup.h"
|
||||
#include "epicsGeneralTime.h"
|
||||
#define GENERALTIME_VERSION "GeneralTime Framework Version 1.2"
|
||||
|
||||
#define TP_DESC_LEN 40
|
||||
#define NUM_OF_EVENTS 256
|
||||
|
||||
typedef struct TIME_CURRENT_PROVIDER {
|
||||
ELLNODE node; /* Linked List Node */
|
||||
char tp_desc[TP_DESC_LEN];
|
||||
pepicsTimeGetCurrent tcp_getCurrent;
|
||||
int tcp_priority;
|
||||
} TIME_CURRENT_PROVIDER;
|
||||
|
||||
typedef struct TIME_EVENT_PROVIDER {
|
||||
ELLNODE node; /* Linked List Node */
|
||||
char tp_desc[TP_DESC_LEN];
|
||||
pepicsTimeGetEvent tep_getEvent;
|
||||
int tep_priority;
|
||||
} TIME_EVENT_PROVIDER;
|
||||
|
||||
typedef struct generalTimePvt
|
||||
{
|
||||
epicsMutexId tcp_list_sem; /* This is a mutex semaphore to protect time-current-provider-list operation */
|
||||
ELLLIST tcp_list; /* time current provider list */
|
||||
TIME_CURRENT_PROVIDER *pLastKnownBestTcp;
|
||||
epicsTimeStamp lastKnownTimeCurrent;
|
||||
|
||||
epicsMutexId tep_list_sem; /* This is a mutex semaphore to protect time-event-provider-list operation */
|
||||
ELLLIST tep_list; /* time event provider list */
|
||||
TIME_EVENT_PROVIDER *pLastKnownBestTep;
|
||||
epicsTimeStamp lastKnownTimeEvent[NUM_OF_EVENTS];
|
||||
epicsTimeStamp lastKnownTimeEventBestTime;
|
||||
|
||||
epicsTimerQueueId sync_queue;
|
||||
unsigned int ErrorCounts;
|
||||
} generalTimePvt;
|
||||
|
||||
int generalTimeGetCurrent(epicsTimeStamp *pDest);
|
||||
static int generalTimeGetCurrentPriority(epicsTimeStamp *pDest, int * pPriority);
|
||||
int generalTimeGetEvent(epicsTimeStamp *pDest,int eventNumber);
|
||||
static int generalTimeGetEventPriority(epicsTimeStamp *pDest,int eventNumber, int * pPriority);
|
||||
|
||||
long generalTimeReport(int level);
|
||||
|
||||
static generalTimePvt *pgeneralTimePvt=NULL;
|
||||
static char logBuffer[160];
|
||||
|
||||
int GENERALTIME_DEBUG=0;
|
||||
|
||||
/* implementation */
|
||||
void generalTime_InitOnce(void)
|
||||
{
|
||||
pgeneralTimePvt = (generalTimePvt *)callocMustSucceed(1,sizeof(generalTimePvt),"generalTime_Init");
|
||||
|
||||
ellInit(&(pgeneralTimePvt->tcp_list));
|
||||
pgeneralTimePvt->tcp_list_sem = epicsMutexMustCreate();
|
||||
|
||||
ellInit(&(pgeneralTimePvt->tep_list));
|
||||
pgeneralTimePvt->tep_list_sem = epicsMutexMustCreate();
|
||||
|
||||
/* Initialise the "last-resort" provider on a per-architecture basis */
|
||||
osdTimeInit();
|
||||
}
|
||||
|
||||
void generalTime_Init(void)
|
||||
{
|
||||
/* We must only initialise generalTime once */
|
||||
static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
epicsThreadOnce(&onceId, (EPICSTHREADFUNC)generalTime_InitOnce, NULL);
|
||||
}
|
||||
|
||||
int epicsTimeGetCurrent(epicsTimeStamp *pDest)
|
||||
{
|
||||
int priority;
|
||||
return(generalTimeGetCurrentPriority(pDest, &priority));
|
||||
}
|
||||
|
||||
static int generalTimeGetCurrentPriority(epicsTimeStamp *pDest, int * pPriority)
|
||||
{
|
||||
return(generalTimeGetExceptPriority(pDest, pPriority, 0)); /* no tcp is excluded */
|
||||
|
||||
}
|
||||
|
||||
int generalTimeGetExceptPriority(epicsTimeStamp *pDest, int * pPriority, int except_tcp)
|
||||
{
|
||||
int key;
|
||||
TIME_CURRENT_PROVIDER * ptcp;
|
||||
int status = epicsTimeERROR;
|
||||
if(!pgeneralTimePvt)
|
||||
generalTime_Init();
|
||||
|
||||
epicsMutexMustLock( pgeneralTimePvt->tcp_list_sem );
|
||||
for(ptcp=(TIME_CURRENT_PROVIDER *)ellFirst( &(pgeneralTimePvt->tcp_list) );
|
||||
ptcp; ptcp=(TIME_CURRENT_PROVIDER *)ellNext((ELLNODE *)ptcp))
|
||||
{/* when we register providers, we sort them by priority */
|
||||
/* Allow providers to ask for time not including their own */
|
||||
if (ptcp->tcp_priority == except_tcp) {
|
||||
continue;
|
||||
}
|
||||
if(ptcp->tcp_getCurrent)
|
||||
status=(*(ptcp->tcp_getCurrent))(pDest);
|
||||
if(status!=epicsTimeERROR)
|
||||
{/* we can check if time monotonic here */
|
||||
if (epicsTimeGreaterThanEqual(pDest, &(pgeneralTimePvt->lastKnownTimeCurrent))) {
|
||||
pgeneralTimePvt->lastKnownTimeCurrent=*pDest;
|
||||
pgeneralTimePvt->pLastKnownBestTcp=ptcp;
|
||||
*pPriority = ptcp->tcp_priority;
|
||||
} else {
|
||||
epicsTimeStamp orig = *pDest;
|
||||
*pDest=pgeneralTimePvt->lastKnownTimeCurrent;
|
||||
key = epicsInterruptLock(); /* OSI has no taskLock, but if we lock interrupt, it is good enough */
|
||||
pgeneralTimePvt->ErrorCounts++;
|
||||
epicsInterruptUnlock(key); /* OSI has no taskLock, but if we lock interrupt, it is good enough */
|
||||
if(GENERALTIME_DEBUG) {
|
||||
sprintf(logBuffer, "TCP provider \"%s\" provides backwards time!\nnew = %us, %uns, last = %us, %uns (%s)\n",
|
||||
ptcp->tp_desc,orig.secPastEpoch,orig.nsec,pDest->secPastEpoch,pDest->nsec,
|
||||
pgeneralTimePvt->pLastKnownBestTcp->tp_desc);
|
||||
epicsInterruptContextMessage(logBuffer);
|
||||
}
|
||||
*pPriority = pgeneralTimePvt->pLastKnownBestTcp->tcp_priority;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(status==epicsTimeERROR)
|
||||
pgeneralTimePvt->pLastKnownBestTcp=NULL;
|
||||
epicsMutexUnlock( pgeneralTimePvt->tcp_list_sem );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int epicsTimeGetEvent(epicsTimeStamp *pDest,int eventNumber)
|
||||
{
|
||||
int priority;
|
||||
if (eventNumber == epicsTimeEventCurrentTime) {
|
||||
return generalTimeGetCurrentPriority(pDest, &priority);
|
||||
} else {
|
||||
return(generalTimeGetEventPriority(pDest, eventNumber, &priority));
|
||||
}
|
||||
}
|
||||
|
||||
static int generalTimeGetEventPriority(epicsTimeStamp *pDest,int eventNumber, int * pPriority)
|
||||
{
|
||||
int key;
|
||||
TIME_EVENT_PROVIDER * ptep;
|
||||
int status = epicsTimeERROR;
|
||||
if(!pgeneralTimePvt)
|
||||
generalTime_Init();
|
||||
|
||||
epicsMutexMustLock( pgeneralTimePvt->tep_list_sem );
|
||||
for(ptep=(TIME_EVENT_PROVIDER *)ellFirst( &(pgeneralTimePvt->tep_list) );
|
||||
ptep; ptep=(TIME_EVENT_PROVIDER *)ellNext((ELLNODE *)ptep))
|
||||
{/* when we register provider, we sort them by priority */
|
||||
if(ptep->tep_getEvent)
|
||||
status=(*(ptep->tep_getEvent))(pDest,eventNumber);
|
||||
if(status!=epicsTimeERROR)
|
||||
{/* we can check if time monotonic here */
|
||||
pgeneralTimePvt->pLastKnownBestTep=ptep;
|
||||
*pPriority = ptep->tep_priority;
|
||||
if(eventNumber>=0 && eventNumber<NUM_OF_EVENTS)
|
||||
{
|
||||
if (epicsTimeGreaterThanEqual(pDest,&(pgeneralTimePvt->lastKnownTimeEvent[eventNumber]))) {
|
||||
pgeneralTimePvt->lastKnownTimeEvent[eventNumber]=*pDest;
|
||||
} else {
|
||||
*pDest=pgeneralTimePvt->lastKnownTimeEvent[eventNumber];
|
||||
key = epicsInterruptLock(); /* OSI has no taskLock, but if we lock interrupt, it is good enough */
|
||||
pgeneralTimePvt->ErrorCounts++;
|
||||
epicsInterruptUnlock(key); /* OSI has no taskLock, but if we lock interrupt, it is good enough */
|
||||
if(GENERALTIME_DEBUG) {
|
||||
sprintf(logBuffer, "TEP provider \"%s\" provides backwards time on Event %d!\n", ptep->tp_desc, eventNumber);
|
||||
epicsInterruptContextMessage(logBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(eventNumber==epicsTimeEventBestTime)
|
||||
{
|
||||
if (epicsTimeGreaterThanEqual(pDest,&(pgeneralTimePvt->lastKnownTimeEventBestTime))) {
|
||||
pgeneralTimePvt->lastKnownTimeEventBestTime=*pDest;
|
||||
} else {
|
||||
*pDest=pgeneralTimePvt->lastKnownTimeEventBestTime;
|
||||
key = epicsInterruptLock(); /* OSI has no taskLock, but if we lock interrupt, it is good enough */
|
||||
pgeneralTimePvt->ErrorCounts++;
|
||||
epicsInterruptUnlock(key); /* OSI has no taskLock, but if we lock interrupt, it is good enough */
|
||||
if(GENERALTIME_DEBUG) {
|
||||
sprintf(logBuffer, "TEP provider \"%s\" provides backwards time on Event BestTime!\n", ptep->tp_desc);
|
||||
epicsInterruptContextMessage(logBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(status==epicsTimeERROR)
|
||||
pgeneralTimePvt->pLastKnownBestTep=NULL;
|
||||
epicsMutexUnlock( pgeneralTimePvt->tep_list_sem );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* For all the similarity of the following two functions, they are
|
||||
* walking separate lists, and assigning to structures of different
|
||||
* types, all because of the difference in function prototype between
|
||||
* the getCurrent and getEvent functions. While they could be templated,
|
||||
* I think it's simpler to leave the duplication there.
|
||||
*/
|
||||
|
||||
int generalTimeEventTpRegister(const char *desc, int priority, pepicsTimeGetEvent getEvent)
|
||||
{
|
||||
TIME_EVENT_PROVIDER * ptep, * ptepref;
|
||||
|
||||
if(!pgeneralTimePvt)
|
||||
generalTime_Init();
|
||||
|
||||
ptep=(TIME_EVENT_PROVIDER *)malloc(sizeof(TIME_EVENT_PROVIDER));
|
||||
|
||||
if(ptep==NULL) {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
|
||||
strncpy(ptep->tp_desc,desc,TP_DESC_LEN-1);
|
||||
ptep->tp_desc[TP_DESC_LEN-1]='\0';
|
||||
ptep->tep_priority=priority;
|
||||
ptep->tep_getEvent=getEvent;
|
||||
|
||||
epicsMutexMustLock( pgeneralTimePvt->tep_list_sem );
|
||||
for(ptepref=(TIME_EVENT_PROVIDER *)ellFirst( &(pgeneralTimePvt->tep_list) );
|
||||
ptepref; ptepref=(TIME_EVENT_PROVIDER *)ellNext((ELLNODE *)ptepref))
|
||||
{
|
||||
if(ptepref->tep_priority > ptep->tep_priority) break;
|
||||
}
|
||||
if(ptepref)
|
||||
{/* found a ref whose priority is just bigger than the new one */
|
||||
ptepref=(TIME_EVENT_PROVIDER *)ellPrevious((ELLNODE *)ptepref);
|
||||
ellInsert( &(pgeneralTimePvt->tep_list), (ELLNODE *)ptepref, (ELLNODE *)ptep );
|
||||
}
|
||||
else
|
||||
{/* either list is empty or no one have bigger(lower) priority, put on tail */
|
||||
ellAdd( &(pgeneralTimePvt->tep_list), (ELLNODE *)ptep );
|
||||
}
|
||||
epicsMutexUnlock( pgeneralTimePvt->tep_list_sem );
|
||||
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
int generalTimeCurrentTpRegister(const char *desc, int priority, pepicsTimeGetCurrent getCurrent)
|
||||
{
|
||||
TIME_CURRENT_PROVIDER * ptcp, * ptcpref;
|
||||
|
||||
if(!pgeneralTimePvt)
|
||||
generalTime_Init();
|
||||
|
||||
ptcp=(TIME_CURRENT_PROVIDER *)malloc(sizeof(TIME_CURRENT_PROVIDER));
|
||||
|
||||
if(ptcp==NULL) {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
|
||||
strncpy(ptcp->tp_desc,desc,TP_DESC_LEN-1);
|
||||
ptcp->tp_desc[TP_DESC_LEN-1]='\0';
|
||||
ptcp->tcp_priority=priority;
|
||||
ptcp->tcp_getCurrent=getCurrent;
|
||||
|
||||
epicsMutexMustLock( pgeneralTimePvt->tcp_list_sem );
|
||||
for(ptcpref=(TIME_CURRENT_PROVIDER *)ellFirst( &(pgeneralTimePvt->tcp_list) );
|
||||
ptcpref; ptcpref=(TIME_CURRENT_PROVIDER *)ellNext((ELLNODE *)ptcpref))
|
||||
{
|
||||
if(ptcpref->tcp_priority > ptcp->tcp_priority) break;
|
||||
}
|
||||
if(ptcpref)
|
||||
{/* found a ref whose priority is just bigger than the new one */
|
||||
ptcpref=(TIME_CURRENT_PROVIDER *)ellPrevious((ELLNODE *)ptcpref);
|
||||
ellInsert( &(pgeneralTimePvt->tcp_list), (ELLNODE *)ptcpref, (ELLNODE *)ptcp );
|
||||
}
|
||||
else
|
||||
{/* either list is empty or no one have bigger(lower) priority, put on tail */
|
||||
ellAdd( &(pgeneralTimePvt->tcp_list), (ELLNODE *)ptcp );
|
||||
}
|
||||
epicsMutexUnlock( pgeneralTimePvt->tcp_list_sem);
|
||||
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide an optional "last resort" provider for Event Time.
|
||||
*
|
||||
* This is deliberately optional, as it represents site policy.
|
||||
* It is intended to be installed as an EventTime provider at the lowest
|
||||
* priority, to return the current time for an event if there is no
|
||||
* better time provider for event times.
|
||||
*
|
||||
* Typically, this will only be used during startup, or a time-provider
|
||||
* resynchronisation, where events are being generated by the event system
|
||||
* but the time provided by the system is not yet valid.
|
||||
*/
|
||||
static int lastResortGetEvent(epicsTimeStamp *timeStamp, int eventNumber)
|
||||
{
|
||||
return epicsTimeGetCurrent(timeStamp);
|
||||
}
|
||||
|
||||
int lastResortEventProviderInstall(void)
|
||||
{
|
||||
return generalTimeEventTpRegister("Last Resort Event", LAST_RESORT_PRIORITY, lastResortGetEvent);
|
||||
}
|
||||
|
||||
epicsTimerId generalTimeCreateSyncTimer(epicsTimerCallback cb, void* param)
|
||||
{
|
||||
if (!pgeneralTimePvt->sync_queue) {
|
||||
pgeneralTimePvt->sync_queue = epicsTimerQueueAllocate(0, epicsThreadPriorityHigh);
|
||||
}
|
||||
return epicsTimerQueueCreateTimer(pgeneralTimePvt->sync_queue, cb, param);
|
||||
}
|
||||
|
||||
long generalTimeReport(int level)
|
||||
{
|
||||
TIME_CURRENT_PROVIDER * ptcp;
|
||||
TIME_EVENT_PROVIDER * ptep;
|
||||
|
||||
int status;
|
||||
epicsTimeStamp tempTS;
|
||||
char tempTSText[40];
|
||||
|
||||
int items; /* how many provider we have */
|
||||
char * ptempText; /* logMsg passed pointer instead of strcpy, so we have to keep a local screen copy then printf */
|
||||
int tempTextOffset;
|
||||
|
||||
printf(GENERALTIME_VERSION"\n");
|
||||
|
||||
if(!pgeneralTimePvt)
|
||||
{/* GeneralTime is not used, we just report version then quit */
|
||||
printf("General time framework is not initialized yet!\n\n");
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
/* GeneralTime is in use, we try to report more detail */
|
||||
|
||||
/* we use sprintf instead of printf because we don't want to hold xxx_list_sem too long */
|
||||
|
||||
if(level>0)
|
||||
{
|
||||
printf("\nFor Time-Current-Provider:\n");
|
||||
epicsMutexMustLock( pgeneralTimePvt->tcp_list_sem );
|
||||
if(( items = ellCount( &(pgeneralTimePvt->tcp_list)) ))
|
||||
{
|
||||
ptempText = (char *)malloc(items * 80 * 3); /* for each provider, we print 3 lines, and each line is less then 80 bytes !!!!!!!! */
|
||||
if(!ptempText)
|
||||
{/* malloc failed */
|
||||
epicsMutexUnlock( pgeneralTimePvt->tcp_list_sem );
|
||||
printf("Malloced memory for print out for %d tcps failed!\n", items);
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
if(GENERALTIME_DEBUG) printf("Malloced memory for print out for %d tcps\n", items);
|
||||
|
||||
bzero(ptempText, items*80*3);
|
||||
tempTextOffset = 0;
|
||||
|
||||
for(ptcp=(TIME_CURRENT_PROVIDER *)ellFirst( &(pgeneralTimePvt->tcp_list) );
|
||||
ptcp; ptcp=(TIME_CURRENT_PROVIDER *)ellNext((ELLNODE *)ptcp))
|
||||
{
|
||||
tempTextOffset += sprintf(ptempText+tempTextOffset, "\t\"%s\",priority %d\n", ptcp->tp_desc, ptcp->tcp_priority);
|
||||
if(level>1)
|
||||
{
|
||||
tempTextOffset += sprintf( ptempText+tempTextOffset, "\t getCurrent is 0x%lx\n",
|
||||
(unsigned long)(ptcp->tcp_getCurrent) );
|
||||
if(ptcp->tcp_getCurrent)
|
||||
{
|
||||
status=(*(ptcp->tcp_getCurrent))(&tempTS);
|
||||
if(status!=epicsTimeERROR)
|
||||
{
|
||||
tempTSText[0]='\0';
|
||||
epicsTimeToStrftime(tempTSText, sizeof(tempTSText), "%Y/%m/%d %H:%M:%S.%06f",&tempTS);
|
||||
tempTextOffset += sprintf(ptempText+tempTextOffset, "\t Current Time is %s!\n", tempTSText);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempTextOffset += sprintf(ptempText+tempTextOffset, "\t Time Current Provider \"%s\" Failed!\n", ptcp->tp_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
epicsMutexUnlock( pgeneralTimePvt->tcp_list_sem );
|
||||
printf("%s", ptempText);
|
||||
free(ptempText);
|
||||
}
|
||||
else
|
||||
{
|
||||
epicsMutexUnlock( pgeneralTimePvt->tcp_list_sem );
|
||||
printf("\tNo Time-Current-Provider registered!\n");
|
||||
}
|
||||
|
||||
printf("For Time-Event-Provider:\n");
|
||||
epicsMutexMustLock( pgeneralTimePvt->tep_list_sem );
|
||||
if(( items = ellCount( &(pgeneralTimePvt->tep_list) ) ))
|
||||
{
|
||||
ptempText = (char *)malloc(items * 80 * 2); /* for each provider, we print 2 lines, and each line is less then 80 bytes !!!!!!!! */
|
||||
if(!ptempText)
|
||||
{/* malloc failed */
|
||||
epicsMutexUnlock( pgeneralTimePvt->tep_list_sem );
|
||||
printf("Malloced memory for print out for %d teps failed!\n", items);
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
if(GENERALTIME_DEBUG) printf("Malloced memory for print out for %d teps\n", items);
|
||||
|
||||
bzero(ptempText, items*80*2);
|
||||
tempTextOffset = 0;
|
||||
|
||||
for(ptep=(TIME_EVENT_PROVIDER *)ellFirst( &(pgeneralTimePvt->tep_list) );
|
||||
ptep; ptep=(TIME_EVENT_PROVIDER *)ellNext((ELLNODE *)ptep))
|
||||
{
|
||||
tempTextOffset += sprintf(ptempText+tempTextOffset,"\t\"%s\",priority %d\n",ptep->tp_desc,ptep->tep_priority);
|
||||
if(level>1)
|
||||
tempTextOffset += sprintf( ptempText+tempTextOffset, "\t getEvent is 0x%lx\n",(unsigned long)(ptep->tep_getEvent) );
|
||||
}
|
||||
epicsMutexUnlock( pgeneralTimePvt->tep_list_sem );
|
||||
printf("%s", ptempText);
|
||||
free(ptempText);
|
||||
}
|
||||
else
|
||||
{
|
||||
epicsMutexUnlock( pgeneralTimePvt->tep_list_sem );
|
||||
printf("\tNo Time-Event-Provider registered!\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following functions are accessors for various internal values, so that
|
||||
* they can be made available to device support. They are used by the
|
||||
* devGeneralTime.c file in <base>/src/dev/softDev which implements the
|
||||
* 'generalTime' DTYP for ai, bo, longin and stringin records
|
||||
*/
|
||||
|
||||
int generalTimeGetCurrentDouble(double * pseconds) /* for ai record, seconds from 01/01/1990 */
|
||||
{
|
||||
epicsTimeStamp ts;
|
||||
if(epicsTimeERROR!=epicsTimeGetCurrent(&ts))
|
||||
{
|
||||
*pseconds=ts.secPastEpoch+((double)(ts.nsec))*1e-9;
|
||||
return epicsTimeOK;
|
||||
}
|
||||
else
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
|
||||
void generalTimeResetErrorCounts() /* for bo record */
|
||||
{
|
||||
if(!pgeneralTimePvt)
|
||||
generalTime_Init();
|
||||
pgeneralTimePvt->ErrorCounts=0;
|
||||
}
|
||||
|
||||
int generalTimeGetErrorCounts() /* for longin record */
|
||||
{
|
||||
if(!pgeneralTimePvt)
|
||||
generalTime_Init();
|
||||
return pgeneralTimePvt->ErrorCounts;
|
||||
}
|
||||
|
||||
void generalTimeGetBestTcp(char * desc) /* for stringin record */
|
||||
{/* the assignment to pLastKnownBestTcp is atomic and desc is never changed after registeration */
|
||||
if(!pgeneralTimePvt)
|
||||
generalTime_Init();
|
||||
if(pgeneralTimePvt->pLastKnownBestTcp)
|
||||
{/* We know some good tcp */
|
||||
strncpy(desc,pgeneralTimePvt->pLastKnownBestTcp->tp_desc,TP_DESC_LEN-1);
|
||||
desc[TP_DESC_LEN-1]='\0';
|
||||
}
|
||||
else
|
||||
{/* no good tcp */
|
||||
strncpy(desc,"No Good Time-Current-Provider",TP_DESC_LEN-1);
|
||||
desc[TP_DESC_LEN-1]='\0';
|
||||
}
|
||||
}
|
||||
|
||||
void generalTimeGetBestTep(char * desc) /* for stringin record */
|
||||
{/* the assignment to pLastKnownBestTep is atomic and desc is never changed after registeration */
|
||||
if(!pgeneralTimePvt)
|
||||
generalTime_Init();
|
||||
if(pgeneralTimePvt->pLastKnownBestTep)
|
||||
{/* We know some good tep */
|
||||
strncpy(desc,pgeneralTimePvt->pLastKnownBestTep->tp_desc,TP_DESC_LEN-1);
|
||||
desc[TP_DESC_LEN-1]='\0';
|
||||
}
|
||||
else
|
||||
{/* no good tep */
|
||||
strncpy(desc,"No Good Time-Event-Provider",TP_DESC_LEN-1);
|
||||
desc[TP_DESC_LEN-1]='\0';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/***************************************************************************
|
||||
* File: epicsGeneralTime.h
|
||||
* Author: Sheng Peng
|
||||
* Institution: Oak Ridge National Laboratory / SNS Project
|
||||
* Date: 07/2004
|
||||
* Version: 1.2
|
||||
*
|
||||
* general EPICS timestamp support API
|
||||
* This is the interface to generalTime for all "users", rather than
|
||||
* Time Providers.
|
||||
*
|
||||
* Integration into EPICS Base by Peter Denison, Diamond Light Source
|
||||
*
|
||||
* Copyright (c) 2008 Diamond Light Source Ltd
|
||||
* Copyright (c) 2004 Oak Ridge National Laboratory
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
****************************************************************************/
|
||||
#ifndef _INC_epicsGeneralTime
|
||||
#define _INC_epicsGeneralTime
|
||||
|
||||
#include <epicsTime.h>
|
||||
#include <epicsTimer.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void generalTime_Init(void); /* this is the init routine you can call explicitly in st.cmd */
|
||||
int lastResortEventProviderInstall(void);
|
||||
int generalTimeGetCurrentDouble(double * pseconds); /* for ai record, seconds from 01/01/1990 */
|
||||
void generalTimeResetErrorCounts(); /* for bo record */
|
||||
int generalTimeGetErrorCounts(); /* for longin record */
|
||||
void generalTimeGetBestTcp(char * desc); /* for stringin record */
|
||||
void generalTimeGetBestTep(char * desc); /* for stringin record */
|
||||
|
||||
long generalTimeReport(int interest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -52,7 +52,6 @@ static const unsigned nSecFracDigits = 9u;
|
||||
|
||||
// Timescale conversion data
|
||||
|
||||
static const unsigned int POSIX_TIME_AT_EPICS_EPOCH = 631152000u;
|
||||
static const unsigned long NTP_TIME_AT_POSIX_EPOCH = 2208988800ul;
|
||||
static const unsigned long NTP_TIME_AT_EPICS_EPOCH =
|
||||
NTP_TIME_AT_POSIX_EPOCH + POSIX_TIME_AT_EPICS_EPOCH;
|
||||
@@ -87,7 +86,12 @@ epicsTimeLoadTimeInit::epicsTimeLoadTimeInit ()
|
||||
time_t t_one = static_cast<time_t> (1);
|
||||
this->time_tSecPerTick = difftime (t_one, t_zero);
|
||||
|
||||
/* Convert our epoch offset into time_t units */
|
||||
/* The EPICS epoch (1/1/1990 00:00:00UTC) was 631152000 seconds after
|
||||
* the ANSI epoch (1/1/1970 00:00:00UTC)
|
||||
* Convert this offset into time_t units, however this must not be
|
||||
* calculated using local time (i.e. using mktime() or similar), since
|
||||
* in the UK the ANSI Epoch had daylight saving time in effect, and
|
||||
* the value calculated would be 3600 seconds wrong.*/
|
||||
this->epicsEpochOffset =
|
||||
(double) POSIX_TIME_AT_EPICS_EPOCH / this->time_tSecPerTick;
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
#include "epicsTypes.h"
|
||||
#include "osdTime.h"
|
||||
|
||||
/* The EPICS Epoch is 00:00:00 Jan 1, 1990 UTC */
|
||||
#define POSIX_TIME_AT_EPICS_EPOCH 631152000u
|
||||
|
||||
/* epics time stamp for C interface*/
|
||||
typedef struct epicsTimeStamp {
|
||||
epicsUInt32 secPastEpoch; /* seconds since 0000 Jan 1, 1990 */
|
||||
@@ -182,10 +185,14 @@ extern "C" {
|
||||
#define epicsTimeEventBestTime -1
|
||||
#define epicsTimeEventDeviceTime -2
|
||||
|
||||
/* These are now provided by the "generalTime" framework */
|
||||
epicsShareFunc int epicsShareAPI epicsTimeGetCurrent ( epicsTimeStamp * pDest );
|
||||
epicsShareFunc int epicsShareAPI epicsTimeGetEvent (
|
||||
epicsTimeStamp *pDest, int eventNumber);
|
||||
|
||||
/* Provide a way of initialising the Time Provider of "last resort" */
|
||||
epicsShareFunc int epicsShareAPI osdTimeInit ( void );
|
||||
|
||||
/* convert to and from ANSI C's "time_t" */
|
||||
epicsShareFunc int epicsShareAPI epicsTimeToTime_t (
|
||||
time_t * pDest, const epicsTimeStamp * pSrc );
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/***************************************************************************
|
||||
* File: generalTimeSup.h
|
||||
* Author: Peter Denison
|
||||
* Institution: Diamond Light Source
|
||||
* Date: 04/2008
|
||||
* Version: 1.1
|
||||
*
|
||||
* support for general EPICS timestamp support
|
||||
*
|
||||
* This file should be included by Time Providers and contains the
|
||||
* interface to the "lower" side of the generalTime framework
|
||||
*
|
||||
* Copyright (c) 2008 Diamond Light Source Ltd
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*************************************************************************/
|
||||
#ifndef generalTimeSuphInclude
|
||||
#define generalTimeSuphInclude
|
||||
|
||||
#define LAST_RESORT_PRIORITY 999
|
||||
#include <epicsTimer.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int (*pepicsTimeGetCurrent)(epicsTimeStamp *pDest);
|
||||
typedef int (*pepicsTimeGetEvent)(epicsTimeStamp *pDest,int eventNumber);
|
||||
|
||||
int generalTimeCurrentTpRegister(const char * desc, int priority, pepicsTimeGetCurrent getCurrent);
|
||||
int generalTimeEventTpRegister(const char * desc, int priority, pepicsTimeGetEvent getEvent);
|
||||
int generalTimeGetExceptPriority(epicsTimeStamp *pDest, int * pPriority, int except_tcp);
|
||||
epicsTimerId generalTimeCreateSyncTimer(epicsTimerCallback cb, void *param);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*generalTimeSuphInclude*/
|
||||
@@ -1,198 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* 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 */
|
||||
/*l Modified by Eric Norum to work with RTEMS */
|
||||
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <rtems.h>
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsTime.h>
|
||||
#include <cantProceed.h>
|
||||
#include <iocClock.h>
|
||||
#include <errlog.h>
|
||||
|
||||
#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;
|
||||
|
||||
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;
|
||||
extern int rtems_bsdnet_get_ntp(int, int(*)(), struct timespec *);
|
||||
if(!firstTime)epicsThreadSleep(iocClockSyncRate);
|
||||
firstTime = 0;
|
||||
if(piocClockPvt->getCurrent != iocClockGetCurrent) {
|
||||
errlogPrintf("syncNTP: NTP client terminating.\n");
|
||||
return;
|
||||
}
|
||||
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 = 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)
|
||||
{
|
||||
if(piocClockPvt)
|
||||
printf("iocClockRegister: iocClock already initialized -- overriding\n");
|
||||
else
|
||||
piocClockPvt = callocMustSucceed(1,sizeof(iocClockPvt),"iocClockRegister");
|
||||
piocClockPvt->getCurrent = getCurrent;
|
||||
piocClockPvt->getEvent = getEvent;
|
||||
}
|
||||
|
||||
int iocClockGetCurrent(epicsTimeStamp *pDest)
|
||||
{
|
||||
unsigned long currentTick,nticks,nsecs;
|
||||
|
||||
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 = piocClockPvt->clock;
|
||||
epicsMutexUnlock(piocClockPvt->lock);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int iocClockGetEvent(epicsTimeStamp *pDest, int eventNumber)
|
||||
{
|
||||
if (eventNumber==epicsTimeEventCurrentTime) {
|
||||
*pDest = piocClockPvt->clock;
|
||||
return(0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* 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.h */
|
||||
|
||||
/* Author: Marty Kraimer Date: 16JUN2000 */
|
||||
|
||||
#include "epicsTime.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int (*pepicsTimeGetCurrent)(epicsTimeStamp *pDest);
|
||||
typedef int (*pepicsTimeGetEvent)(epicsTimeStamp *pDest,int eventNumber);
|
||||
|
||||
void iocClockInit(void);
|
||||
void iocClockRegister(pepicsTimeGetCurrent getCurrent,pepicsTimeGetEvent getEvent);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -11,24 +11,43 @@
|
||||
*/
|
||||
//
|
||||
|
||||
/*
|
||||
* ANSI C
|
||||
*/
|
||||
#include <time.h>
|
||||
/*#include <limits.h>*/
|
||||
#include "epicsTime.h"
|
||||
#include "osiNTPTime.h"
|
||||
#include "osdSysTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
/*
|
||||
* RTEMS
|
||||
#include <rtems.h>
|
||||
*/
|
||||
extern int rtems_bsdnet_get_ntp(int, int(*)(), struct timespec *);
|
||||
|
||||
/*
|
||||
* EPICS
|
||||
*/
|
||||
#define epicsExportSharedSymbols
|
||||
#include <epicsTime.h>
|
||||
extern "C" epicsShareFunc int epicsShareAPI osdTimeInit(void)
|
||||
{
|
||||
NTPTime_Init(100); /* init NTP first so it can be used to sync VW */
|
||||
SysTime_Init(LAST_RESORT_PRIORITY);
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int osdNTPGet(struct timespec *ts)
|
||||
{
|
||||
return rtems_bsdnet_get_ntp(-1, NULL, ts);
|
||||
}
|
||||
|
||||
void osdNTPInit(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
tickGet(void)
|
||||
{
|
||||
rtems_interval t;
|
||||
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &t);
|
||||
return t;
|
||||
}
|
||||
|
||||
int sysClkRateGet(void)
|
||||
{
|
||||
rtems_interval t;
|
||||
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &t);
|
||||
return t;
|
||||
}
|
||||
|
||||
int epicsTime_gmtime ( const time_t *pAnsiTime, struct tm *pTM )
|
||||
{
|
||||
@@ -51,5 +70,3 @@ int epicsTime_localtime ( const time_t *clock, struct tm *result )
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -16,6 +16,16 @@
|
||||
#ifndef osdTimeh
|
||||
#define osdTimeh
|
||||
|
||||
/* NOOP */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int osdNTPGet(struct timespec *);
|
||||
void osdNTPInit(void);
|
||||
int sysClkRateGet(void);
|
||||
int tickGet(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* ifndef osdTimeh */
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
//
|
||||
// epicsTime::osdGetCurrent ()
|
||||
//
|
||||
extern "C" epicsShareFunc int epicsTimeGetCurrent (epicsTimeStamp *pDest)
|
||||
int osdTimeGetCurrent (epicsTimeStamp *pDest)
|
||||
{
|
||||
# if defined(CLOCK_REALTIME)
|
||||
struct timespec ts;
|
||||
@@ -45,15 +46,14 @@ extern "C" epicsShareFunc int epicsTimeGetCurrent (epicsTimeStamp *pDest)
|
||||
# endif
|
||||
}
|
||||
|
||||
//
|
||||
// epicsTimeGetEvent ()
|
||||
//
|
||||
extern "C" epicsShareFunc int epicsShareAPI epicsTimeGetEvent (epicsTimeStamp *pDest, int eventNumber)
|
||||
extern "C" epicsShareFunc int epicsShareAPI osdTimeInit (void)
|
||||
{
|
||||
if (eventNumber==epicsTimeEventCurrentTime) {
|
||||
return epicsTimeGetCurrent (pDest);
|
||||
}
|
||||
else {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
#if defined (CLOCK_REALTIME)
|
||||
const char name[] = "gettimeofday";
|
||||
#else
|
||||
const char name[] = "clock_gettime";
|
||||
#endif
|
||||
|
||||
generalTimeCurrentTpRegister(name, 150, osdTimeGetCurrent);
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
# define debugPrintf(argsInParen)
|
||||
#endif
|
||||
|
||||
static int osdTimeGetCurrent ( epicsTimeStamp *pDest );
|
||||
|
||||
// GNU seems to require that 64 bit constants have LL on
|
||||
// them. The borland compiler fails to compile constants
|
||||
// with the LL suffix. MS compiler doesnt care.
|
||||
@@ -91,7 +93,7 @@ static const LONGLONG ET_TICKS_PER_FT_TICK =
|
||||
//
|
||||
// osdTimeInit ()
|
||||
//
|
||||
static void osdTimeInit ( void * )
|
||||
extern "C" epicsShareFunc int epicsShareAPI osdTimeInit ( void )
|
||||
{
|
||||
static bool osdTimeInitSuccess = false;
|
||||
|
||||
@@ -103,15 +105,15 @@ static void osdTimeInit ( void * )
|
||||
// bypass recursion crowbar in epicsThreadOnce
|
||||
osdTimeOnceFlag = 1;
|
||||
pCurrentTime->startPLL ();
|
||||
generalTimeCurrentTpRegister("PerfCounter", 150, osdTimeGetCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// epicsTimeGetCurrent ()
|
||||
// osdTimeGetCurrent ()
|
||||
//
|
||||
extern "C" epicsShareFunc int epicsShareAPI epicsTimeGetCurrent ( epicsTimeStamp *pDest )
|
||||
static int osdTimeGetCurrent ( epicsTimeStamp *pDest )
|
||||
{
|
||||
epicsThreadOnce ( & osdTimeOnceFlag, osdTimeInit, 0 );
|
||||
if ( ! pCurrentTime ) {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
@@ -121,20 +123,6 @@ extern "C" epicsShareFunc int epicsShareAPI epicsTimeGetCurrent ( epicsTimeStamp
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
//
|
||||
// epicsTimeGetEvent ()
|
||||
//
|
||||
extern "C" epicsShareFunc int epicsShareAPI epicsTimeGetEvent
|
||||
( epicsTimeStamp *pDest, int eventNumber )
|
||||
{
|
||||
if ( eventNumber == epicsTimeEventCurrentTime ) {
|
||||
return epicsTimeGetCurrent ( pDest );
|
||||
}
|
||||
else {
|
||||
return epicsTimeERROR;
|
||||
}
|
||||
}
|
||||
|
||||
inline void UnixTimeToFileTime ( const time_t * pAnsiTime, LPFILETIME pft )
|
||||
{
|
||||
LONGLONG ll = Int32x32To64 ( *pAnsiTime, 10000000 ) + LL_CONSTANT(116444736000000000);
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/* Sheng Peng @ SNS ORNL 07/2004 */
|
||||
/* Peter Denison, Diamond Light Source, Apr 2008 */
|
||||
/* Eric Norum, Argonne National Labs, Apr 2008 */
|
||||
/* Version 1.3 */
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "epicsTypes.h"
|
||||
#include "cantProceed.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsExport.h"
|
||||
#include "epicsThread.h"
|
||||
#include "osdThread.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsTime.h"
|
||||
#include "envDefs.h"
|
||||
|
||||
#define BILLION 1000000000
|
||||
|
||||
#define SYS_TIME_DRV_VERSION "system Time Driver Version 1.3"
|
||||
#define SYNC_PERIOD 60.0
|
||||
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
static void SysTimeSyncTime(void *param);
|
||||
static int SysTimeGetCurrent(epicsTimeStamp *pDest);
|
||||
|
||||
long SysTime_Report(int level);
|
||||
|
||||
typedef struct SysTimePvt
|
||||
{
|
||||
int synced; /* if never synced, we can't use it */
|
||||
epicsMutexId lock;
|
||||
epicsTimeStamp lastReportedTS;
|
||||
epicsTimeStamp lastSyncedTS;
|
||||
struct timespec lastSyncedSysTime;
|
||||
int priority;
|
||||
int synced_priority;
|
||||
} SysTimePvt;
|
||||
|
||||
static SysTimePvt *pSysTimePvt = 0;
|
||||
|
||||
static void SysTimeSyncTime(void *param)
|
||||
{
|
||||
epicsTimeStamp now;
|
||||
struct timespec sys_time_now;
|
||||
|
||||
for (;;) {
|
||||
epicsThreadSleep(SYNC_PERIOD);
|
||||
/* Ask for the best time available, not including ourselves */
|
||||
if (generalTimeGetExceptPriority(&now, &pSysTimePvt->synced_priority,
|
||||
pSysTimePvt->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, &sys_time_now);
|
||||
|
||||
epicsMutexMustLock(pSysTimePvt->lock);
|
||||
pSysTimePvt->lastSyncedTS = now;
|
||||
pSysTimePvt->lastSyncedSysTime = sys_time_now;
|
||||
pSysTimePvt->synced = 1;
|
||||
epicsMutexUnlock(pSysTimePvt->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long SysTime_InitOnce(int priority)
|
||||
{
|
||||
pSysTimePvt = callocMustSucceed(1, sizeof(SysTimePvt), "SysTime_Init");
|
||||
pSysTimePvt->synced = 0;
|
||||
pSysTimePvt->lock = epicsMutexCreate();
|
||||
pSysTimePvt->priority = priority;
|
||||
|
||||
/* register to link list */
|
||||
generalTimeCurrentTpRegister("system Time", priority, SysTimeGetCurrent);
|
||||
|
||||
/* Create the synchronization thread */
|
||||
epicsThreadCreate("System Time Sync", epicsThreadPriorityLow,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall), SysTimeSyncTime,
|
||||
NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct InitInfo
|
||||
{
|
||||
int priority;
|
||||
long retval;
|
||||
};
|
||||
static void SysTime_InitOnceWrapper(void *arg)
|
||||
{
|
||||
struct InitInfo *pargs = (struct InitInfo *)arg;
|
||||
pargs->retval = SysTime_InitOnce(pargs->priority);
|
||||
}
|
||||
|
||||
long SysTime_Init(int priority)
|
||||
{
|
||||
struct InitInfo args;
|
||||
static epicsThreadOnceId onceId= EPICS_THREAD_ONCE_INIT;
|
||||
|
||||
args.priority = priority;
|
||||
epicsThreadOnce(&onceId, SysTime_InitOnceWrapper, &args);
|
||||
return args.retval;
|
||||
}
|
||||
|
||||
static int SysTimeGetCurrent(epicsTimeStamp *pDest)
|
||||
{
|
||||
struct timespec cur_systime;
|
||||
unsigned long diff_sec, diff_nsec;
|
||||
epicsTimeStamp epicsTime;
|
||||
|
||||
double diffTime;
|
||||
|
||||
epicsMutexMustLock(pSysTimePvt->lock);
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &cur_systime);
|
||||
|
||||
if (!pSysTimePvt->synced) {
|
||||
if (cur_systime.tv_sec < POSIX_TIME_AT_EPICS_EPOCH) { /* Earlier than 1990 is clearly wrong. Set the time to 1/1/90
|
||||
+ 1 day (to avoid timezone problems) and set the SysWorks
|
||||
clock to that point */
|
||||
cur_systime.tv_sec = POSIX_TIME_AT_EPICS_EPOCH + 86400;
|
||||
cur_systime.tv_nsec = 0;
|
||||
clock_settime(CLOCK_REALTIME, &cur_systime);
|
||||
printf("****************************"
|
||||
"***************************************************\n"
|
||||
"WARNING: System time not set. Initialised to 2/1/90\n"
|
||||
"*****************************************************"
|
||||
"**************************\n");
|
||||
}
|
||||
epicsTimeFromTimespec(&epicsTime, &cur_systime);
|
||||
}
|
||||
else/* synced, need calculation */
|
||||
{/* the system time is always monotonic */
|
||||
if (cur_systime.tv_nsec >= pSysTimePvt->lastSyncedSysTime.tv_nsec) {
|
||||
diff_sec = cur_systime.tv_sec
|
||||
- pSysTimePvt->lastSyncedSysTime.tv_sec;
|
||||
diff_nsec = cur_systime.tv_nsec
|
||||
- pSysTimePvt->lastSyncedSysTime.tv_nsec;
|
||||
} else {
|
||||
diff_sec = cur_systime.tv_sec
|
||||
- pSysTimePvt->lastSyncedSysTime.tv_sec - 1;
|
||||
diff_nsec
|
||||
= BILLION - pSysTimePvt->lastSyncedSysTime.tv_nsec + cur_systime.tv_nsec;
|
||||
}
|
||||
|
||||
epicsTime.nsec = pSysTimePvt->lastSyncedTS.nsec + diff_nsec;
|
||||
epicsTime.secPastEpoch = pSysTimePvt->lastSyncedTS.secPastEpoch
|
||||
+ diff_sec;
|
||||
if (epicsTime.nsec >= BILLION) {
|
||||
epicsTime.nsec -= BILLION;
|
||||
epicsTime.secPastEpoch ++;
|
||||
}
|
||||
}
|
||||
|
||||
diffTime = epicsTimeDiffInSeconds(&epicsTime, &pSysTimePvt->lastReportedTS);
|
||||
if (diffTime >= 0.0) {/* time is monotonic */
|
||||
*pDest = epicsTime;
|
||||
pSysTimePvt->lastReportedTS = epicsTime;
|
||||
} else {/* time never goes back */
|
||||
*pDest = pSysTimePvt->lastReportedTS;
|
||||
}
|
||||
|
||||
epicsMutexUnlock(pSysTimePvt->lock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
long SysTime_Report(int level)
|
||||
{
|
||||
printf(SYS_TIME_DRV_VERSION"\n");
|
||||
|
||||
if (!pSysTimePvt) {/* drvSysTime is not used, we just report version then quit */
|
||||
printf("system time driver is not initialized yet!\n\n");
|
||||
} else {
|
||||
printf("%synced to %d. Last time = %lds, %ldns. ",
|
||||
pSysTimePvt->synced ? "S" : "Not s",
|
||||
pSysTimePvt->synced_priority,
|
||||
pSysTimePvt->lastSyncedSysTime.tv_sec,
|
||||
pSysTimePvt->lastSyncedSysTime.tv_nsec);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _INC_drvSysTime
|
||||
#define _INC_drvSysTime
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
long SysTime_Init(int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -23,12 +23,12 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsTime.h"
|
||||
|
||||
#include "generalTimeSup.h"
|
||||
|
||||
//
|
||||
// epicsTime::osdGetCurrent ()
|
||||
//
|
||||
extern "C" epicsShareFunc int epicsShareAPI epicsTimeGetCurrent (epicsTimeStamp *pDest)
|
||||
extern "C" epicsShareFunc int epicsShareAPI osdTimeGetCurrent (epicsTimeStamp *pDest)
|
||||
{
|
||||
# ifdef CLOCK_REALTIME
|
||||
struct timespec ts;
|
||||
@@ -55,15 +55,9 @@ extern "C" epicsShareFunc int epicsShareAPI epicsTimeGetCurrent (epicsTimeStamp
|
||||
# endif
|
||||
}
|
||||
|
||||
//
|
||||
// epicsTimeGetEvent ()
|
||||
//
|
||||
extern "C" epicsShareFunc int epicsShareAPI epicsTimeGetEvent (epicsTimeStamp *pDest, int eventNumber)
|
||||
extern "C" epicsShareFunc int epicsShareAPI osdTimeInit(void)
|
||||
{
|
||||
if (eventNumber==epicsTimeEventCurrentTime) {
|
||||
return epicsTimeGetCurrent (pDest);
|
||||
}
|
||||
return epicsTimeERROR;
|
||||
return generalTimeCurrentTpRegister("posix Time", 100, osdTimeGetCurrent);
|
||||
}
|
||||
|
||||
int epicsTime_gmtime ( const time_t *pAnsiTime, // X aCC 361
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* 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 */
|
||||
|
||||
#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 <sntpcLib.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <envLib.h>
|
||||
|
||||
#include "epicsTypes.h"
|
||||
#include "cantProceed.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsTime.h"
|
||||
#include "iocClock.h"
|
||||
#include "envDefs.h"
|
||||
|
||||
#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;
|
||||
const char *pserverAddr;
|
||||
}iocClockPvt;
|
||||
static iocClockPvt *piocClockPvt = 0;
|
||||
static int nConsecutiveBad = 0;
|
||||
|
||||
extern char* sysBootLine;
|
||||
|
||||
static void syncNTP(void)
|
||||
{
|
||||
struct timespec Currtime;
|
||||
epicsTimeStamp epicsTime;
|
||||
STATUS status;
|
||||
int prevStatusBad = 0;
|
||||
int firstTime=1;
|
||||
|
||||
while(1) {
|
||||
double diffTime;
|
||||
if(!firstTime)epicsThreadSleep(iocClockSyncRate);
|
||||
firstTime = 0;
|
||||
status = sntpcTimeGet((char *)piocClockPvt->pserverAddr,
|
||||
piocClockPvt->tickRate,&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 = callocMustSucceed(1,sizeof(iocClockPvt),"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 */
|
||||
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);
|
||||
piocClockPvt->pserverAddr = host_addr;
|
||||
}
|
||||
if(!piocClockPvt->pserverAddr) {
|
||||
errlogPrintf("No NTP server is defined. Clock does not work\n");
|
||||
return;
|
||||
}
|
||||
/* if TIMEZONE not defined, set it from EPICS_TIMEZONE */
|
||||
if (getenv("TIMEZONE") == NULL) {
|
||||
const char *timezone = envGetConfigParamPtr(&EPICS_TIMEZONE);
|
||||
if(timezone == NULL) {
|
||||
printf("iocClockInit: No Time Zone Information\n");
|
||||
} else {
|
||||
char envtimezone[100];
|
||||
sprintf(envtimezone,"TIMEZONE=%s",timezone);
|
||||
if(putenv(envtimezone)==ERROR) {
|
||||
printf("iocClockInit: TIMEZONE putenv failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
epicsThreadCreate("syncNTP",
|
||||
epicsThreadPriorityHigh,
|
||||
epicsThreadGetStackSize(epicsThreadStackSmall),
|
||||
(EPICSTHREADFUNC)syncNTP,0);
|
||||
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;
|
||||
|
||||
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 = piocClockPvt->clock;
|
||||
epicsMutexUnlock(piocClockPvt->lock);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int iocClockGetEvent(epicsTimeStamp *pDest, int eventNumber)
|
||||
{
|
||||
if (eventNumber==epicsTimeEventCurrentTime) {
|
||||
*pDest = piocClockPvt->clock;
|
||||
return(0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* 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.h */
|
||||
|
||||
/* Author: Marty Kraimer Date: 16JUN2000 */
|
||||
|
||||
#include "epicsTime.h"
|
||||
|
||||
typedef int (*pepicsTimeGetCurrent)(epicsTimeStamp *pDest);
|
||||
typedef int (*pepicsTimeGetEvent)(epicsTimeStamp *pDest,int eventNumber);
|
||||
|
||||
void iocClockInit(void);
|
||||
void iocClockRegister(pepicsTimeGetCurrent getCurrent,pepicsTimeGetEvent getEvent);
|
||||
@@ -8,9 +8,48 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include "epicsTime.h"
|
||||
#include <tickLib.h>
|
||||
#include <sysLib.h>
|
||||
#include <sntpcLib.h>
|
||||
#include <string.h>
|
||||
|
||||
// epicsTimeGetCurrent and epicsTimeGetEvent are implemented in iocClock.c
|
||||
#include "epicsTime.h"
|
||||
#include "errlog.h"
|
||||
#include "osiNTPTime.h"
|
||||
#include "osdSysTime.h"
|
||||
#include "generalTimeSup.h"
|
||||
#include "envDefs.h"
|
||||
|
||||
const char *pserverAddr = NULL;
|
||||
extern char* sysBootLine;
|
||||
|
||||
extern "C" epicsShareFunc int epicsShareAPI osdTimeInit(void)
|
||||
{
|
||||
NTPTime_Init(100); /* init NTP first so it can be used to sync VW */
|
||||
SysTime_Init(LAST_RESORT_PRIORITY);
|
||||
return epicsTimeOK;
|
||||
}
|
||||
|
||||
int osdNTPGet(struct timespec *ts)
|
||||
{
|
||||
return sntpcTimeGet((char *)pserverAddr, sysClkRateGet() ,ts);
|
||||
}
|
||||
|
||||
void osdNTPInit(void)
|
||||
{
|
||||
pserverAddr = envGetConfigParamPtr(&EPICS_TS_NTP_INET);
|
||||
if(!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);
|
||||
pserverAddr = host_addr;
|
||||
}
|
||||
if(!pserverAddr) {
|
||||
errlogPrintf("No NTP server is defined. Clock does not work\n");
|
||||
}
|
||||
}
|
||||
|
||||
// vxWorks localtime_r interface does not match POSIX standards
|
||||
int epicsTime_localtime ( const time_t *clock, struct tm *result )
|
||||
|
||||
@@ -9,3 +9,21 @@
|
||||
\*************************************************************************/
|
||||
/* Following needed for struct timeval */
|
||||
#include <sys/times.h>
|
||||
|
||||
#ifndef osdTimeh
|
||||
#define osdTimeh
|
||||
|
||||
#include <tickLib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int osdNTPGet(struct timespec *);
|
||||
void osdNTPInit(void);
|
||||
int sysClkRateGet(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* ifndef osdTimeh */
|
||||
|
||||
@@ -17,16 +17,12 @@
|
||||
* modules top be loaded
|
||||
*/
|
||||
|
||||
extern void iocClockInit(void);
|
||||
#include "epicsDynLink.h"
|
||||
extern int logMsgToErrlog(void);
|
||||
extern int veclist(int);
|
||||
|
||||
void vxComLibrary(int callit)
|
||||
{
|
||||
|
||||
|
||||
if(callit) iocClockInit();
|
||||
if(callit) symFindByNameEPICS(0,0,0,0);
|
||||
if(callit) logMsgToErrlog();
|
||||
if(callit) veclist(0);
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
|
||||
/* 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.3 */
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "epicsTypes.h"
|
||||
#include "cantProceed.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "epicsTime.h"
|
||||
#include "envDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "generalTimeSup.h"
|
||||
#include "osdTime.h"
|
||||
|
||||
#define BILLION 1000000000
|
||||
#define NTPTimeSyncInterval 10.0
|
||||
|
||||
#define NTPTIME_DRV_VERSION "NTPTime Driver Version 1.3"
|
||||
|
||||
#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;
|
||||
}NTPTimePvt;
|
||||
static NTPTimePvt *pNTPTimePvt = 0;
|
||||
static int nConsecutiveBad = 0;
|
||||
|
||||
static void NTPTimeSyncNTP(void)
|
||||
{
|
||||
struct timespec Currtime;
|
||||
epicsTimeStamp epicsTime;
|
||||
int status;
|
||||
int prevStatusBad = 0;
|
||||
|
||||
while(1) {
|
||||
double diffTime;
|
||||
epicsThreadSleep(NTPTimeSyncInterval);
|
||||
pNTPTimePvt->tickRate = sysClkRateGet();
|
||||
status = osdNTPGet(&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");
|
||||
|
||||
pNTPTimePvt->synced = FALSE;
|
||||
pNTPTimePvt->lock = epicsMutexCreate();
|
||||
pNTPTimePvt->nanosecondsPerTick = BILLION/sysClkRateGet();
|
||||
pNTPTimePvt->tickRate = sysClkRateGet();
|
||||
/* look first for environment variable or CONFIG_SITE_ENV default */
|
||||
osdNTPInit();
|
||||
/* 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 = osdNTPGet(&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("%synced.\n", pNTPTimePvt->synced?"S":"Not s");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _INC_drvDevNTPTime
|
||||
#define _INC_drvDevNTPTime
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
long NTPTime_Init(int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user