General Time, from Peter Denison, Eric Norum and many others...

This commit is contained in:
Andrew Johnson
2008-04-18 18:39:32 +00:00
parent b02f69092c
commit a3cd917de2
26 changed files with 1481 additions and 535 deletions
+1
View File
@@ -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
+262
View File
@@ -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;
}
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+527
View File
@@ -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';
}
}
+42
View File
@@ -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
+6 -2
View File
@@ -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;
+7
View File
@@ -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 );
+38
View File
@@ -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*/
-198
View File
@@ -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);
}
-28
View File
@@ -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
+34 -17
View File
@@ -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" */
+11 -1
View File
@@ -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 */
+11 -11
View File
@@ -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;
}
+6 -18
View File
@@ -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);
+185
View File
@@ -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;
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef _INC_drvSysTime
#define _INC_drvSysTime
#ifdef __cplusplus
extern "C" {
#endif
long SysTime_Init(int);
#ifdef __cplusplus
}
#endif
#endif
+4 -10
View File
@@ -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
-219
View File
@@ -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);
}
-20
View File
@@ -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);
+41 -2
View File
@@ -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 )
+18
View File
@@ -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 */
-4
View File
@@ -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);
+226
View File
@@ -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;
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef _INC_drvDevNTPTime
#define _INC_drvDevNTPTime
#ifdef __cplusplus
extern "C" {
#endif
long NTPTime_Init(int);
#ifdef __cplusplus
}
#endif
#endif