diff --git a/clock.h b/clock.h index 660abc1..e02dcfd 100644 --- a/clock.h +++ b/clock.h @@ -20,6 +20,16 @@ #define HAVE_CLOCK_H #include "ds.h" +#include "transport.h" + +#define MAX_PORTS 8 + +/** Defines a network interface, with PTP options. */ +struct interface { + char *name; + enum transport_type transport; + enum timestamp_type timestamping; +}; /** Opaque type. */ struct clock; @@ -47,6 +57,20 @@ struct port *clock_best_port(struct clock *c); */ UInteger8 clock_class(struct clock *c); +/** + * Create a clock instance. There can only be one clock in any system, + * so subsequent calls will destroy the previous clock instance. + * + * @param phc PTP hardware clock device to use. + * Pass NULL to select CLOCK_REALTIME. + * @param interface An array of network interfaces. + * @param count The number of elements in @a interfaces. + * @param ds A pointer to a default data set for the clock. + * @return A pointer to the single global clock instance. + */ +struct clock *clock_create(char *phc, struct interface *iface, int count, + struct defaultDS *ds); + /** * Obtains a clock's default data set. * @param c The clock instance. @@ -54,4 +78,11 @@ UInteger8 clock_class(struct clock *c); */ struct dataset *clock_default_ds(struct clock *c); +/** + * Poll for events and dispatch them. + * @param c A pointer to a clock instance obtained with clock_create(). + * @return Zero on success, non-zero otherwise. + */ +int clock_poll(struct clock *c); + #endif diff --git a/linuxptp.c b/linuxptp.c new file mode 100644 index 0000000..ecaa31f --- /dev/null +++ b/linuxptp.c @@ -0,0 +1,161 @@ +/** + * @file + * @note Copyright (C) 2011 Richard Cochran + * + * 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 +#include +#include +#include + +#include "clock.h" +#include "print.h" +#include "transport.h" +#include "udp.h" + +#define DEFAULT_PHC "/dev/ptp0" + +static int running = 1; +static struct defaultDS ds; + +static int generate_clock_identity(struct ClockIdentity *ci, char *name) +{ + unsigned char mac[6]; + if (udp_interface_macaddr(name, mac, sizeof(mac))) + return -1; + ci->id[0] = mac[0]; + ci->id[1] = mac[1]; + ci->id[2] = mac[2]; + ci->id[3] = 0xFF; + ci->id[4] = 0xFE; + ci->id[5] = mac[3]; + ci->id[6] = mac[4]; + ci->id[7] = mac[5]; + return 0; +} + +static void usage(char *progname) +{ + fprintf(stderr, + "\nusage: %s [options]\n\n" + " Network Transport\n\n" + " -2 IEEE 802.3\n" + " -4 UDP IPV4 (default)\n" + " -6 UDP IPV6\n\n" + " Time Stamping\n\n" + " -r HARDWARE (default)\n" + " -s SOFTWARE\n" + " -z LEGACY HW\n\n" + " Other Options\n\n" + " -h prints this message and exits\n" + " -i [dev] interface device to use, for example 'eth0'\n" + " (may be specified multiple times)\n" + " -p [dev] PTP hardware clock device to use, default '%s'\n" + " (ignored when SOFTWARE time stamping is selected)\n\n", + progname, DEFAULT_PHC); +} + +int main(int argc, char *argv[]) +{ + char *phc = DEFAULT_PHC, *progname; + int c, i, nports = 0; + struct interface iface[MAX_PORTS]; + enum transport_type transport = TRANS_UDP_IPV4; + enum timestamp_type timestamping = TS_HARDWARE; + struct clock *clock; + + /* Process the command line arguments. */ + progname = strrchr(argv[0], '/'); + progname = progname ? 1+progname : argv[0]; + while (EOF != (c = getopt(argc, argv, "246hi:p:rsz"))) { + switch (c) { + case '2': + transport = TRANS_IEEE_802_3; + break; + case '4': + transport = TRANS_UDP_IPV4; + break; + case '6': + transport = TRANS_UDP_IPV6; + break; + case 'i': + if (nports < MAX_PORTS) { + iface[nports++].name = optarg; + } else { + fprintf(stderr, "too many interfaces\n"); + return -1; + } + break; + case 'p': + phc = optarg; + break; + case 'r': + timestamping = TS_HARDWARE; + break; + case 's': + timestamping = TS_SOFTWARE; + break; + case 'z': + timestamping = TS_LEGACY_HW; + break; + case 'h': + usage(progname); + return 0; + case '?': + usage(progname); + return -1; + default: + usage(progname); + return -1; + } + } + + if (!nports) { + usage(progname); + return -1; + } + for (i = 0; i < nports; i++) { + iface[i].transport = transport; + iface[i].timestamping = timestamping; + } + if (timestamping == TS_SOFTWARE) { + phc = NULL; + } + + ds.priority1 = 128; + ds.clockQuality.clockClass = 248; + ds.clockQuality.clockAccuracy = 0xfe; + ds.clockQuality.offsetScaledLogVariance = 0xffff; + ds.priority2 = 128; + + if (generate_clock_identity(&ds.clockIdentity, iface[0].name)) { + fprintf(stderr, "failed to generate a clock identity\n"); + return -1; + } + + clock = clock_create(phc, iface, nports, &ds); + if (!clock) { + fprintf(stderr, "failed to create a clock\n"); + return -1; + } + + while (running) { + if (clock_poll(clock)) + break; + } + + return 0; +} diff --git a/makefile b/makefile index 6c04669..db0f514 100644 --- a/makefile +++ b/makefile @@ -24,7 +24,8 @@ CFLAGS = -Wall $(INC) $(DEBUG) LDFLAGS = LDLIBS = -lm -lrt PRG = linuxptp -OBJ = bmc.o fsm.o msg.o phc.o pi.o print.o servo.o transport.o udp.o util.o +OBJ = bmc.o fsm.o linuxptp.o msg.o phc.o pi.o print.o \ + servo.o transport.o udp.o util.o SRC = $(OBJ:.o=.c) DEPEND = $(OBJ:.o=.d)