Files
pcas/src/libCom/osi/os/RTEMS/osdTime.cpp
T
2016-02-29 17:07:03 -06:00

171 lines
4.4 KiB
C++

/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* $Revision-Id$
*
* Author: W. Eric Norum
*/
#define __BSD_VISIBLE 1
#include <sys/types.h>
#include <sys/socket.h>
#include <epicsStdio.h>
#include <rtems.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <rtems/rtems_bsdnet_internal.h>
#include "epicsTime.h"
#include "osdTime.h"
#include "osiNTPTime.h"
#include "osiClockTime.h"
#include "generalTimeSup.h"
extern "C" {
extern rtems_interval rtemsTicksPerSecond;
int rtems_bsdnet_get_ntp(int, int(*)(), struct timespec *);
static int ntpSocket = -1;
void osdTimeRegister(void)
{
/* Init NTP first so it can be used to sync ClockTime */
NTPTime_Init(100);
ClockTime_Init(CLOCKTIME_SYNC);
}
int osdNTPGet(struct timespec *ts)
{
static unsigned bequiet;
ssize_t ret;
if (ntpSocket < 0)
return -1;
/* rtems_bsdnet_get_ntp() will send an NTP request, then
* call recvfrom() exactly once to process the expected reply.
* Any leftovers in the socket buffer (ie. duplicates of
* previous replies) will cause problems.
* So flush out the socket buffer first.
*/
do {
char junk[16];
ret = recvfrom(ntpSocket, junk, sizeof(junk), MSG_DONTWAIT, NULL, NULL);
if (ret == -1 && errno == EAGAIN) {
break;
}
else if (ret == -1) {
if (!bequiet) {
printf("osdNTPGet cleaner error: %s\n", strerror(errno));
bequiet = 1;
}
break;
}
else {
bequiet = 0;
}
} while (ret > 0);
return rtems_bsdnet_get_ntp(ntpSocket, NULL, ts);
}
void osdNTPInit(void)
{
struct sockaddr_in myAddr;
ntpSocket = socket (AF_INET, SOCK_DGRAM, 0);
if (ntpSocket < 0) {
printf("osdNTPInit() Can't create socket: %s\n", strerror (errno));
return;
}
memset (&myAddr, 0, sizeof myAddr);
myAddr.sin_family = AF_INET;
myAddr.sin_port = htons (0);
myAddr.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind (ntpSocket, (struct sockaddr *)&myAddr, sizeof myAddr) < 0) {
printf("osdNTPInit() Can't bind socket: %s\n", strerror (errno));
close (ntpSocket);
ntpSocket = -1;
}
}
void osdNTPReport(void)
{
}
int osdTickGet(void)
{
rtems_interval t;
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &t);
return t;
}
int osdTickRateGet(void)
{
return rtemsTicksPerSecond;
}
/*
* Use reentrant versions of time access
*/
int epicsTime_gmtime ( const time_t *pAnsiTime, struct tm *pTM )
{
struct tm * pRet = gmtime_r ( pAnsiTime, pTM );
if ( pRet ) {
return epicsTimeOK;
}
else {
return epicsTimeERROR;
}
}
int epicsTime_localtime ( const time_t *clock, struct tm *result )
{
struct tm * pRet = localtime_r ( clock, result );
if ( pRet ) {
return epicsTimeOK;
}
else {
return epicsTimeERROR;
}
}
rtems_interval rtemsTicksPerSecond;
double rtemsTicksPerSecond_double, rtemsTicksPerTwoSeconds_double;
} // extern "C"
/*
* Static constructors are run too early in a standalone binary
* to be able to initialize the NTP time provider (the network
* is not available yet), so the RTEMS standalone startup code
* explicitly calls osdTimeRegister() at the appropriate time.
* However if we are loaded dynamically we *do* register our
* standard time providers at static constructor time; in this
* case the network is available already.
*/
static int staticTimeRegister(void)
{
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &rtemsTicksPerSecond);
rtemsTicksPerSecond_double = rtemsTicksPerSecond;
rtemsTicksPerTwoSeconds_double = rtemsTicksPerSecond_double * 2.0;
/* If networking is already up at the time static constructors
* are executed then we are probably run-time loaded and it's
* OK to osdTimeRegister() at this point.
*/
if (rtems_bsdnet_ticks_per_second != 0)
osdTimeRegister();
return 1;
}
static int done = staticTimeRegister();