162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PTP 1588 clock support - User space test program 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2010 OMICRON electronics GmbH 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#define _GNU_SOURCE 862306a36Sopenharmony_ci#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ 962306a36Sopenharmony_ci#include <errno.h> 1062306a36Sopenharmony_ci#include <fcntl.h> 1162306a36Sopenharmony_ci#include <inttypes.h> 1262306a36Sopenharmony_ci#include <math.h> 1362306a36Sopenharmony_ci#include <signal.h> 1462306a36Sopenharmony_ci#include <stdio.h> 1562306a36Sopenharmony_ci#include <stdlib.h> 1662306a36Sopenharmony_ci#include <string.h> 1762306a36Sopenharmony_ci#include <sys/ioctl.h> 1862306a36Sopenharmony_ci#include <sys/mman.h> 1962306a36Sopenharmony_ci#include <sys/stat.h> 2062306a36Sopenharmony_ci#include <sys/time.h> 2162306a36Sopenharmony_ci#include <sys/timex.h> 2262306a36Sopenharmony_ci#include <sys/types.h> 2362306a36Sopenharmony_ci#include <time.h> 2462306a36Sopenharmony_ci#include <unistd.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/ptp_clock.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define DEVICE "/dev/ptp0" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#ifndef ADJ_SETOFFSET 3162306a36Sopenharmony_ci#define ADJ_SETOFFSET 0x0100 3262306a36Sopenharmony_ci#endif 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#ifndef CLOCK_INVALID 3562306a36Sopenharmony_ci#define CLOCK_INVALID -1 3662306a36Sopenharmony_ci#endif 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define NSEC_PER_SEC 1000000000LL 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* clock_adjtime is not available in GLIBC < 2.14 */ 4162306a36Sopenharmony_ci#if !__GLIBC_PREREQ(2, 14) 4262306a36Sopenharmony_ci#include <sys/syscall.h> 4362306a36Sopenharmony_cistatic int clock_adjtime(clockid_t id, struct timex *tx) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci return syscall(__NR_clock_adjtime, id, tx); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci#endif 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic void show_flag_test(int rq_index, unsigned int flags, int err) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci printf("PTP_EXTTS_REQUEST%c flags 0x%08x : (%d) %s\n", 5262306a36Sopenharmony_ci rq_index ? '1' + rq_index : ' ', 5362306a36Sopenharmony_ci flags, err, strerror(errno)); 5462306a36Sopenharmony_ci /* sigh, uClibc ... */ 5562306a36Sopenharmony_ci errno = 0; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic void do_flag_test(int fd, unsigned int index) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct ptp_extts_request extts_request; 6162306a36Sopenharmony_ci unsigned long request[2] = { 6262306a36Sopenharmony_ci PTP_EXTTS_REQUEST, 6362306a36Sopenharmony_ci PTP_EXTTS_REQUEST2, 6462306a36Sopenharmony_ci }; 6562306a36Sopenharmony_ci unsigned int enable_flags[5] = { 6662306a36Sopenharmony_ci PTP_ENABLE_FEATURE, 6762306a36Sopenharmony_ci PTP_ENABLE_FEATURE | PTP_RISING_EDGE, 6862306a36Sopenharmony_ci PTP_ENABLE_FEATURE | PTP_FALLING_EDGE, 6962306a36Sopenharmony_ci PTP_ENABLE_FEATURE | PTP_RISING_EDGE | PTP_FALLING_EDGE, 7062306a36Sopenharmony_ci PTP_ENABLE_FEATURE | (PTP_EXTTS_VALID_FLAGS + 1), 7162306a36Sopenharmony_ci }; 7262306a36Sopenharmony_ci int err, i, j; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci memset(&extts_request, 0, sizeof(extts_request)); 7562306a36Sopenharmony_ci extts_request.index = index; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 7862306a36Sopenharmony_ci for (j = 0; j < 5; j++) { 7962306a36Sopenharmony_ci extts_request.flags = enable_flags[j]; 8062306a36Sopenharmony_ci err = ioctl(fd, request[i], &extts_request); 8162306a36Sopenharmony_ci show_flag_test(i, extts_request.flags, err); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci extts_request.flags = 0; 8462306a36Sopenharmony_ci err = ioctl(fd, request[i], &extts_request); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic clockid_t get_clockid(int fd) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci#define CLOCKFD 3 9262306a36Sopenharmony_ci return (((unsigned int) ~fd) << 3) | CLOCKFD; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic long ppb_to_scaled_ppm(int ppb) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * The 'freq' field in the 'struct timex' is in parts per 9962306a36Sopenharmony_ci * million, but with a 16 bit binary fractional field. 10062306a36Sopenharmony_ci * Instead of calculating either one of 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * scaled_ppm = (ppb / 1000) << 16 [1] 10362306a36Sopenharmony_ci * scaled_ppm = (ppb << 16) / 1000 [2] 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * we simply use double precision math, in order to avoid the 10662306a36Sopenharmony_ci * truncation in [1] and the possible overflow in [2]. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci return (long) (ppb * 65.536); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int64_t pctns(struct ptp_clock_time *t) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci return t->sec * NSEC_PER_SEC + t->nsec; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void usage(char *progname) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci fprintf(stderr, 11962306a36Sopenharmony_ci "usage: %s [options]\n" 12062306a36Sopenharmony_ci " -c query the ptp clock's capabilities\n" 12162306a36Sopenharmony_ci " -d name device to open\n" 12262306a36Sopenharmony_ci " -e val read 'val' external time stamp events\n" 12362306a36Sopenharmony_ci " -f val adjust the ptp clock frequency by 'val' ppb\n" 12462306a36Sopenharmony_ci " -g get the ptp clock time\n" 12562306a36Sopenharmony_ci " -h prints this message\n" 12662306a36Sopenharmony_ci " -i val index for event/trigger\n" 12762306a36Sopenharmony_ci " -k val measure the time offset between system and phc clock\n" 12862306a36Sopenharmony_ci " for 'val' times (Maximum 25)\n" 12962306a36Sopenharmony_ci " -l list the current pin configuration\n" 13062306a36Sopenharmony_ci " -L pin,val configure pin index 'pin' with function 'val'\n" 13162306a36Sopenharmony_ci " the channel index is taken from the '-i' option\n" 13262306a36Sopenharmony_ci " 'val' specifies the auxiliary function:\n" 13362306a36Sopenharmony_ci " 0 - none\n" 13462306a36Sopenharmony_ci " 1 - external time stamp\n" 13562306a36Sopenharmony_ci " 2 - periodic output\n" 13662306a36Sopenharmony_ci " -n val shift the ptp clock time by 'val' nanoseconds\n" 13762306a36Sopenharmony_ci " -o val phase offset (in nanoseconds) to be provided to the PHC servo\n" 13862306a36Sopenharmony_ci " -p val enable output with a period of 'val' nanoseconds\n" 13962306a36Sopenharmony_ci " -H val set output phase to 'val' nanoseconds (requires -p)\n" 14062306a36Sopenharmony_ci " -w val set output pulse width to 'val' nanoseconds (requires -p)\n" 14162306a36Sopenharmony_ci " -P val enable or disable (val=1|0) the system clock PPS\n" 14262306a36Sopenharmony_ci " -s set the ptp clock time from the system time\n" 14362306a36Sopenharmony_ci " -S set the system time from the ptp clock time\n" 14462306a36Sopenharmony_ci " -t val shift the ptp clock time by 'val' seconds\n" 14562306a36Sopenharmony_ci " -T val set the ptp clock time to 'val' seconds\n" 14662306a36Sopenharmony_ci " -x val get an extended ptp clock time with the desired number of samples (up to %d)\n" 14762306a36Sopenharmony_ci " -X get a ptp clock cross timestamp\n" 14862306a36Sopenharmony_ci " -z test combinations of rising/falling external time stamp flags\n", 14962306a36Sopenharmony_ci progname, PTP_MAX_SAMPLES); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ciint main(int argc, char *argv[]) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct ptp_clock_caps caps; 15562306a36Sopenharmony_ci struct ptp_extts_event event; 15662306a36Sopenharmony_ci struct ptp_extts_request extts_request; 15762306a36Sopenharmony_ci struct ptp_perout_request perout_request; 15862306a36Sopenharmony_ci struct ptp_pin_desc desc; 15962306a36Sopenharmony_ci struct timespec ts; 16062306a36Sopenharmony_ci struct timex tx; 16162306a36Sopenharmony_ci struct ptp_clock_time *pct; 16262306a36Sopenharmony_ci struct ptp_sys_offset *sysoff; 16362306a36Sopenharmony_ci struct ptp_sys_offset_extended *soe; 16462306a36Sopenharmony_ci struct ptp_sys_offset_precise *xts; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci char *progname; 16762306a36Sopenharmony_ci unsigned int i; 16862306a36Sopenharmony_ci int c, cnt, fd; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci char *device = DEVICE; 17162306a36Sopenharmony_ci clockid_t clkid; 17262306a36Sopenharmony_ci int adjfreq = 0x7fffffff; 17362306a36Sopenharmony_ci int adjtime = 0; 17462306a36Sopenharmony_ci int adjns = 0; 17562306a36Sopenharmony_ci int adjphase = 0; 17662306a36Sopenharmony_ci int capabilities = 0; 17762306a36Sopenharmony_ci int extts = 0; 17862306a36Sopenharmony_ci int flagtest = 0; 17962306a36Sopenharmony_ci int gettime = 0; 18062306a36Sopenharmony_ci int index = 0; 18162306a36Sopenharmony_ci int list_pins = 0; 18262306a36Sopenharmony_ci int pct_offset = 0; 18362306a36Sopenharmony_ci int getextended = 0; 18462306a36Sopenharmony_ci int getcross = 0; 18562306a36Sopenharmony_ci int n_samples = 0; 18662306a36Sopenharmony_ci int pin_index = -1, pin_func; 18762306a36Sopenharmony_ci int pps = -1; 18862306a36Sopenharmony_ci int seconds = 0; 18962306a36Sopenharmony_ci int settime = 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci int64_t t1, t2, tp; 19262306a36Sopenharmony_ci int64_t interval, offset; 19362306a36Sopenharmony_ci int64_t perout_phase = -1; 19462306a36Sopenharmony_ci int64_t pulsewidth = -1; 19562306a36Sopenharmony_ci int64_t perout = -1; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci progname = strrchr(argv[0], '/'); 19862306a36Sopenharmony_ci progname = progname ? 1+progname : argv[0]; 19962306a36Sopenharmony_ci while (EOF != (c = getopt(argc, argv, "cd:e:f:ghH:i:k:lL:n:o:p:P:sSt:T:w:x:Xz"))) { 20062306a36Sopenharmony_ci switch (c) { 20162306a36Sopenharmony_ci case 'c': 20262306a36Sopenharmony_ci capabilities = 1; 20362306a36Sopenharmony_ci break; 20462306a36Sopenharmony_ci case 'd': 20562306a36Sopenharmony_ci device = optarg; 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci case 'e': 20862306a36Sopenharmony_ci extts = atoi(optarg); 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci case 'f': 21162306a36Sopenharmony_ci adjfreq = atoi(optarg); 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci case 'g': 21462306a36Sopenharmony_ci gettime = 1; 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci case 'H': 21762306a36Sopenharmony_ci perout_phase = atoll(optarg); 21862306a36Sopenharmony_ci break; 21962306a36Sopenharmony_ci case 'i': 22062306a36Sopenharmony_ci index = atoi(optarg); 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci case 'k': 22362306a36Sopenharmony_ci pct_offset = 1; 22462306a36Sopenharmony_ci n_samples = atoi(optarg); 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci case 'l': 22762306a36Sopenharmony_ci list_pins = 1; 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci case 'L': 23062306a36Sopenharmony_ci cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func); 23162306a36Sopenharmony_ci if (cnt != 2) { 23262306a36Sopenharmony_ci usage(progname); 23362306a36Sopenharmony_ci return -1; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci case 'n': 23762306a36Sopenharmony_ci adjns = atoi(optarg); 23862306a36Sopenharmony_ci break; 23962306a36Sopenharmony_ci case 'o': 24062306a36Sopenharmony_ci adjphase = atoi(optarg); 24162306a36Sopenharmony_ci break; 24262306a36Sopenharmony_ci case 'p': 24362306a36Sopenharmony_ci perout = atoll(optarg); 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci case 'P': 24662306a36Sopenharmony_ci pps = atoi(optarg); 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case 's': 24962306a36Sopenharmony_ci settime = 1; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci case 'S': 25262306a36Sopenharmony_ci settime = 2; 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci case 't': 25562306a36Sopenharmony_ci adjtime = atoi(optarg); 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci case 'T': 25862306a36Sopenharmony_ci settime = 3; 25962306a36Sopenharmony_ci seconds = atoi(optarg); 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci case 'w': 26262306a36Sopenharmony_ci pulsewidth = atoi(optarg); 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci case 'x': 26562306a36Sopenharmony_ci getextended = atoi(optarg); 26662306a36Sopenharmony_ci if (getextended < 1 || getextended > PTP_MAX_SAMPLES) { 26762306a36Sopenharmony_ci fprintf(stderr, 26862306a36Sopenharmony_ci "number of extended timestamp samples must be between 1 and %d; was asked for %d\n", 26962306a36Sopenharmony_ci PTP_MAX_SAMPLES, getextended); 27062306a36Sopenharmony_ci return -1; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci break; 27362306a36Sopenharmony_ci case 'X': 27462306a36Sopenharmony_ci getcross = 1; 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci case 'z': 27762306a36Sopenharmony_ci flagtest = 1; 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci case 'h': 28062306a36Sopenharmony_ci usage(progname); 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci case '?': 28362306a36Sopenharmony_ci default: 28462306a36Sopenharmony_ci usage(progname); 28562306a36Sopenharmony_ci return -1; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci fd = open(device, O_RDWR); 29062306a36Sopenharmony_ci if (fd < 0) { 29162306a36Sopenharmony_ci fprintf(stderr, "opening %s: %s\n", device, strerror(errno)); 29262306a36Sopenharmony_ci return -1; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci clkid = get_clockid(fd); 29662306a36Sopenharmony_ci if (CLOCK_INVALID == clkid) { 29762306a36Sopenharmony_ci fprintf(stderr, "failed to read clock id\n"); 29862306a36Sopenharmony_ci return -1; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (capabilities) { 30262306a36Sopenharmony_ci if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) { 30362306a36Sopenharmony_ci perror("PTP_CLOCK_GETCAPS"); 30462306a36Sopenharmony_ci } else { 30562306a36Sopenharmony_ci printf("capabilities:\n" 30662306a36Sopenharmony_ci " %d maximum frequency adjustment (ppb)\n" 30762306a36Sopenharmony_ci " %d programmable alarms\n" 30862306a36Sopenharmony_ci " %d external time stamp channels\n" 30962306a36Sopenharmony_ci " %d programmable periodic signals\n" 31062306a36Sopenharmony_ci " %d pulse per second\n" 31162306a36Sopenharmony_ci " %d programmable pins\n" 31262306a36Sopenharmony_ci " %d cross timestamping\n" 31362306a36Sopenharmony_ci " %d adjust_phase\n" 31462306a36Sopenharmony_ci " %d maximum phase adjustment (ns)\n", 31562306a36Sopenharmony_ci caps.max_adj, 31662306a36Sopenharmony_ci caps.n_alarm, 31762306a36Sopenharmony_ci caps.n_ext_ts, 31862306a36Sopenharmony_ci caps.n_per_out, 31962306a36Sopenharmony_ci caps.pps, 32062306a36Sopenharmony_ci caps.n_pins, 32162306a36Sopenharmony_ci caps.cross_timestamping, 32262306a36Sopenharmony_ci caps.adjust_phase, 32362306a36Sopenharmony_ci caps.max_phase_adj); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (0x7fffffff != adjfreq) { 32862306a36Sopenharmony_ci memset(&tx, 0, sizeof(tx)); 32962306a36Sopenharmony_ci tx.modes = ADJ_FREQUENCY; 33062306a36Sopenharmony_ci tx.freq = ppb_to_scaled_ppm(adjfreq); 33162306a36Sopenharmony_ci if (clock_adjtime(clkid, &tx)) { 33262306a36Sopenharmony_ci perror("clock_adjtime"); 33362306a36Sopenharmony_ci } else { 33462306a36Sopenharmony_ci puts("frequency adjustment okay"); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (adjtime || adjns) { 33962306a36Sopenharmony_ci memset(&tx, 0, sizeof(tx)); 34062306a36Sopenharmony_ci tx.modes = ADJ_SETOFFSET | ADJ_NANO; 34162306a36Sopenharmony_ci tx.time.tv_sec = adjtime; 34262306a36Sopenharmony_ci tx.time.tv_usec = adjns; 34362306a36Sopenharmony_ci while (tx.time.tv_usec < 0) { 34462306a36Sopenharmony_ci tx.time.tv_sec -= 1; 34562306a36Sopenharmony_ci tx.time.tv_usec += NSEC_PER_SEC; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (clock_adjtime(clkid, &tx) < 0) { 34962306a36Sopenharmony_ci perror("clock_adjtime"); 35062306a36Sopenharmony_ci } else { 35162306a36Sopenharmony_ci puts("time shift okay"); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (adjphase) { 35662306a36Sopenharmony_ci memset(&tx, 0, sizeof(tx)); 35762306a36Sopenharmony_ci tx.modes = ADJ_OFFSET | ADJ_NANO; 35862306a36Sopenharmony_ci tx.offset = adjphase; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (clock_adjtime(clkid, &tx) < 0) { 36162306a36Sopenharmony_ci perror("clock_adjtime"); 36262306a36Sopenharmony_ci } else { 36362306a36Sopenharmony_ci puts("phase adjustment okay"); 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (gettime) { 36862306a36Sopenharmony_ci if (clock_gettime(clkid, &ts)) { 36962306a36Sopenharmony_ci perror("clock_gettime"); 37062306a36Sopenharmony_ci } else { 37162306a36Sopenharmony_ci printf("clock time: %ld.%09ld or %s", 37262306a36Sopenharmony_ci ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec)); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (settime == 1) { 37762306a36Sopenharmony_ci clock_gettime(CLOCK_REALTIME, &ts); 37862306a36Sopenharmony_ci if (clock_settime(clkid, &ts)) { 37962306a36Sopenharmony_ci perror("clock_settime"); 38062306a36Sopenharmony_ci } else { 38162306a36Sopenharmony_ci puts("set time okay"); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (settime == 2) { 38662306a36Sopenharmony_ci clock_gettime(clkid, &ts); 38762306a36Sopenharmony_ci if (clock_settime(CLOCK_REALTIME, &ts)) { 38862306a36Sopenharmony_ci perror("clock_settime"); 38962306a36Sopenharmony_ci } else { 39062306a36Sopenharmony_ci puts("set time okay"); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (settime == 3) { 39562306a36Sopenharmony_ci ts.tv_sec = seconds; 39662306a36Sopenharmony_ci ts.tv_nsec = 0; 39762306a36Sopenharmony_ci if (clock_settime(clkid, &ts)) { 39862306a36Sopenharmony_ci perror("clock_settime"); 39962306a36Sopenharmony_ci } else { 40062306a36Sopenharmony_ci puts("set time okay"); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (pin_index >= 0) { 40562306a36Sopenharmony_ci memset(&desc, 0, sizeof(desc)); 40662306a36Sopenharmony_ci desc.index = pin_index; 40762306a36Sopenharmony_ci desc.func = pin_func; 40862306a36Sopenharmony_ci desc.chan = index; 40962306a36Sopenharmony_ci if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) { 41062306a36Sopenharmony_ci perror("PTP_PIN_SETFUNC"); 41162306a36Sopenharmony_ci } else { 41262306a36Sopenharmony_ci puts("set pin function okay"); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (extts) { 41762306a36Sopenharmony_ci memset(&extts_request, 0, sizeof(extts_request)); 41862306a36Sopenharmony_ci extts_request.index = index; 41962306a36Sopenharmony_ci extts_request.flags = PTP_ENABLE_FEATURE; 42062306a36Sopenharmony_ci if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) { 42162306a36Sopenharmony_ci perror("PTP_EXTTS_REQUEST"); 42262306a36Sopenharmony_ci extts = 0; 42362306a36Sopenharmony_ci } else { 42462306a36Sopenharmony_ci puts("external time stamp request okay"); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci for (; extts; extts--) { 42762306a36Sopenharmony_ci cnt = read(fd, &event, sizeof(event)); 42862306a36Sopenharmony_ci if (cnt != sizeof(event)) { 42962306a36Sopenharmony_ci perror("read"); 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci printf("event index %u at %lld.%09u\n", event.index, 43362306a36Sopenharmony_ci event.t.sec, event.t.nsec); 43462306a36Sopenharmony_ci fflush(stdout); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci /* Disable the feature again. */ 43762306a36Sopenharmony_ci extts_request.flags = 0; 43862306a36Sopenharmony_ci if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) { 43962306a36Sopenharmony_ci perror("PTP_EXTTS_REQUEST"); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (flagtest) { 44462306a36Sopenharmony_ci do_flag_test(fd, index); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (list_pins) { 44862306a36Sopenharmony_ci int n_pins = 0; 44962306a36Sopenharmony_ci if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) { 45062306a36Sopenharmony_ci perror("PTP_CLOCK_GETCAPS"); 45162306a36Sopenharmony_ci } else { 45262306a36Sopenharmony_ci n_pins = caps.n_pins; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci for (i = 0; i < n_pins; i++) { 45562306a36Sopenharmony_ci desc.index = i; 45662306a36Sopenharmony_ci if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) { 45762306a36Sopenharmony_ci perror("PTP_PIN_GETFUNC"); 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci printf("name %s index %u func %u chan %u\n", 46162306a36Sopenharmony_ci desc.name, desc.index, desc.func, desc.chan); 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (pulsewidth >= 0 && perout < 0) { 46662306a36Sopenharmony_ci puts("-w can only be specified together with -p"); 46762306a36Sopenharmony_ci return -1; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (perout_phase >= 0 && perout < 0) { 47162306a36Sopenharmony_ci puts("-H can only be specified together with -p"); 47262306a36Sopenharmony_ci return -1; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (perout >= 0) { 47662306a36Sopenharmony_ci if (clock_gettime(clkid, &ts)) { 47762306a36Sopenharmony_ci perror("clock_gettime"); 47862306a36Sopenharmony_ci return -1; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci memset(&perout_request, 0, sizeof(perout_request)); 48162306a36Sopenharmony_ci perout_request.index = index; 48262306a36Sopenharmony_ci perout_request.period.sec = perout / NSEC_PER_SEC; 48362306a36Sopenharmony_ci perout_request.period.nsec = perout % NSEC_PER_SEC; 48462306a36Sopenharmony_ci perout_request.flags = 0; 48562306a36Sopenharmony_ci if (pulsewidth >= 0) { 48662306a36Sopenharmony_ci perout_request.flags |= PTP_PEROUT_DUTY_CYCLE; 48762306a36Sopenharmony_ci perout_request.on.sec = pulsewidth / NSEC_PER_SEC; 48862306a36Sopenharmony_ci perout_request.on.nsec = pulsewidth % NSEC_PER_SEC; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci if (perout_phase >= 0) { 49162306a36Sopenharmony_ci perout_request.flags |= PTP_PEROUT_PHASE; 49262306a36Sopenharmony_ci perout_request.phase.sec = perout_phase / NSEC_PER_SEC; 49362306a36Sopenharmony_ci perout_request.phase.nsec = perout_phase % NSEC_PER_SEC; 49462306a36Sopenharmony_ci } else { 49562306a36Sopenharmony_ci perout_request.start.sec = ts.tv_sec + 2; 49662306a36Sopenharmony_ci perout_request.start.nsec = 0; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (ioctl(fd, PTP_PEROUT_REQUEST2, &perout_request)) { 50062306a36Sopenharmony_ci perror("PTP_PEROUT_REQUEST"); 50162306a36Sopenharmony_ci } else { 50262306a36Sopenharmony_ci puts("periodic output request okay"); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (pps != -1) { 50762306a36Sopenharmony_ci int enable = pps ? 1 : 0; 50862306a36Sopenharmony_ci if (ioctl(fd, PTP_ENABLE_PPS, enable)) { 50962306a36Sopenharmony_ci perror("PTP_ENABLE_PPS"); 51062306a36Sopenharmony_ci } else { 51162306a36Sopenharmony_ci puts("pps for system time request okay"); 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (pct_offset) { 51662306a36Sopenharmony_ci if (n_samples <= 0 || n_samples > 25) { 51762306a36Sopenharmony_ci puts("n_samples should be between 1 and 25"); 51862306a36Sopenharmony_ci usage(progname); 51962306a36Sopenharmony_ci return -1; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci sysoff = calloc(1, sizeof(*sysoff)); 52362306a36Sopenharmony_ci if (!sysoff) { 52462306a36Sopenharmony_ci perror("calloc"); 52562306a36Sopenharmony_ci return -1; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci sysoff->n_samples = n_samples; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (ioctl(fd, PTP_SYS_OFFSET, sysoff)) 53062306a36Sopenharmony_ci perror("PTP_SYS_OFFSET"); 53162306a36Sopenharmony_ci else 53262306a36Sopenharmony_ci puts("system and phc clock time offset request okay"); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci pct = &sysoff->ts[0]; 53562306a36Sopenharmony_ci for (i = 0; i < sysoff->n_samples; i++) { 53662306a36Sopenharmony_ci t1 = pctns(pct+2*i); 53762306a36Sopenharmony_ci tp = pctns(pct+2*i+1); 53862306a36Sopenharmony_ci t2 = pctns(pct+2*i+2); 53962306a36Sopenharmony_ci interval = t2 - t1; 54062306a36Sopenharmony_ci offset = (t2 + t1) / 2 - tp; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci printf("system time: %lld.%09u\n", 54362306a36Sopenharmony_ci (pct+2*i)->sec, (pct+2*i)->nsec); 54462306a36Sopenharmony_ci printf("phc time: %lld.%09u\n", 54562306a36Sopenharmony_ci (pct+2*i+1)->sec, (pct+2*i+1)->nsec); 54662306a36Sopenharmony_ci printf("system time: %lld.%09u\n", 54762306a36Sopenharmony_ci (pct+2*i+2)->sec, (pct+2*i+2)->nsec); 54862306a36Sopenharmony_ci printf("system/phc clock time offset is %" PRId64 " ns\n" 54962306a36Sopenharmony_ci "system clock time delay is %" PRId64 " ns\n", 55062306a36Sopenharmony_ci offset, interval); 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci free(sysoff); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (getextended) { 55762306a36Sopenharmony_ci soe = calloc(1, sizeof(*soe)); 55862306a36Sopenharmony_ci if (!soe) { 55962306a36Sopenharmony_ci perror("calloc"); 56062306a36Sopenharmony_ci return -1; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci soe->n_samples = getextended; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (ioctl(fd, PTP_SYS_OFFSET_EXTENDED, soe)) { 56662306a36Sopenharmony_ci perror("PTP_SYS_OFFSET_EXTENDED"); 56762306a36Sopenharmony_ci } else { 56862306a36Sopenharmony_ci printf("extended timestamp request returned %d samples\n", 56962306a36Sopenharmony_ci getextended); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci for (i = 0; i < getextended; i++) { 57262306a36Sopenharmony_ci printf("sample #%2d: system time before: %lld.%09u\n", 57362306a36Sopenharmony_ci i, soe->ts[i][0].sec, soe->ts[i][0].nsec); 57462306a36Sopenharmony_ci printf(" phc time: %lld.%09u\n", 57562306a36Sopenharmony_ci soe->ts[i][1].sec, soe->ts[i][1].nsec); 57662306a36Sopenharmony_ci printf(" system time after: %lld.%09u\n", 57762306a36Sopenharmony_ci soe->ts[i][2].sec, soe->ts[i][2].nsec); 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci free(soe); 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (getcross) { 58562306a36Sopenharmony_ci xts = calloc(1, sizeof(*xts)); 58662306a36Sopenharmony_ci if (!xts) { 58762306a36Sopenharmony_ci perror("calloc"); 58862306a36Sopenharmony_ci return -1; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (ioctl(fd, PTP_SYS_OFFSET_PRECISE, xts)) { 59262306a36Sopenharmony_ci perror("PTP_SYS_OFFSET_PRECISE"); 59362306a36Sopenharmony_ci } else { 59462306a36Sopenharmony_ci puts("system and phc crosstimestamping request okay"); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci printf("device time: %lld.%09u\n", 59762306a36Sopenharmony_ci xts->device.sec, xts->device.nsec); 59862306a36Sopenharmony_ci printf("system time: %lld.%09u\n", 59962306a36Sopenharmony_ci xts->sys_realtime.sec, xts->sys_realtime.nsec); 60062306a36Sopenharmony_ci printf("monoraw time: %lld.%09u\n", 60162306a36Sopenharmony_ci xts->sys_monoraw.sec, xts->sys_monoraw.nsec); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci free(xts); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci close(fd); 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci} 610