This is Unofficial EPICS BASE Doxygen Site
osdTime.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Saskatchewan
3 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
4 * National Laboratory.
5 * EPICS BASE is distributed subject to a Software License Agreement found
6 * in file LICENSE that is included with this distribution.
7 \*************************************************************************/
8 /*
9  * Author: W. Eric Norum
10  */
11 #define __BSD_VISIBLE 1
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 
15 #define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
16 #include <epicsStdio.h>
17 #include <rtems.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <rtems/rtems_bsdnet_internal.h>
24 #include "epicsTime.h"
25 #include "osdTime.h"
26 #include "osiNTPTime.h"
27 #include "osiClockTime.h"
28 #include "generalTimeSup.h"
29 
30 extern "C" {
31 
32 extern rtems_interval rtemsTicksPerSecond;
33 int rtems_bsdnet_get_ntp(int, int(*)(), struct timespec *);
34 static int ntpSocket = -1;
35 
36 void osdTimeRegister(void)
37 {
38  /* Init NTP first so it can be used to sync ClockTime */
39  NTPTime_Init(100);
41 
43 }
44 
45 int osdNTPGet(struct timespec *ts)
46 {
47  static unsigned bequiet;
48  ssize_t ret;
49 
50  if (ntpSocket < 0)
51  return -1;
52 
53  /* rtems_bsdnet_get_ntp() will send an NTP request, then
54  * call recvfrom() exactly once to process the expected reply.
55  * Any leftovers in the socket buffer (ie. duplicates of
56  * previous replies) will cause problems.
57  * So flush out the socket buffer first.
58  */
59  do {
60  char junk[16];
61 
62  ret = recvfrom(ntpSocket, junk, sizeof(junk), MSG_DONTWAIT, NULL, NULL);
63  if (ret == -1 && errno == EAGAIN) {
64  break;
65  }
66  else if (ret == -1) {
67  if (!bequiet) {
68  printf("osdNTPGet cleaner error: %s\n", strerror(errno));
69  bequiet = 1;
70  }
71  break;
72  }
73  else {
74  bequiet = 0;
75  }
76  } while (ret > 0);
77 
78  return rtems_bsdnet_get_ntp(ntpSocket, NULL, ts);
79 }
80 
81 void osdNTPInit(void)
82 {
83  struct sockaddr_in myAddr;
84 
85  ntpSocket = socket (AF_INET, SOCK_DGRAM, 0);
86  if (ntpSocket < 0) {
87  printf("osdNTPInit() Can't create socket: %s\n", strerror (errno));
88  return;
89  }
90  memset (&myAddr, 0, sizeof myAddr);
91  myAddr.sin_family = AF_INET;
92  myAddr.sin_port = htons (0);
93  myAddr.sin_addr.s_addr = htonl (INADDR_ANY);
94  if (bind (ntpSocket, (struct sockaddr *)&myAddr, sizeof myAddr) < 0) {
95  printf("osdNTPInit() Can't bind socket: %s\n", strerror (errno));
96  close (ntpSocket);
97  ntpSocket = -1;
98  }
99 }
100 
101 void osdNTPReport(void)
102 {
103 }
104 
105 int osdTickGet(void)
106 {
107  rtems_interval t;
108  rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &t);
109  return t;
110 }
111 
112 int osdTickRateGet(void)
113 {
114  return rtemsTicksPerSecond;
115 }
116 
117 /*
118  * Use reentrant versions of time access
119  */
120 int epicsTime_gmtime ( const time_t *pAnsiTime, struct tm *pTM )
121 {
122  struct tm * pRet = gmtime_r ( pAnsiTime, pTM );
123  if ( pRet ) {
124  return epicsTimeOK;
125  }
126  else {
127  return errno;
128  }
129 }
130 
131 int epicsTime_localtime ( const time_t *clock, struct tm *result )
132 {
133  struct tm * pRet = localtime_r ( clock, result );
134  if ( pRet ) {
135  return epicsTimeOK;
136  }
137  else {
138  return errno;
139  }
140 }
141 
142 rtems_interval rtemsTicksPerSecond;
144 
145 } // extern "C"
146 
147 /*
148  * Static constructors are run too early in a standalone binary
149  * to be able to initialize the NTP time provider (the network
150  * is not available yet), so the RTEMS standalone startup code
151  * explicitly calls osdTimeRegister() at the appropriate time.
152  * However if we are loaded dynamically we *do* register our
153  * standard time providers at static constructor time; in this
154  * case the network is available already.
155  */
156 static int staticTimeRegister(void)
157 {
158  rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &rtemsTicksPerSecond);
161 
162  /* If networking is already up at the time static constructors
163  * are executed then we are probably run-time loaded and it's
164  * OK to osdTimeRegister() at this point.
165  */
166  if (rtems_bsdnet_ticks_per_second != 0)
167  osdTimeRegister();
168 
169  return 1;
170 }
171 static int done = staticTimeRegister();
int osdTickRateGet(void)
Definition: osdTime.cpp:112
pvac::PutEvent result
Definition: clientSync.cpp:117
int osdNTPGet(struct timespec *ts)
Definition: osdTime.cpp:45
void ClockTime_Init(int synchronize)
void osdNTPReport(void)
Definition: osdTime.cpp:101
double rtemsTicksPerTwoSeconds_double
Definition: osdTime.cpp:143
#define printf
Definition: epicsStdio.h:41
void osdMonotonicInit(void)
Definition: osdMonotonic.c:19
#define NULL
Definition: catime.c:38
#define epicsTimeOK
Success.
Definition: epicsTime.h:339
void osdTimeRegister(void)
Definition: osdTime.cpp:36
void NTPTime_Init(int priority)
Definition: osiNTPTime.c:121
int rtems_bsdnet_get_ntp(int, int(*)(), struct timespec *)
double rtemsTicksPerSecond_double
Definition: osdTime.cpp:143
#define CLOCKTIME_SYNC
Definition: osiClockTime.h:12
void osdNTPInit(void)
Definition: osdTime.cpp:81
Defined by POSIX Real Time.
Definition: osdTime.h:21
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
int epicsTime_gmtime(const time_t *pAnsiTime, struct tm *pTM)
Break down a time_t into a struct tm in the UTC timezone.
Definition: osdTime.cpp:55
int epicsTime_localtime(const time_t *clock, struct tm *result)
Break down a time_t into a struct tm in the local timezone.
Definition: osdTime.cpp:61
int osdTickGet(void)
Definition: osdTime.cpp:105
rtems_interval rtemsTicksPerSecond
Definition: osdTime.cpp:142