On Fri, Dec 08, 2017 at 11:09:40PM +0000, Keller, Jacob E wrote:
> I'm thinking the best way is to use the external timestamp events setup, and 
> then plug that in as the pps source into phc2sys?
> 
> Does this make any sense, or am I paddling up the wrong creek?

So you *could* extend phc2sys, but that program is complex enough as
is.  I have made thoughts about a successor to phc2sys that would
handle gpio based measurements, including setting the pin functions
using the PHC ioctls.

But for now, I would just write a simple program for your specific
setup.  Below is an example for using three i210 cards whose first SDP
are connected.  The first card is hard coded as the PPS producer.  In
a more realistic JBOD setting, you would want to switch the PPS
producer to be the PHC of the port that takes on the SLAVE role.

HTH,
Richard

--->8---
/**
 * @file synbc.c
 * @brief Synchronize the ports of a JBOD Boundary Clock.
 * @note Copyright (C) 2015 Richard Cochran <richardcoch...@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>

#include <linux/ptp_clock.h>

#include "clockadj.h"
#include "config.h"
#include "phc.h"
#include "print.h"
#include "servo.h"
#include "util.h"

#define N_PHC 3

static int synbc_extts(int fd, int enable)
{
        struct ptp_extts_request extts_request;
        int index = 0;
        memset(&extts_request, 0, sizeof(extts_request));
        extts_request.index = index;
        extts_request.flags = enable ? PTP_ENABLE_FEATURE : 0;
        if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
                pr_err("PTP_EXTTS_REQUEST");
                return -1;
        }
        pr_info("external time stamp request okay");
        return 0;
}

static int synbc_pin_input(int fd)
{
        struct ptp_pin_desc desc;
        int index = 0, pin_index = 0;

        memset(&desc, 0, sizeof(desc));
        desc.index = pin_index;
        desc.func = PTP_PF_EXTTS;
        desc.chan = index;
        if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
                pr_err("PTP_PIN_SETFUNC");
                return -1;
        }
        pr_info("set pin function okay");
        return 0;
}

static int synbc_pin_output(int fd)
{
        struct ptp_pin_desc desc;
        int index = 0, pin_index = 0;

        memset(&desc, 0, sizeof(desc));
        desc.index = pin_index;
        desc.func = PTP_PF_PEROUT;
        desc.chan = index;
        if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
                pr_err("PTP_PIN_SETFUNC");
                return -1;
        }
        pr_info("set pin function okay");
        return 0;
}

static int synbc_pps_output(clockid_t clkid, int fd)
{
        struct ptp_perout_request perout_request;
        struct timespec ts;
        int index = 0, perout = 2000000000;

        if (clock_gettime(clkid, &ts)) {
                pr_err("clock_gettime");
                return -1;
        }
        memset(&perout_request, 0, sizeof(perout_request));
        perout_request.index = index;
        /*disable old setting*/
        if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
                pr_err("PTP_PEROUT_REQUEST");
                return -1;
        }
        perout_request.start.sec = ts.tv_sec + 2;
        perout_request.start.nsec = 0;
        perout_request.period.sec = 0;
        perout_request.period.nsec = perout;
        if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
                pr_err("PTP_PEROUT_REQUEST");
                return -1;
        }
        pr_info("periodic output request okay");
        return 0;
}

static int synbc_settime(clockid_t *clkid)
{
        struct timespec ts;
        int i;
        if (clock_gettime(clkid[0], &ts)) {
                pr_err("clock_gettime");
                return -1;
        }
        for (i = 1; i < N_PHC; i++) {
                if (clock_settime(clkid[i], &ts)) {
                        pr_err("clock_settime");
                        return -1;
                }
        }
        return 0;
}

int main()
{
        int fd[N_PHC], i;
        clockid_t clkid[N_PHC];
        struct config *config;
        struct pollfd pfd[N_PHC - 1];
        struct servo *servo[N_PHC - 1];
        char device[64];

        handle_term_signals();
        print_set_progname("synbc");
        print_set_verbose(1);
        print_set_syslog(0);

        config = config_create();
        if (!config)
                return -1;

        for (i = 0; i < N_PHC; i++) {
                snprintf(device, sizeof(device), "/dev/ptp%d", i);
                clkid[i] = phc_open(device);
                if (CLOCK_INVALID == clkid[i]) {
                        pr_err("Failed to open %s: %m", device);
                        return -1;
                }
                fd[i] = CLOCKID_TO_FD(clkid[i]);
        }

        for (i = 1; i < N_PHC; i++) {
                servo[i - 1] = servo_create(config, CLOCK_SERVO_PI, 0, 100000, 
0);
                if (!servo[i - 1])
                        return -1;
                servo_sync_interval(servo[i - 1], 1.0);
        }

        if (synbc_settime(clkid))
                return -1;

        /* Configure a 1 PPS between the cards. */

        if (synbc_pin_output(fd[0]))
                return -1;

        for (i = 1; i < N_PHC; i++)
                if (synbc_pin_input(fd[i]))
                        return -1;

        if (synbc_pps_output(clkid[0], fd[0]))
                return -1;

        for (i = 1; i < N_PHC; i++)
                if (synbc_extts(fd[i], 1))
                        return -1;

        for (i = 1; i < N_PHC; i++) {
                pfd[i - 1].fd = fd[i];
                pfd[i - 1].events = POLLIN | POLLPRI;
        }

        while (is_running()) {
                int cnt = poll(pfd, N_PHC - 1, 1000);
                if (cnt < 0) {
                        if (EINTR == errno) {
                                continue;
                        } else {
                                pr_emerg("poll failed");
                                return -1;
                        }
                } else if (!cnt) {
                        pr_err("no PPS");
                        continue;
                }
                for (i = 1; i < N_PHC; i++) {
                        if (pfd[i - 1].revents & (POLLIN | POLLPRI)) {

                                struct ptp_extts_event event;
                                enum servo_state state;
                                double ppb;
                                int64_t offset;
                                uint64_t ts;

                                cnt = read(fd[i], &event, sizeof(event));
                                if (cnt != sizeof(event)) {
                                        perror("read");
                                        break;
                                }
                                pr_debug("ptp%d event at %lld.%09u", i,
                                         event.t.sec, event.t.nsec);

                                ts = event.t.sec * NS_PER_SEC;
                                ts += event.t.nsec;
                                offset = ts % NS_PER_SEC;
                                if (offset > NS_PER_SEC / 2)
                                        offset -= NS_PER_SEC;

                                ppb = servo_sample(servo[i - 1], offset, ts,
                                                   1.0, &state);

                                pr_info("ptp%d offset %10" PRId64 " s%d freq 
%+7.0f ",
                                        i, offset, state, ppb);

                                switch (state) {
                                case SERVO_UNLOCKED:
                                        break;
                                case SERVO_JUMP:
                                        clockadj_step(clkid[i], -offset);
                                        /* Fall through. */
                                case SERVO_LOCKED:
                                        clockadj_set_freq(clkid[i], -ppb);
                                        break;
                                }

                        }
                }
        }

        for (i = 1; i < N_PHC; i++)
                if (synbc_extts(fd[i], 0))
                        pr_err("hm");

        for (i = 0; i < N_PHC; i++)
                phc_close(clkid[i]);

        for (i = 1; i < N_PHC; i++)
                servo_destroy(servo[i - 1]);

        config_destroy(config);

        return 0;
}


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to