-
Notifications
You must be signed in to change notification settings - Fork 1
/
spec_ptp2ntpd.c
212 lines (184 loc) · 7.08 KB
/
spec_ptp2ntpd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <time.h>
#include <stdint.h> // uint_32
#include <sys/time.h> // gettimeofday()
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <inttypes.h> // for printing out 64-bit numbers
#include <time.h> /* time_t, struct tm, time, gmtime */
#include "speclib.h"
// Linux Daemon Writing HOWTO
// http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html
// NTP reflock
// http://www.eecis.udel.edu/~mills/ntp/html/drivers/driver28.html
// Configuring NTP with // /etc/ntpd.conf
// server 127.127.t.u minpoll 4 maxpoll 4
// t = 28 (shared memory reflock)
// u = 0 (unique id)
// fudge time1 t1 time2 t2 stratum str refid string flag1 0/1 flag2 0/1 flag3 0/1 flag4 0/1
/* this is the struct NTP expects to see in shared memory */
struct shmTime {
int mode; /* 0 - if valid is set:
* use values,
* clear valid
* 1 - if valid is set:
* if count before and after read of data is equal:
* use values
* clear valid
*/
volatile int count; // mode0: NTP bumps count each time it reads
time_t clockTimeStampSec;
int clockTimeStampUSec;
time_t receiveTimeStampSec;
int receiveTimeStampUSec;
int leap;
int precision;
int nsamples;
volatile int valid; // set valid once timestamps updated
unsigned clockTimeStampNSec; /* Unsigned ns timestamps */
unsigned receiveTimeStampNSec; /* Unsigned ns timestamps */
int dummy[8];
};
struct shmTime* T;
/* from NTP shm reflock code */
struct shmTime *getShmTime (int unit) {
int shmid=0;
/* 0x4e545030 is NTP0.
* Big units will give non-ascii but that's OK
* as long as everybody does it the same way.
*/
shmid=shmget (0x4e545030+unit, sizeof (struct shmTime), IPC_CREAT|(unit<2?0600:0666));
if (shmid==-1) { /*error */
syslog(LOG_ERR,"SHM shmget (unit %d): %s",unit,strerror(errno));
return 0;
}
else { /* no error */
struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0);
if ((int)(long)p==-1) { /* error */
syslog(LOG_ERR,"SHM shmat (unit %d): %s",unit,strerror(errno));
return 0;
}
return p;
}
}
/* read from SPEC shared memory */
uint32_t read_mem(void *base, uint32_t offset) {
uint32_t *ptr;
ptr = base + 0x20300 + offset;
return *ptr;
}
/* based on minimal daemon code from the daemon-HOWTO */
int main(void) {
/* Our process ID and Session ID */
pid_t pid, sid;
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
}
/* Change the file mode mask */
umask(0);
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
//syslog(LOG_ERR,"setsid() error. EXIT.");
exit(EXIT_FAILURE);
}
/* Change the current working directory */
if ((chdir("/")) < 0) {
/* Log the failure */
//syslog(LOG_ERR,"chdir() error. EXIT.");
exit(EXIT_FAILURE);
}
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/* Daemon-specific initialization goes here */
/* use syslog */
setlogmask (LOG_UPTO (LOG_NOTICE));
openlog ("spec_ptp2ntpd", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
syslog (LOG_NOTICE, "Program started by User %d", getuid());
// Attach to SPEC shared memory
int bar = BASE_BAR0;
int bus = -1, dev_fn = -1;
void *card;
void *map_base;
card = spec_open(bus, dev_fn);
if(!card)
{
syslog(LOG_ERR, "Can't detect a SPEC card under the given "
"adress. Make sure a SPEC card is present in your PC, "
"the driver is loaded and you run the program as root. EXIT.\n");
exit(1);
}
syslog(LOG_NOTICE,"Found SPEC at %x \n",(uint)card);
map_base = spec_get_base(card, bar);
if(!map_base || map_base == (void *) -1) {
syslog(LOG_ERR,"mmap(/dev/mem): %s. EXIT.\n", strerror(errno));
syslog(LOG_ERR, "map_base = %x \n",(uint)map_base);
exit(1);
}
syslog(LOG_NOTICE,"map_base = %u \n",(uint)map_base);
syslog (LOG_NOTICE, "Attached to SPEC SHM at %x", (uint)map_base);
// attach to NTP shared memory
T = getShmTime(0);
if (T==0) { /* error */
syslog(LOG_ERR,"getShmTime() error");
syslog(LOG_ERR,"EXITING.");
exit(EXIT_FAILURE);
} else {
syslog (LOG_NOTICE, "Attached to NTP SHM at %x", (uint)T);
}
// initialize
T->mode=1; // does it matter? set here or by NTP?
T->leap=0; // ?
T->precision=-10; //?
T->nsamples=10; // ?
shmdt(T); //detach
struct timeval tv;
uint32_t nsec_cycles, s_lsb, usecs;
double cycle = 1/125e6;
uint32_t nsecs;
/* The Big Loop */
while (1) {
T = getShmTime(0); // attach to shared memory
gettimeofday(&tv,NULL); // system time-stamp
// WR time
nsec_cycles = read_mem(map_base, 4 ); // read nanoseconds, in number of 62.5MHz ref cycles
nsecs = (uint32_t) (cycle*nsec_cycles*1e9);
usecs = (uint32_t) (cycle*nsec_cycles*1e6);
s_lsb = read_mem(map_base, 8 ); // read utc lsb
//s_msb = read_mem(map_base, 12 ); // read utc msb
// clock time
T->clockTimeStampSec = s_lsb;
T->clockTimeStampUSec = usecs; // offset 4 msec, just for fun
T->clockTimeStampNSec = nsecs;
// time stamp
T->receiveTimeStampSec = tv.tv_sec;
T->receiveTimeStampUSec = tv.tv_usec;
T->receiveTimeStampNSec = tv.tv_usec*1000;
T->valid = 1;
T->count += 1;
shmdt(T); // detach, required here?
syslog (LOG_NOTICE, "WR time is %d.%09d ", (int)s_lsb,(int)nsecs);
syslog (LOG_NOTICE, "system time is %d.%06d ", (int)tv.tv_sec,(int)tv.tv_usec);
sleep(8); // minpoll is 4, so NTP reads every 16s
}
spec_close(card);
closelog();
exit(EXIT_SUCCESS);
}