void ntpshm_init(struct gps_context_t *context, bool enablepps) /* attach all NTP SHM segments. called once at startup, while still root */ { int i; for (i = 0; i < NTPSHMSEGS; i++) context->shmTime[i] = getShmTime(i); memset(context->shmTimeInuse,0,sizeof(context->shmTimeInuse)); # ifdef PPS_ENABLE context->shmTimePPS = enablepps; # endif /* PPS_ENABLE */ context->enable_ntpshm = true; }
void ntpshm_context_init(struct gps_context_t *context) /* Attach all NTP SHM segments. Called once at startup, while still root. */ { int i; for (i = 0; i < NTPSHMSEGS; i++) { // Only grab the first two when running as root. if (2 <= i || 0 == getuid()) { context->shmTime[i] = getShmTime(context, i); } } memset(context->shmTimeInuse, 0, sizeof(context->shmTimeInuse)); }
void ntpshm_init(struct gps_context_t *context, bool enablepps UNUSED) #endif /* PPS_ENABLE */ /* Attach all NTP SHM segments. Called once at startup, while still root. */ { int i; for (i = 0; i < NTPSHMSEGS; i++) { // Only grab the first two when running as root. if (2 <= i || 0 == getuid()) { context->shmTime[i] = getShmTime(i); } } memset(context->shmTimeInuse, 0, sizeof(context->shmTimeInuse)); # ifdef PPS_ENABLE context->shmTimePPS = enablepps; # endif /* PPS_ENABLE */ context->enable_ntpshm = true; }
/* * shm_start - attach to shared memory */ static int shm_start( int unit, struct peer *peer ) { struct refclockproc * const pp = peer->procptr; struct shmunit * const up = emalloc_zero(sizeof(*up)); pp->io.clock_recv = noentry; pp->io.srcclock = peer; pp->io.datalen = 0; pp->io.fd = -1; up->forall = (unit >= 2) && !(peer->ttl & SHM_MODE_PRIVATE); up->shm = getShmTime(unit, up->forall); /* * Initialize miscellaneous peer variables */ memcpy((char *)&pp->refid, REFID, 4); if (up->shm != 0) { pp->unitptr = up; up->shm->precision = PRECISION; peer->precision = up->shm->precision; up->shm->valid = 0; up->shm->nsamples = NSAMPLES; pp->clockdesc = DESCRIPTION; /* items to be changed later in 'shm_control()': */ up->max_delay = 5; up->max_delta = 4*3600; return 1; } else { free(up); pp->unitptr = NULL; return 0; } }
int main ( int argc, char *argv[] ) { volatile struct shmTime *p=getShmTime(2); if (argc<=1) { printf ("usage: %s r[c][l]|w|snnn\n",argv[0]); printf (" r read shared memory\n"); printf (" c clear valid-flag\n"); printf (" l loop (so, rcl will read and clear in a loop\n"); printf (" w write shared memory with current time\n"); printf (" snnnn set nsamples to nnn\n"); printf (" lnnnn set leap to nnn\n"); printf (" pnnnn set precision to -nnn\n"); exit (0); } switch (argv[1][0]) { case 's': { p->nsamples=atoi(&argv[1][1]); } break; case 'l': { p->leap=atoi(&argv[1][1]); } break; case 'p': { p->precision=-atoi(&argv[1][1]); } break; case 'r': { char *ap=&argv[1][1]; int clear=0; int loop=0; printf ("reader\n"); while (*ap) { switch (*ap) { case 'l' : loop=1; break; case 'c' : clear=1; break; } ap++; } do { printf ("mode=%d, count=%d, clock=%d.%d, rec=%d.%d,\n", p->mode,p->count,p->clockTimeStampSec,p->clockTimeStampUSec, p->receiveTimeStampSec,p->receiveTimeStampUSec); printf (" leap=%d, precision=%d, nsamples=%d, valid=%d\n", p->leap, p->precision, p->nsamples, p->valid); if (!p->valid) printf ("***\n"); if (clear) { p->valid=0; printf ("cleared\n"); } if (loop) sleep (1); } while (loop); } break; case 'w': { printf ("writer\n"); p->mode=0; if (!p->valid) { p->clockTimeStampSec=time(0)-20; p->clockTimeStampUSec=0; p->receiveTimeStampSec=time(0)-1; p->receiveTimeStampUSec=0; printf ("%d %d\n",p->clockTimeStampSec, p->receiveTimeStampSec); p->valid=1; } else { printf ("p->valid still set\n"); /* not an error! */ } } break; } }
int main ( int argc, char *argv[] ) { volatile struct shmTime *p; int unit; char *argp; if (argc<=1) { usage: printf ("usage: %s [uu:]{r[c][l]|w|snnn}\n",argv[0]); printf (" uu use clock unit uu (default: 2)\n"); printf (" r read shared memory\n"); printf (" c clear valid-flag\n"); printf (" l loop (so, rcl will read and clear in a loop\n"); printf (" w write shared memory with current time\n"); printf (" snnnn set nsamples to nnn\n"); printf (" lnnnn set leap to nnn\n"); printf (" pnnnn set precision to -nnn\n"); exit (0); } srand(time(NULL)); unit = strtoul(argv[1], &argp, 10); if (argp == argv[1]) unit = 2; else if (*argp == ':') argp++; else goto usage; p=getShmTime(unit); switch (*argp) { case 's': p->nsamples=atoi(argp+1); break; case 'l': p->leap=atoi(argp+1); break; case 'p': p->precision=-atoi(argp+1); break; case 'r': { int clear=0; int loop=0; printf ("reader\n"); while (*++argp) { switch (*argp) { case 'l': loop=1; break; case 'c': clear=1; break; default : goto usage; } } again: printf ("mode=%d, count=%d, clock=%ld.%09u, rec=%ld.%09u,\n", p->mode,p->count, (long)p->clockTimeStampSec,p->clockTimeStampNSec, (long)p->receiveTimeStampSec,p->receiveTimeStampNSec); printf (" leap=%d, precision=%d, nsamples=%d, valid=%d\n", p->leap, p->precision, p->nsamples, p->valid); if (!p->valid) printf ("***\n"); if (clear) { p->valid=0; printf ("cleared\n"); } if (loop) { sleep (1); goto again; } break; } case 'w': { /* To show some life action, we read the system * clock and use a bit of fuzz from 'random()' to get a * bit of wobbling into the values (so we can observe a * certain jitter!) */ time_t clk_sec, rcv_sec; uint clk_frc, rcv_frc; #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) /* Here we have a high-resolution system clock, and * we're not afraid to use it! */ struct timespec tmptime; if (0 == clock_gettime(CLOCK_REALTIME, &tmptime)) { rcv_sec = tmptime.tv_sec; rcv_frc = (uint)tmptime.tv_nsec; } else #endif { time(&rcv_sec); rcv_frc = (uint)random() % 1000000000u; } /* add a wobble of ~3.5msec to the clock time */ clk_sec = rcv_sec; clk_frc = rcv_frc + (uint)(random()%7094713 - 3547356); /* normalise result -- the SHM driver is picky! */ while ((int)clk_frc < 0) { clk_frc += 1000000000; clk_sec -= 1; } while ((int)clk_frc >= 1000000000) { clk_frc -= 1000000000; clk_sec += 1; } /* Most 'real' time sources would create a clock * (reference) time stamp where the fraction is zero, * but that's not an actual requirement. So we show how * to deal with the time stamps in general; changing the * behaviour for cases where the fraction of the * clock time is zero should be trivial. */ printf ("writer\n"); p->mode=0; if (!p->valid) { p->clockTimeStampSec = clk_sec; p->clockTimeStampUSec = clk_frc / 1000; /* truncate! */ p->clockTimeStampNSec = clk_frc; p->receiveTimeStampSec = rcv_sec; p->receiveTimeStampUSec = rcv_frc / 1000; /* truncate! */ p->receiveTimeStampNSec = rcv_frc; printf ("%ld.%09u %ld.%09u\n", (long)p->clockTimeStampSec , p->clockTimeStampNSec , (long)p->receiveTimeStampSec, p->receiveTimeStampNSec); p->valid=1; } else { printf ("p->valid still set\n"); /* not an error! */ } break; } default: break; } return 0; }
/* * shm_timer - called once every second. * * This tries to grab a sample from the SHM segment, filtering bad ones */ static void shm_timer( int unit, struct peer *peer ) { struct refclockproc * const pp = peer->procptr; struct shmunit * const up = pp->unitptr; volatile struct shmTime *shm; l_fp tsrcv; l_fp tsref; int c; /* for formatting 'a_lastcode': */ struct calendar cd; time_t tt; vint64 ts; enum segstat_t status; struct shm_stat_t shm_stat; up->ticks++; if ((shm = up->shm) == NULL) { /* try to map again - this may succeed if meanwhile some- body has ipcrm'ed the old (unaccessible) shared mem segment */ shm = up->shm = getShmTime(unit, up->forall); if (shm == NULL) { DPRINTF(1, ("%s: no SHM segment\n", refnumtoa(&peer->srcadr))); return; } } /* query the segment, atomically */ status = shm_query(shm, &shm_stat); switch (status) { case OK: DPRINTF(2, ("%s: SHM type %d sample\n", refnumtoa(&peer->srcadr), shm_stat.mode)); break; case NO_SEGMENT: /* should never happen, but is harmless */ return; case NOT_READY: DPRINTF(1, ("%s: SHM not ready\n",refnumtoa(&peer->srcadr))); up->notready++; return; case BAD_MODE: DPRINTF(1, ("%s: SHM type blooper, mode=%d\n", refnumtoa(&peer->srcadr), shm->mode)); up->bad++; msyslog (LOG_ERR, "SHM: bad mode found in shared memory: %d", shm->mode); return; case CLASH: DPRINTF(1, ("%s: type 1 access clash\n", refnumtoa(&peer->srcadr))); msyslog (LOG_NOTICE, "SHM: access clash in shared memory"); up->clash++; return; default: DPRINTF(1, ("%s: internal error, unknown SHM fetch status\n", refnumtoa(&peer->srcadr))); msyslog (LOG_NOTICE, "internal error, unknown SHM fetch status"); up->bad++; return; } /* format the last time code in human-readable form into * 'pp->a_lastcode'. Someone claimed: "NetBSD has incompatible * tv_sec". I can't find a base for this claim, but we can work * around that potential problem. BTW, simply casting a pointer * is a receipe for disaster on some architectures. */ tt = (time_t)shm_stat.tvt.tv_sec; ts = time_to_vint64(&tt); ntpcal_time_to_date(&cd, &ts); /* add ntpq -c cv timecode in ISO 8601 format */ c = snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), "%04u-%02u-%02uT%02u:%02u:%02u.%09ldZ", cd.year, cd.month, cd.monthday, cd.hour, cd.minute, cd.second, (long)shm_stat.tvt.tv_nsec); pp->lencode = ((size_t)c < sizeof(pp->a_lastcode)) ? c : 0; /* check 1: age control of local time stamp */ tt = shm_stat.tvc.tv_sec - shm_stat.tvr.tv_sec; if (tt < 0 || tt > up->max_delay) { DPRINTF(1, ("%s:SHM stale/bad receive time, delay=%llds\n", refnumtoa(&peer->srcadr), (long long)tt)); up->bad++; msyslog (LOG_ERR, "SHM: stale/bad receive time, delay=%llds", (long long)tt); return; } /* check 2: delta check */ tt = shm_stat.tvr.tv_sec - shm_stat.tvt.tv_sec - (shm_stat.tvr.tv_nsec < shm_stat.tvt.tv_nsec); if (tt < 0) tt = -tt; if (up->max_delta > 0 && tt > up->max_delta) { DPRINTF(1, ("%s: SHM diff limit exceeded, delta=%llds\n", refnumtoa(&peer->srcadr), (long long)tt)); up->bad++; msyslog (LOG_ERR, "SHM: difference limit exceeded, delta=%llds\n", (long long)tt); return; } /* if we really made it to this point... we're winners! */ DPRINTF(2, ("%s: SHM feeding data\n", refnumtoa(&peer->srcadr))); tsrcv = tspec_stamp_to_lfp(shm_stat.tvr); tsref = tspec_stamp_to_lfp(shm_stat.tvt); pp->leap = shm_stat.leap; peer->precision = shm_stat.precision; refclock_process_offset(pp, tsref, tsrcv, pp->fudgetime1); up->good++; }
/* 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); }