18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PTP 1588 clock support - User space test program 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 OMICRON electronics GmbH 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#define _GNU_SOURCE 88c2ecf20Sopenharmony_ci#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ 98c2ecf20Sopenharmony_ci#include <errno.h> 108c2ecf20Sopenharmony_ci#include <fcntl.h> 118c2ecf20Sopenharmony_ci#include <inttypes.h> 128c2ecf20Sopenharmony_ci#include <math.h> 138c2ecf20Sopenharmony_ci#include <signal.h> 148c2ecf20Sopenharmony_ci#include <stdio.h> 158c2ecf20Sopenharmony_ci#include <stdlib.h> 168c2ecf20Sopenharmony_ci#include <string.h> 178c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 188c2ecf20Sopenharmony_ci#include <sys/mman.h> 198c2ecf20Sopenharmony_ci#include <sys/stat.h> 208c2ecf20Sopenharmony_ci#include <sys/time.h> 218c2ecf20Sopenharmony_ci#include <sys/timex.h> 228c2ecf20Sopenharmony_ci#include <sys/types.h> 238c2ecf20Sopenharmony_ci#include <time.h> 248c2ecf20Sopenharmony_ci#include <unistd.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/ptp_clock.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define DEVICE "/dev/ptp0" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#ifndef ADJ_SETOFFSET 318c2ecf20Sopenharmony_ci#define ADJ_SETOFFSET 0x0100 328c2ecf20Sopenharmony_ci#endif 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#ifndef CLOCK_INVALID 358c2ecf20Sopenharmony_ci#define CLOCK_INVALID -1 368c2ecf20Sopenharmony_ci#endif 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define NSEC_PER_SEC 1000000000LL 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* clock_adjtime is not available in GLIBC < 2.14 */ 418c2ecf20Sopenharmony_ci#if !__GLIBC_PREREQ(2, 14) 428c2ecf20Sopenharmony_ci#include <sys/syscall.h> 438c2ecf20Sopenharmony_cistatic int clock_adjtime(clockid_t id, struct timex *tx) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return syscall(__NR_clock_adjtime, id, tx); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci#endif 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void show_flag_test(int rq_index, unsigned int flags, int err) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci printf("PTP_EXTTS_REQUEST%c flags 0x%08x : (%d) %s\n", 528c2ecf20Sopenharmony_ci rq_index ? '1' + rq_index : ' ', 538c2ecf20Sopenharmony_ci flags, err, strerror(errno)); 548c2ecf20Sopenharmony_ci /* sigh, uClibc ... */ 558c2ecf20Sopenharmony_ci errno = 0; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void do_flag_test(int fd, unsigned int index) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct ptp_extts_request extts_request; 618c2ecf20Sopenharmony_ci unsigned long request[2] = { 628c2ecf20Sopenharmony_ci PTP_EXTTS_REQUEST, 638c2ecf20Sopenharmony_ci PTP_EXTTS_REQUEST2, 648c2ecf20Sopenharmony_ci }; 658c2ecf20Sopenharmony_ci unsigned int enable_flags[5] = { 668c2ecf20Sopenharmony_ci PTP_ENABLE_FEATURE, 678c2ecf20Sopenharmony_ci PTP_ENABLE_FEATURE | PTP_RISING_EDGE, 688c2ecf20Sopenharmony_ci PTP_ENABLE_FEATURE | PTP_FALLING_EDGE, 698c2ecf20Sopenharmony_ci PTP_ENABLE_FEATURE | PTP_RISING_EDGE | PTP_FALLING_EDGE, 708c2ecf20Sopenharmony_ci PTP_ENABLE_FEATURE | (PTP_EXTTS_VALID_FLAGS + 1), 718c2ecf20Sopenharmony_ci }; 728c2ecf20Sopenharmony_ci int err, i, j; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci memset(&extts_request, 0, sizeof(extts_request)); 758c2ecf20Sopenharmony_ci extts_request.index = index; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 788c2ecf20Sopenharmony_ci for (j = 0; j < 5; j++) { 798c2ecf20Sopenharmony_ci extts_request.flags = enable_flags[j]; 808c2ecf20Sopenharmony_ci err = ioctl(fd, request[i], &extts_request); 818c2ecf20Sopenharmony_ci show_flag_test(i, extts_request.flags, err); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci extts_request.flags = 0; 848c2ecf20Sopenharmony_ci err = ioctl(fd, request[i], &extts_request); 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic clockid_t get_clockid(int fd) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci#define CLOCKFD 3 928c2ecf20Sopenharmony_ci return (((unsigned int) ~fd) << 3) | CLOCKFD; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic long ppb_to_scaled_ppm(int ppb) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci /* 988c2ecf20Sopenharmony_ci * The 'freq' field in the 'struct timex' is in parts per 998c2ecf20Sopenharmony_ci * million, but with a 16 bit binary fractional field. 1008c2ecf20Sopenharmony_ci * Instead of calculating either one of 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * scaled_ppm = (ppb / 1000) << 16 [1] 1038c2ecf20Sopenharmony_ci * scaled_ppm = (ppb << 16) / 1000 [2] 1048c2ecf20Sopenharmony_ci * 1058c2ecf20Sopenharmony_ci * we simply use double precision math, in order to avoid the 1068c2ecf20Sopenharmony_ci * truncation in [1] and the possible overflow in [2]. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci return (long) (ppb * 65.536); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int64_t pctns(struct ptp_clock_time *t) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return t->sec * 1000000000LL + t->nsec; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void usage(char *progname) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci fprintf(stderr, 1198c2ecf20Sopenharmony_ci "usage: %s [options]\n" 1208c2ecf20Sopenharmony_ci " -c query the ptp clock's capabilities\n" 1218c2ecf20Sopenharmony_ci " -d name device to open\n" 1228c2ecf20Sopenharmony_ci " -e val read 'val' external time stamp events\n" 1238c2ecf20Sopenharmony_ci " -f val adjust the ptp clock frequency by 'val' ppb\n" 1248c2ecf20Sopenharmony_ci " -g get the ptp clock time\n" 1258c2ecf20Sopenharmony_ci " -h prints this message\n" 1268c2ecf20Sopenharmony_ci " -i val index for event/trigger\n" 1278c2ecf20Sopenharmony_ci " -k val measure the time offset between system and phc clock\n" 1288c2ecf20Sopenharmony_ci " for 'val' times (Maximum 25)\n" 1298c2ecf20Sopenharmony_ci " -l list the current pin configuration\n" 1308c2ecf20Sopenharmony_ci " -L pin,val configure pin index 'pin' with function 'val'\n" 1318c2ecf20Sopenharmony_ci " the channel index is taken from the '-i' option\n" 1328c2ecf20Sopenharmony_ci " 'val' specifies the auxiliary function:\n" 1338c2ecf20Sopenharmony_ci " 0 - none\n" 1348c2ecf20Sopenharmony_ci " 1 - external time stamp\n" 1358c2ecf20Sopenharmony_ci " 2 - periodic output\n" 1368c2ecf20Sopenharmony_ci " -p val enable output with a period of 'val' nanoseconds\n" 1378c2ecf20Sopenharmony_ci " -H val set output phase to 'val' nanoseconds (requires -p)\n" 1388c2ecf20Sopenharmony_ci " -w val set output pulse width to 'val' nanoseconds (requires -p)\n" 1398c2ecf20Sopenharmony_ci " -P val enable or disable (val=1|0) the system clock PPS\n" 1408c2ecf20Sopenharmony_ci " -s set the ptp clock time from the system time\n" 1418c2ecf20Sopenharmony_ci " -S set the system time from the ptp clock time\n" 1428c2ecf20Sopenharmony_ci " -t val shift the ptp clock time by 'val' seconds\n" 1438c2ecf20Sopenharmony_ci " -T val set the ptp clock time to 'val' seconds\n" 1448c2ecf20Sopenharmony_ci " -z test combinations of rising/falling external time stamp flags\n", 1458c2ecf20Sopenharmony_ci progname); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct ptp_clock_caps caps; 1518c2ecf20Sopenharmony_ci struct ptp_extts_event event; 1528c2ecf20Sopenharmony_ci struct ptp_extts_request extts_request; 1538c2ecf20Sopenharmony_ci struct ptp_perout_request perout_request; 1548c2ecf20Sopenharmony_ci struct ptp_pin_desc desc; 1558c2ecf20Sopenharmony_ci struct timespec ts; 1568c2ecf20Sopenharmony_ci struct timex tx; 1578c2ecf20Sopenharmony_ci struct ptp_clock_time *pct; 1588c2ecf20Sopenharmony_ci struct ptp_sys_offset *sysoff; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci char *progname; 1618c2ecf20Sopenharmony_ci unsigned int i; 1628c2ecf20Sopenharmony_ci int c, cnt, fd; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci char *device = DEVICE; 1658c2ecf20Sopenharmony_ci clockid_t clkid; 1668c2ecf20Sopenharmony_ci int adjfreq = 0x7fffffff; 1678c2ecf20Sopenharmony_ci int adjtime = 0; 1688c2ecf20Sopenharmony_ci int capabilities = 0; 1698c2ecf20Sopenharmony_ci int extts = 0; 1708c2ecf20Sopenharmony_ci int flagtest = 0; 1718c2ecf20Sopenharmony_ci int gettime = 0; 1728c2ecf20Sopenharmony_ci int index = 0; 1738c2ecf20Sopenharmony_ci int list_pins = 0; 1748c2ecf20Sopenharmony_ci int pct_offset = 0; 1758c2ecf20Sopenharmony_ci int n_samples = 0; 1768c2ecf20Sopenharmony_ci int pin_index = -1, pin_func; 1778c2ecf20Sopenharmony_ci int pps = -1; 1788c2ecf20Sopenharmony_ci int seconds = 0; 1798c2ecf20Sopenharmony_ci int settime = 0; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci int64_t t1, t2, tp; 1828c2ecf20Sopenharmony_ci int64_t interval, offset; 1838c2ecf20Sopenharmony_ci int64_t perout_phase = -1; 1848c2ecf20Sopenharmony_ci int64_t pulsewidth = -1; 1858c2ecf20Sopenharmony_ci int64_t perout = -1; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci progname = strrchr(argv[0], '/'); 1888c2ecf20Sopenharmony_ci progname = progname ? 1+progname : argv[0]; 1898c2ecf20Sopenharmony_ci while (EOF != (c = getopt(argc, argv, "cd:e:f:ghH:i:k:lL:p:P:sSt:T:w:z"))) { 1908c2ecf20Sopenharmony_ci switch (c) { 1918c2ecf20Sopenharmony_ci case 'c': 1928c2ecf20Sopenharmony_ci capabilities = 1; 1938c2ecf20Sopenharmony_ci break; 1948c2ecf20Sopenharmony_ci case 'd': 1958c2ecf20Sopenharmony_ci device = optarg; 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci case 'e': 1988c2ecf20Sopenharmony_ci extts = atoi(optarg); 1998c2ecf20Sopenharmony_ci break; 2008c2ecf20Sopenharmony_ci case 'f': 2018c2ecf20Sopenharmony_ci adjfreq = atoi(optarg); 2028c2ecf20Sopenharmony_ci break; 2038c2ecf20Sopenharmony_ci case 'g': 2048c2ecf20Sopenharmony_ci gettime = 1; 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci case 'H': 2078c2ecf20Sopenharmony_ci perout_phase = atoll(optarg); 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci case 'i': 2108c2ecf20Sopenharmony_ci index = atoi(optarg); 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci case 'k': 2138c2ecf20Sopenharmony_ci pct_offset = 1; 2148c2ecf20Sopenharmony_ci n_samples = atoi(optarg); 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case 'l': 2178c2ecf20Sopenharmony_ci list_pins = 1; 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci case 'L': 2208c2ecf20Sopenharmony_ci cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func); 2218c2ecf20Sopenharmony_ci if (cnt != 2) { 2228c2ecf20Sopenharmony_ci usage(progname); 2238c2ecf20Sopenharmony_ci return -1; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci case 'p': 2278c2ecf20Sopenharmony_ci perout = atoll(optarg); 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci case 'P': 2308c2ecf20Sopenharmony_ci pps = atoi(optarg); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case 's': 2338c2ecf20Sopenharmony_ci settime = 1; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci case 'S': 2368c2ecf20Sopenharmony_ci settime = 2; 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci case 't': 2398c2ecf20Sopenharmony_ci adjtime = atoi(optarg); 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci case 'T': 2428c2ecf20Sopenharmony_ci settime = 3; 2438c2ecf20Sopenharmony_ci seconds = atoi(optarg); 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci case 'w': 2468c2ecf20Sopenharmony_ci pulsewidth = atoi(optarg); 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci case 'z': 2498c2ecf20Sopenharmony_ci flagtest = 1; 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci case 'h': 2528c2ecf20Sopenharmony_ci usage(progname); 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci case '?': 2558c2ecf20Sopenharmony_ci default: 2568c2ecf20Sopenharmony_ci usage(progname); 2578c2ecf20Sopenharmony_ci return -1; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci fd = open(device, O_RDWR); 2628c2ecf20Sopenharmony_ci if (fd < 0) { 2638c2ecf20Sopenharmony_ci fprintf(stderr, "opening %s: %s\n", device, strerror(errno)); 2648c2ecf20Sopenharmony_ci return -1; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci clkid = get_clockid(fd); 2688c2ecf20Sopenharmony_ci if (CLOCK_INVALID == clkid) { 2698c2ecf20Sopenharmony_ci fprintf(stderr, "failed to read clock id\n"); 2708c2ecf20Sopenharmony_ci return -1; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (capabilities) { 2748c2ecf20Sopenharmony_ci if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) { 2758c2ecf20Sopenharmony_ci perror("PTP_CLOCK_GETCAPS"); 2768c2ecf20Sopenharmony_ci } else { 2778c2ecf20Sopenharmony_ci printf("capabilities:\n" 2788c2ecf20Sopenharmony_ci " %d maximum frequency adjustment (ppb)\n" 2798c2ecf20Sopenharmony_ci " %d programmable alarms\n" 2808c2ecf20Sopenharmony_ci " %d external time stamp channels\n" 2818c2ecf20Sopenharmony_ci " %d programmable periodic signals\n" 2828c2ecf20Sopenharmony_ci " %d pulse per second\n" 2838c2ecf20Sopenharmony_ci " %d programmable pins\n" 2848c2ecf20Sopenharmony_ci " %d cross timestamping\n" 2858c2ecf20Sopenharmony_ci " %d adjust_phase\n", 2868c2ecf20Sopenharmony_ci caps.max_adj, 2878c2ecf20Sopenharmony_ci caps.n_alarm, 2888c2ecf20Sopenharmony_ci caps.n_ext_ts, 2898c2ecf20Sopenharmony_ci caps.n_per_out, 2908c2ecf20Sopenharmony_ci caps.pps, 2918c2ecf20Sopenharmony_ci caps.n_pins, 2928c2ecf20Sopenharmony_ci caps.cross_timestamping, 2938c2ecf20Sopenharmony_ci caps.adjust_phase); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (0x7fffffff != adjfreq) { 2988c2ecf20Sopenharmony_ci memset(&tx, 0, sizeof(tx)); 2998c2ecf20Sopenharmony_ci tx.modes = ADJ_FREQUENCY; 3008c2ecf20Sopenharmony_ci tx.freq = ppb_to_scaled_ppm(adjfreq); 3018c2ecf20Sopenharmony_ci if (clock_adjtime(clkid, &tx)) { 3028c2ecf20Sopenharmony_ci perror("clock_adjtime"); 3038c2ecf20Sopenharmony_ci } else { 3048c2ecf20Sopenharmony_ci puts("frequency adjustment okay"); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (adjtime) { 3098c2ecf20Sopenharmony_ci memset(&tx, 0, sizeof(tx)); 3108c2ecf20Sopenharmony_ci tx.modes = ADJ_SETOFFSET; 3118c2ecf20Sopenharmony_ci tx.time.tv_sec = adjtime; 3128c2ecf20Sopenharmony_ci tx.time.tv_usec = 0; 3138c2ecf20Sopenharmony_ci if (clock_adjtime(clkid, &tx) < 0) { 3148c2ecf20Sopenharmony_ci perror("clock_adjtime"); 3158c2ecf20Sopenharmony_ci } else { 3168c2ecf20Sopenharmony_ci puts("time shift okay"); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (gettime) { 3218c2ecf20Sopenharmony_ci if (clock_gettime(clkid, &ts)) { 3228c2ecf20Sopenharmony_ci perror("clock_gettime"); 3238c2ecf20Sopenharmony_ci } else { 3248c2ecf20Sopenharmony_ci printf("clock time: %ld.%09ld or %s", 3258c2ecf20Sopenharmony_ci ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec)); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (settime == 1) { 3308c2ecf20Sopenharmony_ci clock_gettime(CLOCK_REALTIME, &ts); 3318c2ecf20Sopenharmony_ci if (clock_settime(clkid, &ts)) { 3328c2ecf20Sopenharmony_ci perror("clock_settime"); 3338c2ecf20Sopenharmony_ci } else { 3348c2ecf20Sopenharmony_ci puts("set time okay"); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (settime == 2) { 3398c2ecf20Sopenharmony_ci clock_gettime(clkid, &ts); 3408c2ecf20Sopenharmony_ci if (clock_settime(CLOCK_REALTIME, &ts)) { 3418c2ecf20Sopenharmony_ci perror("clock_settime"); 3428c2ecf20Sopenharmony_ci } else { 3438c2ecf20Sopenharmony_ci puts("set time okay"); 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (settime == 3) { 3488c2ecf20Sopenharmony_ci ts.tv_sec = seconds; 3498c2ecf20Sopenharmony_ci ts.tv_nsec = 0; 3508c2ecf20Sopenharmony_ci if (clock_settime(clkid, &ts)) { 3518c2ecf20Sopenharmony_ci perror("clock_settime"); 3528c2ecf20Sopenharmony_ci } else { 3538c2ecf20Sopenharmony_ci puts("set time okay"); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (extts) { 3588c2ecf20Sopenharmony_ci memset(&extts_request, 0, sizeof(extts_request)); 3598c2ecf20Sopenharmony_ci extts_request.index = index; 3608c2ecf20Sopenharmony_ci extts_request.flags = PTP_ENABLE_FEATURE; 3618c2ecf20Sopenharmony_ci if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) { 3628c2ecf20Sopenharmony_ci perror("PTP_EXTTS_REQUEST"); 3638c2ecf20Sopenharmony_ci extts = 0; 3648c2ecf20Sopenharmony_ci } else { 3658c2ecf20Sopenharmony_ci puts("external time stamp request okay"); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci for (; extts; extts--) { 3688c2ecf20Sopenharmony_ci cnt = read(fd, &event, sizeof(event)); 3698c2ecf20Sopenharmony_ci if (cnt != sizeof(event)) { 3708c2ecf20Sopenharmony_ci perror("read"); 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci printf("event index %u at %lld.%09u\n", event.index, 3748c2ecf20Sopenharmony_ci event.t.sec, event.t.nsec); 3758c2ecf20Sopenharmony_ci fflush(stdout); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci /* Disable the feature again. */ 3788c2ecf20Sopenharmony_ci extts_request.flags = 0; 3798c2ecf20Sopenharmony_ci if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) { 3808c2ecf20Sopenharmony_ci perror("PTP_EXTTS_REQUEST"); 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (flagtest) { 3858c2ecf20Sopenharmony_ci do_flag_test(fd, index); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (list_pins) { 3898c2ecf20Sopenharmony_ci int n_pins = 0; 3908c2ecf20Sopenharmony_ci if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) { 3918c2ecf20Sopenharmony_ci perror("PTP_CLOCK_GETCAPS"); 3928c2ecf20Sopenharmony_ci } else { 3938c2ecf20Sopenharmony_ci n_pins = caps.n_pins; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci for (i = 0; i < n_pins; i++) { 3968c2ecf20Sopenharmony_ci desc.index = i; 3978c2ecf20Sopenharmony_ci if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) { 3988c2ecf20Sopenharmony_ci perror("PTP_PIN_GETFUNC"); 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci printf("name %s index %u func %u chan %u\n", 4028c2ecf20Sopenharmony_ci desc.name, desc.index, desc.func, desc.chan); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (pulsewidth >= 0 && perout < 0) { 4078c2ecf20Sopenharmony_ci puts("-w can only be specified together with -p"); 4088c2ecf20Sopenharmony_ci return -1; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (perout_phase >= 0 && perout < 0) { 4128c2ecf20Sopenharmony_ci puts("-H can only be specified together with -p"); 4138c2ecf20Sopenharmony_ci return -1; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (perout >= 0) { 4178c2ecf20Sopenharmony_ci if (clock_gettime(clkid, &ts)) { 4188c2ecf20Sopenharmony_ci perror("clock_gettime"); 4198c2ecf20Sopenharmony_ci return -1; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci memset(&perout_request, 0, sizeof(perout_request)); 4228c2ecf20Sopenharmony_ci perout_request.index = index; 4238c2ecf20Sopenharmony_ci perout_request.period.sec = perout / NSEC_PER_SEC; 4248c2ecf20Sopenharmony_ci perout_request.period.nsec = perout % NSEC_PER_SEC; 4258c2ecf20Sopenharmony_ci perout_request.flags = 0; 4268c2ecf20Sopenharmony_ci if (pulsewidth >= 0) { 4278c2ecf20Sopenharmony_ci perout_request.flags |= PTP_PEROUT_DUTY_CYCLE; 4288c2ecf20Sopenharmony_ci perout_request.on.sec = pulsewidth / NSEC_PER_SEC; 4298c2ecf20Sopenharmony_ci perout_request.on.nsec = pulsewidth % NSEC_PER_SEC; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci if (perout_phase >= 0) { 4328c2ecf20Sopenharmony_ci perout_request.flags |= PTP_PEROUT_PHASE; 4338c2ecf20Sopenharmony_ci perout_request.phase.sec = perout_phase / NSEC_PER_SEC; 4348c2ecf20Sopenharmony_ci perout_request.phase.nsec = perout_phase % NSEC_PER_SEC; 4358c2ecf20Sopenharmony_ci } else { 4368c2ecf20Sopenharmony_ci perout_request.start.sec = ts.tv_sec + 2; 4378c2ecf20Sopenharmony_ci perout_request.start.nsec = 0; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (ioctl(fd, PTP_PEROUT_REQUEST2, &perout_request)) { 4418c2ecf20Sopenharmony_ci perror("PTP_PEROUT_REQUEST"); 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci puts("periodic output request okay"); 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (pin_index >= 0) { 4488c2ecf20Sopenharmony_ci memset(&desc, 0, sizeof(desc)); 4498c2ecf20Sopenharmony_ci desc.index = pin_index; 4508c2ecf20Sopenharmony_ci desc.func = pin_func; 4518c2ecf20Sopenharmony_ci desc.chan = index; 4528c2ecf20Sopenharmony_ci if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) { 4538c2ecf20Sopenharmony_ci perror("PTP_PIN_SETFUNC"); 4548c2ecf20Sopenharmony_ci } else { 4558c2ecf20Sopenharmony_ci puts("set pin function okay"); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (pps != -1) { 4608c2ecf20Sopenharmony_ci int enable = pps ? 1 : 0; 4618c2ecf20Sopenharmony_ci if (ioctl(fd, PTP_ENABLE_PPS, enable)) { 4628c2ecf20Sopenharmony_ci perror("PTP_ENABLE_PPS"); 4638c2ecf20Sopenharmony_ci } else { 4648c2ecf20Sopenharmony_ci puts("pps for system time request okay"); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (pct_offset) { 4698c2ecf20Sopenharmony_ci if (n_samples <= 0 || n_samples > 25) { 4708c2ecf20Sopenharmony_ci puts("n_samples should be between 1 and 25"); 4718c2ecf20Sopenharmony_ci usage(progname); 4728c2ecf20Sopenharmony_ci return -1; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci sysoff = calloc(1, sizeof(*sysoff)); 4768c2ecf20Sopenharmony_ci if (!sysoff) { 4778c2ecf20Sopenharmony_ci perror("calloc"); 4788c2ecf20Sopenharmony_ci return -1; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci sysoff->n_samples = n_samples; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (ioctl(fd, PTP_SYS_OFFSET, sysoff)) 4838c2ecf20Sopenharmony_ci perror("PTP_SYS_OFFSET"); 4848c2ecf20Sopenharmony_ci else 4858c2ecf20Sopenharmony_ci puts("system and phc clock time offset request okay"); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci pct = &sysoff->ts[0]; 4888c2ecf20Sopenharmony_ci for (i = 0; i < sysoff->n_samples; i++) { 4898c2ecf20Sopenharmony_ci t1 = pctns(pct+2*i); 4908c2ecf20Sopenharmony_ci tp = pctns(pct+2*i+1); 4918c2ecf20Sopenharmony_ci t2 = pctns(pct+2*i+2); 4928c2ecf20Sopenharmony_ci interval = t2 - t1; 4938c2ecf20Sopenharmony_ci offset = (t2 + t1) / 2 - tp; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci printf("system time: %lld.%09u\n", 4968c2ecf20Sopenharmony_ci (pct+2*i)->sec, (pct+2*i)->nsec); 4978c2ecf20Sopenharmony_ci printf("phc time: %lld.%09u\n", 4988c2ecf20Sopenharmony_ci (pct+2*i+1)->sec, (pct+2*i+1)->nsec); 4998c2ecf20Sopenharmony_ci printf("system time: %lld.%09u\n", 5008c2ecf20Sopenharmony_ci (pct+2*i+2)->sec, (pct+2*i+2)->nsec); 5018c2ecf20Sopenharmony_ci printf("system/phc clock time offset is %" PRId64 " ns\n" 5028c2ecf20Sopenharmony_ci "system clock time delay is %" PRId64 " ns\n", 5038c2ecf20Sopenharmony_ci offset, interval); 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci free(sysoff); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci close(fd); 5108c2ecf20Sopenharmony_ci return 0; 5118c2ecf20Sopenharmony_ci} 512