1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-16 08:12:53 +08:00
corundum/utils/perout.c

171 lines
4.0 KiB
C
Raw Normal View History

// SPDX-License-Identifier: BSD-2-Clause-Views
2019-07-17 18:48:50 -07:00
/*
* Copyright (c) 2019-2023 The Regents of the University of California
*/
2019-07-17 18:48:50 -07:00
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <linux/ptp_clock.h>
#include "timespec.h"
2019-07-17 18:48:50 -07:00
#ifndef CLOCK_INVALID
#define CLOCK_INVALID -1
#endif
static clockid_t get_clockid(int fd)
{
#define CLOCKFD 3
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
return FD_TO_CLOCKID(fd);
}
#define NSEC_PER_SEC 1000000000
static void usage(char *name)
{
fprintf(stderr,
"usage: %s [options]\n"
" -d name device to open\n"
" -s number start time (ns)\n"
" -p number period (ns)\n",
name);
}
int main(int argc, char *argv[])
{
char *name;
int opt;
char *device = NULL;
int ptp_fd;
clockid_t clkid;
struct ptp_perout_request perout_request;
struct timespec ts_now;
struct timespec ts_start;
struct timespec ts_period;
2019-07-17 18:48:50 -07:00
int64_t start_nsec = 0;
int64_t period_nsec = 0;
name = strrchr(argv[0], '/');
name = name ? 1+name : argv[0];
while ((opt = getopt(argc, argv, "d:s:p:h?")) != EOF)
{
switch (opt)
{
case 'd':
device = optarg;
break;
case 's':
start_nsec = atoll(optarg);
break;
case 'p':
period_nsec = atoll(optarg);
break;
case 'h':
case '?':
usage(name);
return 0;
default:
usage(name);
return -1;
}
}
if (!device)
{
fprintf(stderr, "PTP device not specified\n");
usage(name);
return -1;
}
ptp_fd = open(device, O_RDWR);
if (ptp_fd < 0)
{
fprintf(stderr, "Failed to open %s: %s\n", device, strerror(errno));
return -1;
}
clkid = get_clockid(ptp_fd);
if (clkid == CLOCK_INVALID)
{
fprintf(stderr, "Failed to read clock id\n");
close(ptp_fd);
return -1;
}
if (period_nsec > 0)
{
if (clock_gettime(clkid, &ts_now))
2019-07-17 18:48:50 -07:00
{
perror("Failed to read current time");
return -1;
}
// normalize start
ts_start.tv_sec = start_nsec / NSEC_PER_SEC;
ts_start.tv_nsec = start_nsec - ts_start.tv_sec * NSEC_PER_SEC;
2019-07-17 18:48:50 -07:00
// normalize period
ts_period.tv_sec = period_nsec / NSEC_PER_SEC;
ts_period.tv_nsec = period_nsec - ts_period.tv_sec * NSEC_PER_SEC;
2019-07-17 18:48:50 -07:00
printf("time %ld.%09ld\n", ts_now.tv_sec, ts_now.tv_nsec);
printf("start %ld.%09ld\n", ts_start.tv_sec, ts_start.tv_nsec);
printf("period %ld.%09ld\n", ts_period.tv_sec, ts_period.tv_nsec);
2019-07-17 18:48:50 -07:00
if (timespec_lt(ts_start, ts_now))
2019-07-17 18:48:50 -07:00
{
// start time is in the past
// modulo start with period
ts_start = timespec_mod(ts_start, ts_period);
2019-07-17 18:48:50 -07:00
// align time with period
struct timespec ts_aligned = timespec_sub(ts_now, timespec_mod(ts_now, ts_period));
// add aligned time
ts_start = timespec_add(ts_start, ts_aligned);
2019-07-17 18:48:50 -07:00
}
printf("time %ld.%09ld\n", ts_now.tv_sec, ts_now.tv_nsec);
printf("start %ld.%09ld\n", ts_start.tv_sec, ts_start.tv_nsec);
printf("period %ld.%09ld\n", ts_period.tv_sec, ts_period.tv_nsec);
2019-07-17 18:48:50 -07:00
memset(&perout_request, 0, sizeof(perout_request));
perout_request.index = 0;
perout_request.start.sec = ts_start.tv_sec;
perout_request.start.nsec = ts_start.tv_nsec;
perout_request.period.sec = ts_period.tv_sec;
perout_request.period.nsec = ts_period.tv_nsec;
2019-07-17 18:48:50 -07:00
if (ioctl(ptp_fd, PTP_PEROUT_REQUEST, &perout_request))
{
perror("PTP_PEROUT_REQUEST ioctl failed");
}
else
{
printf("PTP_PEROUT_REQUEST ioctl OK\n");
}
}
close(ptp_fd);
return 0;
}