diff options
| author | Yuval Adam <yuv.adm@gmail.com> | 2014-08-08 14:42:07 +0300 |
|---|---|---|
| committer | Yuval Adam <yuv.adm@gmail.com> | 2014-08-08 14:42:07 +0300 |
| commit | a6163888f3c56123b1db313743c6147ba498732c (patch) | |
| tree | ff7d15d991d1d09ba6cbc0cec80924f57445bfdd /third_party/ptpd-1.1.0 | |
| parent | c3e4c9a25c2910d2d66d52215b3406b13d5b23d5 (diff) | |
Add third_party libs
Diffstat (limited to 'third_party/ptpd-1.1.0')
44 files changed, 10519 insertions, 0 deletions
diff --git a/third_party/ptpd-1.1.0/COPYRIGHT b/third_party/ptpd-1.1.0/COPYRIGHT new file mode 100644 index 0000000..cbc5b04 --- /dev/null +++ b/third_party/ptpd-1.1.0/COPYRIGHT @@ -0,0 +1,18 @@ +The following copyright notice applies to all files which compose the
+PTPd. This notice applies as if the text was explicitly included each
+file.
+
+Copyright (c) 2009-2010 George V. Neville-Neil, Steven Kreuzer, Martin Burnicki
+Copyright (c) 2005-2008 Kendall Correll, Aidan Williams
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/third_party/ptpd-1.1.0/ChangeLog b/third_party/ptpd-1.1.0/ChangeLog new file mode 100644 index 0000000..787b424 --- /dev/null +++ b/third_party/ptpd-1.1.0/ChangeLog @@ -0,0 +1,17 @@ +2010-10-12 George Neville-Neil <gnn@neville-neil.com>
+
+ * 1.1.0 Release
+
+ * Add code to limit how much of an offset or delay the client is
+ willing to tolerate.
+
+ * Add support for BINTIME on FreeBSD which gives more accurate
+ packet timestamps.
+
+ * Add quality file support
+
+ * Add support for syslog.
+
+ * Add support for user configurable TTL.
+
+ * Clean up code formatting, headers, comments etc.
diff --git a/third_party/ptpd-1.1.0/Makefile b/third_party/ptpd-1.1.0/Makefile new file mode 100644 index 0000000..8de8a93 --- /dev/null +++ b/third_party/ptpd-1.1.0/Makefile @@ -0,0 +1,17 @@ +# Root Makefile for ptpd, used for cutting releases
+
+VERSION = ptpd-1.1.0
+
+release:
+ (cd src; make clean)
+ mkdir $(VERSION)
+ (cd $(VERSION); \
+ ln -s ../src .; \
+ ln -s ../doc .; \
+ ln -s ../tools .; \
+ ln -s ../COPYRIGHT .; \
+ ln -s ../ChangeLog .; \
+ ln -s ../Makefile .; \
+ ln -s ../README .; \
+ ln -s ../RELEASE_NOTES .)
+ tar cvzf $(VERSION).tar.gz -L --exclude .o --exclude Doxygen --exclude .svn --exclude .dep --exclude core $(VERSION)
diff --git a/third_party/ptpd-1.1.0/README b/third_party/ptpd-1.1.0/README new file mode 100644 index 0000000..8261176 --- /dev/null +++ b/third_party/ptpd-1.1.0/README @@ -0,0 +1,37 @@ +README for PTPd
+
+
+- Introduction -
+
+This is the source code for the PTP daemon (PTPd). PTPd implements the
+Precision Time Protocol (PTP) as defined by 'IEEE Std 1588-2002'. PTP
+provides precise time coordination of Ethernet LAN connected computers. It
+was designed primarily for instrumentation and control systems.
+
+
+- Use -
+
+PTPd can coordinate the clocks of a group of LAN connected computers with each
+other. It has been shown to achieve microsecond level coordination, even on
+limited platforms.
+
+The 'ptpd' program can be built from the included source code; see the release
+notes about platform compatibility. To use the program, run 'ptpd' on a group of
+LAN connected computers. Compile with 'PTPD_DBG' defined and run with the '-c'
+argument to watch what's going on.
+
+If you are just looking for software to update the time on your desktop, you
+probably want something that implements the Network Time Protocol. It can
+coordinate computer clocks with an absolute time reference such as UTC.
+
+
+- Legal notice -
+
+PTPd was written by using only information contained within 'IEEE Std
+1588-2002'. IEEE 1588 may contain patented technology, the use of which is not
+under the control of the authors of PTPd. Users of IEEE 1588 may need to obtain
+a license for the patented technology in the protocol. Contact the IEEE for
+licensing information.
+
+PTPd comes with absolutely no warranty.
+
diff --git a/third_party/ptpd-1.1.0/RELEASE_NOTES b/third_party/ptpd-1.1.0/RELEASE_NOTES new file mode 100644 index 0000000..2c79ca3 --- /dev/null +++ b/third_party/ptpd-1.1.0/RELEASE_NOTES @@ -0,0 +1,148 @@ +RELEASE_NOTES for PTPd
+
+v1.0.0, 9 August 2008:
+
+The long over due 1.0 release. A few small fixes, the most notable of which is a
+fix to check the revision of an IEEE-1588 message to prevent PTPd from
+interfering with IEEE-1588 v2 devices on the same network. There are some extras
+thanks to contributors, including an updated MPC8313E patch, a QNX patch, and a
+man page. PTPd v1 will be branched in the repository, and work toward IEEE-1588
+v2 will begin on the trunk.
+
+v1rc1, 17 June 2007:
+
+This release fixes a regression in v1b5 that broke unicast support. It also adds
+a PTPd patch posted on the website for 1588 hardware support on MPC8313E
+processors.
+
+v1b5, 3 December 2006:
+
+PTPd is now ported to *BSD. Also, there are small fixes for 64-bit
+architectures, better interface search on Linux, and disallow master mode if the
+stratum is 255 for 1588 spec compliance. There is a fairly large change to
+separate the internal time representation from the external IEEE 1588 time
+representation. This significantly simplifies the time arithmetic functions, and
+it should allow PTPd to work properly after 2038 despite the fact that the Linux
+clock will rollover. PTPd should run seamlessly through 2038 as a slave, but to
+run PTPd as a master after 2038, you need to set the 'half epoch' flag with the
+'-h' command line option. Finally, there is a change so that PTPd no longer
+needs a kernel modification to retrieve send time stamps. PTPd now retrieves
+send time stamps from looped back received messages.
+
+ -kendall
+
+
+v1b4, 28 June 2006:
+
+More fixes, including some to make PTPd work with the PTPManager program. The
+default UTC offset has also been changed again. Now it is zero to comply with
+the 1588 spec, which says that unless a clock is otherwise synced to UTC, it
+should report a UTC offset of zero. The '-t' option (don't adjust the clock) has
+been fixed so that it also prevents zeroing the frequency at start up. The
+ability to query a network with management messages has been added with the '-k'
+option. Finally, PTPd's timer and polling mechanism has been changed to allow it
+to respond immediately to received messages.
+
+ -kendall
+
+
+v1b3, 6 March 2006:
+
+There has been some useful feedback since the last release. This release
+contains some requested bug fixes including an update of the default UTC offset.
+This release also adds a requested slave-only mode. Thanks to everyone for the
+input.
+
+ -kendall
+
+
+v1b2, 8 December 2005:
+
+There has been no feedback from the previous release, so this release does not
+contain any significant changes to the source. This release is just the few
+minor source changes still sitting in CVS, along with some cleaning of the extra
+bits like the documentation and tools. Also, I have removed the 'parpp' tool
+from the distribution because its use is not straightforward, and I think it may
+be more confusing than helpful to casual users. Finally, I included a PDF of the
+paper I wrote for the 2005 Conference on IEEE 1588 to make up for my languishing
+source code documentation effort.
+
+ -kendall
+
+
+v1b1, 18 October 2005:
+
+The site seems to be getting some downloads, so I want this latest code out
+there. There are only small changes. The number of foreign master records now
+has a command-line option. Also, the the 'Q' randomization of Delay Request
+messages is essentially disabled because I realized it was not implemented
+correctly. This is no big deal, because PTPd's Delay Requests do not occur in a
+consistent part of the Sync interval window, so they are implicitly randomized.
+Anyway, PTPd has been plug-fested a couple of times, and everything seems to
+work well, so I am comfortable calling this a beta release. Hopefully people
+will try the program out and help shake out some bugs.
+
+ -kendall
+
+
+v1a4, 24 September 2005:
+
+A fair amount of changes, most of which I do not recall. Fixing support for all
+of the management messages is one that comes to mind. A fix that sets socket
+reuse is another one. Also, there's a fix to the initial clock reset that
+allows it to start up very close to master clock time. In general, this release
+is more stream-lining and tightening up core functionality. I think that the
+protocol stack and the clock servo are feature complete for v1. I will be
+testing this release at the IEEE 1588 conference in Zurich. After that, I will
+probably tag my next release as beta.
+
+ -kendall
+
+
+v1a3, 17 August 2005:
+
+Lots of changes. PTPd functions essentially the same as before, but the code has
+been reorganized and trimmed. Also, PTPd now has a real clock servo, and there
+is a hook for kernel send time stamps. The stock Linux kernel does not have
+a send time stamp, so you'll have to implement your own. I'd be glad to provide
+instructions how or kernel patches if anyone is interested. PTPd has shown the
+ability to hold coordination solidly within 10us running on a 66MHz M68k.
+
+ -kendall
+
+
+v1a2, 4 June 2005:
+
+PTPd can now be built with 'make'. It also includes a little bit of usage
+information in README. This release also fixes a broken clock servo that
+caused a slave with a time greater than master clock time to run away from
+master clock time. Finally, it includes an updated 'parpp' that hopefully
+can be used to precisely quantify the precision of clock coordination.
+
+ -kendall
+
+
+v1a1, 25 May 2005:
+
+This is the first public source code release of PTPd. The source has been
+compiled with gcc and tested on an x86 Linux machine. The code may work on
+big-endian machines as well, but it will only work on 32-bit Linux machines.
+
+This release also includes a kernel module that generates a pulse-per-second
+(PPS) on the most significant data bit of a PC parallel port. The PPS
+generated by PTP systems can be used to verify their clock coordination. The
+included PPS generator is not precise, so it does not provide a good way to
+quantify the time coordination precision.
+
+All of this code is a work in progress. Please feel free to mess around with
+it and use it as you wish. While I can offer no support, I welcome any
+questions/comments on porting, bugs, features, or anything else. One
+exception, please do not ask me what PTP is. One can learn more about PTP
+from the IEEE 1588 specification, and one can join the LXI Consortium to
+work with the companies using PTP.
+
+Finally, this release is not intended to be a functional PTP system
+(although one can be built from it using 'gcc ptpd.c -o ptpd'). It should
+not be too hard to figure out how to use it if you dig into the source.
+
+ -kendall
diff --git a/third_party/ptpd-1.1.0/doc/clock_servo.svg b/third_party/ptpd-1.1.0/doc/clock_servo.svg new file mode 100644 index 0000000..713d77d --- /dev/null +++ b/third_party/ptpd-1.1.0/doc/clock_servo.svg @@ -0,0 +1,350 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.0"
+ width="700"
+ height="250"
+ id="svg2">
+ <defs
+ id="defs3" />
+ <g
+ id="layer1">
+ <path
+ d="M 74,202.5 L 452.5,202.5 L 452.5,80"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3663" />
+ <polyline
+ points="16510,6352 19685,6352"
+ id="polyline2275"
+ style="fill:none;stroke:#000000;stroke-width:27.03482819;stroke-miterlimit:4;stroke-dasharray:none"
+ transform="matrix(3.861393e-2,0,0,3.543307e-2,-160.516,-66.07086)" />
+ <polyline
+ points="5080,4447 14605,4447"
+ id="polyline2277"
+ style="fill:none;stroke:#000000;stroke-width:27.88088608;stroke-miterlimit:4;stroke-dasharray:none"
+ transform="matrix(3.630597e-2,0,0,3.543307e-2,-103.732,-89.83858)" />
+ <polyline
+ points="8890,4447 8890,6352"
+ id="polyline2279"
+ style="fill:none;stroke:#000000;stroke-width:28.22222328;stroke-miterlimit:4"
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)" />
+ <polyline
+ points="5080,6987 8890,6987"
+ id="polyline2281"
+ style="fill:none;stroke:#000000;stroke-width:22.10805321;stroke-miterlimit:4;stroke-dasharray:none"
+ transform="matrix(5.774179e-2,0,0,3.543307e-2,-212.3245,-89.83858)" />
+ <polyline
+ points="15557,5082 14605,5082 14605,3812 16510,3812 16510,5082 15557,5082"
+ id="polyline2289"
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-98.65352,-89.83858)"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:28.22222328;stroke-miterlimit:4;stroke-opacity:1" />
+ <polyline
+ points="15240,7622 13970,7622 13970,5717 16510,5717 16510,7622 15240,7622"
+ id="polyline2303"
+ transform="matrix(3.972112e-2,0,0,3.543307e-2,-152.7534,-89.84251)"
+ style="font-size:494px;font-weight:400;fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:28.22222328;stroke-miterlimit:4;stroke-opacity:1;font-family:Nimbus Roman No9 L" />
+ <polygon
+ points="9525,6996 9524,6964 9522,6933 9518,6901 9512,6870 9505,6839 9496,6809 9485,6779 9474,6749 9460,6720 9445,6692 9429,6665 9411,6638 9392,6613 9372,6588 9350,6565 9327,6542 9304,6521 9279,6501 9253,6482 9226,6465 9198,6449 9170,6434 9140,6421 9111,6409 9080,6399 9049,6390 9018,6383 8986,6377 8954,6373 8922,6371 8890,6370 8890,6370 8858,6371 8826,6373 8794,6377 8762,6383 8731,6390 8700,6399 8669,6409 8640,6421 8610,6434 8582,6449 8554,6465 8527,6482 8501,6501 8476,6521 8453,6542 8430,6565 8408,6588 8388,6613 8369,6638 8351,6665 8335,6692 8320,6720 8306,6749 8295,6779 8284,6809 8275,6839 8268,6870 8262,6901 8258,6933 8256,6964 8255,6996 8255,6996 8256,7028 8258,7059 8262,7091 8268,7122 8275,7153 8284,7183 8295,7213 8306,7243 8320,7272 8335,7300 8351,7327 8369,7354 8388,7379 8408,7404 8430,7427 8453,7450 8476,7471 8501,7491 8527,7510 8554,7527 8582,7543 8610,7558 8640,7571 8669,7583 8700,7593 8731,7602 8762,7609 8794,7615 8826,7619 8858,7621 8890,7622 8890,7622 8922,7621 8954,7619 8986,7615 9018,7609 9049,7602 9080,7593 9111,7583 9140,7571 9170,7558 9198,7543 9226,7527 9253,7510 9279,7491 9304,7471 9327,7450 9350,7427 9372,7404 9392,7379 9411,7354 9429,7327 9445,7300 9460,7272 9474,7243 9485,7213 9496,7183 9505,7153 9512,7122 9518,7091 9522,7059 9524,7028 9525,6996 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)"
+ style="font-size:494px;font-weight:400;fill:#ffffff;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2313" />
+ <polygon
+ points="6985,4447 6680,4345 6680,4548 6985,4447 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)"
+ style="font-size:494px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2325" />
+ <polyline
+ points="20955,5715 20955,5323"
+ id="polyline2541"
+ transform="matrix(3.543307e-2,0,0,7.65343e-2,-101.2348,-298.1284)"
+ style="font-size:494px;font-weight:400;fill:none;stroke:#000000;stroke-width:19.20293236;stroke-miterlimit:4;stroke-dasharray:none;font-family:Nimbus Roman No9 L" />
+ <polygon
+ points="19685,5717 22225,5717 22225,7622 19685,7622 19685,5717 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-101,-66.07086)"
+ style="font-size:494px;font-weight:400;fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:28.22222328;stroke-miterlimit:4;stroke-opacity:1;font-family:Nimbus Roman No9 L"
+ id="polygon2333" />
+ <polygon
+ points="22225,3811 22223,3747 22218,3682 22210,3619 22199,3555 22184,3492 22167,3431 22146,3370 22122,3310 22095,3251 22065,3194 22033,3139 21997,3085 21959,3033 21919,2983 21875,2935 21830,2890 21782,2847 21732,2806 21681,2768 21627,2732 21571,2700 21514,2670 21456,2643 21396,2619 21335,2598 21273,2581 21211,2566 21147,2555 21083,2547 21019,2542 20955,2540 20955,2540 20891,2542 20827,2547 20763,2555 20699,2566 20637,2581 20575,2598 20514,2619 20454,2643 20396,2670 20339,2700 20283,2732 20229,2768 20178,2806 20128,2847 20080,2890 20035,2935 19991,2983 19951,3033 19913,3085 19877,3139 19845,3194 19815,3251 19788,3310 19764,3370 19743,3431 19726,3492 19711,3555 19700,3619 19692,3682 19687,3747 19685,3811 19685,3811 19687,3875 19692,3940 19700,4003 19711,4067 19726,4130 19743,4191 19764,4252 19788,4312 19815,4371 19845,4428 19877,4483 19913,4537 19951,4589 19991,4639 20035,4687 20080,4732 20128,4775 20178,4816 20229,4854 20283,4890 20339,4922 20396,4952 20454,4979 20514,5003 20575,5024 20637,5041 20699,5056 20763,5067 20827,5075 20891,5080 20955,5082 20955,5082 21019,5080 21083,5075 21147,5067 21211,5056 21273,5041 21335,5024 21396,5003 21456,4979 21514,4952 21571,4922 21627,4890 21681,4854 21732,4816 21782,4775 21830,4732 21875,4687 21919,4639 21959,4589 21997,4537 22033,4483 22065,4428 22095,4371 22122,4312 22146,4252 22167,4191 22184,4130 22199,4067 22210,4003 22218,3940 22223,3875 22225,3811 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-101,-65.07086)"
+ style="font-size:494px;font-weight:400;fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:28.22222328;stroke-miterlimit:4;stroke-opacity:1;font-family:Nimbus Roman No9 L"
+ id="polygon2349" />
+ <polygon
+ points="3175,3812 5080,3812 5080,8892 3175,8892 3175,3812 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)"
+ style="font-size:494px;font-weight:400;fill:#ffffff;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2361" />
+ <polyline
+ points="4127,8892 3175,8892 3175,3812 5080,3812 5080,8892 4127,8892"
+ id="polyline2365"
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)"
+ style="font-size:494px;font-weight:400;fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:28.22222328;stroke-miterlimit:4;stroke-opacity:1;font-family:Nimbus Roman No9 L" />
+ <polygon
+ points="12065,4456 12064,4424 12062,4393 12058,4361 12052,4330 12045,4299 12036,4269 12025,4239 12014,4209 12000,4180 11985,4152 11969,4125 11951,4098 11932,4073 11912,4048 11890,4025 11867,4002 11844,3981 11819,3961 11793,3942 11766,3925 11738,3909 11710,3894 11680,3881 11651,3869 11620,3859 11589,3850 11558,3843 11526,3837 11494,3833 11462,3831 11430,3830 11430,3830 11398,3831 11366,3833 11334,3837 11302,3843 11271,3850 11240,3859 11209,3869 11180,3881 11150,3894 11122,3909 11094,3925 11067,3942 11041,3961 11016,3981 10993,4002 10970,4025 10948,4048 10928,4073 10909,4098 10891,4125 10875,4152 10860,4180 10846,4209 10835,4239 10824,4269 10815,4299 10808,4330 10802,4361 10798,4393 10796,4424 10795,4456 10795,4456 10796,4488 10798,4519 10802,4551 10808,4582 10815,4613 10824,4643 10835,4673 10846,4703 10860,4732 10875,4760 10891,4787 10909,4814 10928,4839 10948,4864 10970,4887 10993,4910 11016,4931 11041,4951 11067,4970 11094,4987 11122,5003 11150,5018 11180,5031 11209,5043 11240,5053 11271,5062 11302,5069 11334,5075 11366,5079 11398,5081 11430,5082 11430,5082 11462,5081 11494,5079 11526,5075 11558,5069 11589,5062 11620,5053 11651,5043 11680,5031 11710,5018 11738,5003 11766,4987 11793,4970 11819,4951 11844,4931 11867,4910 11890,4887 11912,4864 11932,4839 11951,4814 11969,4787 11985,4760 12000,4732 12014,4703 12025,4673 12036,4643 12045,4613 12052,4582 12058,4551 12062,4519 12064,4488 12065,4456 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)"
+ style="font-size:423px;font-weight:400;fill:#ffffff;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2407" />
+ <polyline
+ points="11430,5082 11430,6352"
+ style="font-size:494px;font-weight:400;fill:none;stroke:#000000;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polyline2423"
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)" />
+ <polygon
+ points="8890,5717 8991,5412 8788,5412 8890,5717 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)"
+ style="font-size:423px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2435" />
+ <polygon
+ points="6985,6987 6680,6885 6680,7088 6985,6987 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)"
+ style="font-size:423px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2443" />
+ <polygon
+ points="10160,4447 9855,4345 9855,4548 10160,4447 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-96.1555,-89.83858)"
+ style="font-size:423px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2451" />
+ <polygon
+ points="10160,6987 9855,6885 9855,7088 10160,6987 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-94.1555,-89.95669)"
+ style="font-size:423px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2459" />
+ <polygon
+ points="13335,4447 13030,4345 13030,4548 13335,4447 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)"
+ style="font-size:423px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2467" />
+ <polygon
+ points="6985,8257 6680,8155 6680,8358 6985,8257 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-89.83858)"
+ style="font-size:423px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2485" />
+ <polygon
+ points="18415,6352 18110,6250 18110,6453 18415,6352 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-65.83858)"
+ style="font-size:423px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2493" />
+ <polyline
+ points="11748,7622 10796,7622 10796,6352 12701,6352 12701,7622 11748,7622"
+ id="polyline2505"
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-95.2987,-89.83858)"
+ style="font-size:423px;font-weight:400;fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:28.22222328;stroke-miterlimit:4;stroke-opacity:1;font-family:Nimbus Roman No9 L" />
+ <polygon
+ points="11430,5717 11328,6021 11531,6021 11430,5717 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-99.311,-97.83858)"
+ style="font-size:494px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2513" />
+ <polygon
+ points="15240,7622 15138,7926 15341,7926 15240,7622 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-87.38581,-85.07086)"
+ style="font-size:494px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2521" />
+ <polygon
+ points="15240,5717 15341,5412 15138,5412 15240,5717 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-87.38581,-92.76377)"
+ style="font-size:494px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2529" />
+ <polygon
+ points="20955,5080 20853,5384 21056,5384 20955,5080 "
+ transform="matrix(3.543307e-2,0,0,3.543307e-2,-101.2171,-61.83858)"
+ style="font-size:494px;font-weight:400;fill:#000000;stroke:none;stroke-width:28.22222328;stroke-miterlimit:4;font-family:Nimbus Roman No9 L"
+ id="polygon2537" />
+ <text
+ x="452.10867"
+ y="141.56526"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
+ id="text2151"
+ xml:space="preserve"><tspan
+ x="452.10867"
+ y="141.56526"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Arial"
+ id="tspan2153">PI</tspan><tspan
+ x="452.10867"
+ y="164.06526"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Arial"
+ id="tspan2155">controller</tspan></text>
+ <text
+ x="142.27893"
+ y="43"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text2157"
+ xml:space="preserve"><tspan
+ x="144.38831"
+ y="43"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2159">master-to-slave </tspan><tspan
+ x="142.27893"
+ y="58"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2161">delay</tspan></text>
+ <text
+ x="142.41797"
+ y="133.58594"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text2163"
+ xml:space="preserve"><tspan
+ x="142.41797"
+ y="133.58594"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2165">slave-to-master</tspan><tspan
+ x="142.41797"
+ y="148.58594"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2167">delay</tspan></text>
+ <text
+ x="142.60547"
+ y="193.11719"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text2169"
+ xml:space="preserve"><tspan
+ x="142.60547"
+ y="193.11719"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2173">interval</tspan></text>
+ <text
+ x="257.41992"
+ y="148.11719"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text2175"
+ xml:space="preserve"><tspan
+ x="257.41992"
+ y="148.11719"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2177">1/2</tspan></text>
+ <text
+ x="341.03125"
+ y="107"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text2179"
+ xml:space="preserve"><tspan
+ x="341.03125"
+ y="107"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2181">one-way</tspan><tspan
+ x="341.03125"
+ y="122"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2183">delay</tspan></text>
+ <text
+ x="295.59073"
+ y="164.17467"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
+ id="text2185"
+ xml:space="preserve"><tspan
+ x="295.59073"
+ y="164.17467"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Arial"
+ id="tspan2187">LP IIR</tspan></text>
+ <text
+ x="424.57254"
+ y="74.174667"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
+ id="text2189"
+ xml:space="preserve"><tspan
+ x="424.57254"
+ y="74.174667"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Arial"
+ id="tspan2191">LP FIR</tspan></text>
+ <text
+ x="369.19922"
+ y="43"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text2193"
+ xml:space="preserve"><tspan
+ x="369.19922"
+ y="43"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2197">offset from</tspan><tspan
+ x="369.19922"
+ y="58"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2199">master</tspan></text>
+ <text
+ x="547.66797"
+ y="133.11719"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text3653"
+ xml:space="preserve"><tspan
+ x="547.66797"
+ y="133.11719"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan3657">tick rate</tspan><tspan
+ x="547.66797"
+ y="148.11719"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan3659">adjustment</tspan></text>
+ <path
+ d="M 205 97.5 A 22.5 22.5 0 1 1 160,97.5 A 22.5 22.5 0 1 1 205 97.5 z"
+ transform="translate(33.18899,60.23228)"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path2206" />
+ <text
+ x="209.06204"
+ y="162.70938"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
+ id="text3665"
+ xml:space="preserve"><tspan
+ x="209.06204"
+ y="162.70938"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Arial"
+ id="tspan3667">∑</tspan></text>
+ <path
+ d="M 205 97.5 A 22.5 22.5 0 1 1 160,97.5 A 22.5 22.5 0 1 1 205 97.5 z"
+ transform="translate(123.189,-29.76772)"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path3660" />
+ <text
+ x="299.06204"
+ y="72.709381"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
+ id="text3669"
+ xml:space="preserve"><tspan
+ x="299.06204"
+ y="72.709381"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Arial"
+ id="tspan3671">∑</tspan></text>
+ <text
+ x="641.42212"
+ y="165.67467"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
+ id="text3673"
+ xml:space="preserve"><tspan
+ x="641.42212"
+ y="165.67467"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Arial"
+ id="tspan3677">Kernel</tspan><tspan
+ x="641.42212"
+ y="188.17467"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Arial"
+ id="tspan3679">FLL</tspan></text>
+ <text
+ x="616.56104"
+ y="76.675018"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
+ id="text3681"
+ xml:space="preserve"><tspan
+ x="616.56104"
+ y="76.675018"
+ id="tspan3683">Clock</tspan></text>
+ <text
+ x="24.329134"
+ y="141.5692"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
+ id="text3685"
+ xml:space="preserve"><tspan
+ x="24.329134"
+ y="141.5692"
+ id="tspan3687">PTPd</tspan></text>
+ <text
+ x="292.41992"
+ y="102.11719"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text8772"
+ xml:space="preserve"><tspan
+ x="292.41992"
+ y="102.11719"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Arial"
+ id="tspan8774">–</tspan></text>
+ </g>
+</svg>
diff --git a/third_party/ptpd-1.1.0/doc/data_paths.svg b/third_party/ptpd-1.1.0/doc/data_paths.svg new file mode 100644 index 0000000..7930acd --- /dev/null +++ b/third_party/ptpd-1.1.0/doc/data_paths.svg @@ -0,0 +1,424 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.0"
+ width="700"
+ height="250"
+ id="svg1767">
+ <defs
+ id="defs1769" />
+ <g
+ id="layer1">
+ <path
+ d="M 364.07449,162.44787 L 302.94811,162.44787 L 302.94811,93.94787"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path10927" />
+ <path
+ d="M 320.13707,113.44787 L 587.7613,113.44787"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1.03431964;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path7992" />
+ <path
+ d="M 38.29449,67.44787 L 587.25057,67.44787"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path2796" />
+ <path
+ d="M 55.18019,88.44787 L 586.7613,88.44787"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path2798" />
+ <rect
+ width="39.179855"
+ height="32.988602"
+ x="101.86665"
+ y="61.447876"
+ style="fill:#b9b9f7;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1308" />
+ <text
+ x="109.064"
+ y="82.304474"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text2038"
+ xml:space="preserve"><tspan
+ x="109.064"
+ y="82.304474"
+ id="tspan2040">PHY</tspan></text>
+ <rect
+ width="39.179855"
+ height="32.97155"
+ x="156.99518"
+ y="61.476318"
+ style="fill:#b9b9f7;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect14609" />
+ <text
+ x="162.88"
+ y="82.324402"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text2044"
+ xml:space="preserve"><tspan
+ x="162.88"
+ y="82.324402"
+ id="tspan2046">MAC</tspan></text>
+ <rect
+ width="39.179855"
+ height="59.320122"
+ x="287.90771"
+ y="61.127747"
+ style="fill:#f7bcbc;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2048" />
+ <rect
+ width="39.179855"
+ height="33.034515"
+ x="211.76129"
+ y="61.413361"
+ style="fill:#b9b9f7;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect14611" />
+ <text
+ x="230.57193"
+ y="74.702103"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text2050"
+ xml:space="preserve"><tspan
+ x="230.57193"
+ y="74.702103"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2052">HW</tspan><tspan
+ x="230.57193"
+ y="89.702103"
+ style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle"
+ id="tspan2054">Buff</tspan></text>
+ <text
+ x="67.761307"
+ y="80.447876"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text3526"
+ xml:space="preserve"><tspan
+ x="67.761307"
+ y="80.447876"
+ id="tspan3528">Tx</tspan></text>
+ <text
+ x="66.589432"
+ y="101.44787"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text3530"
+ xml:space="preserve"><tspan
+ x="66.589432"
+ y="101.44787"
+ id="tspan3532">Rx</tspan></text>
+ <text
+ x="295.9166"
+ y="94.089569"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text3552"
+ xml:space="preserve"><tspan
+ x="295.9166"
+ y="94.089569"
+ id="tspan3554">IRQ</tspan></text>
+ <rect
+ width="48.382557"
+ height="58.927467"
+ x="382.37872"
+ y="61.520401"
+ style="fill:#f7bcbc;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4287" />
+ <text
+ x="405.987"
+ y="87.852295"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4289"
+ xml:space="preserve"><tspan
+ x="405.987"
+ y="87.852295"
+ id="tspan4291">NIC</tspan><tspan
+ x="405.987"
+ y="102.85229"
+ id="tspan1506">Driver</tspan></text>
+ <rect
+ width="48.382557"
+ height="58.927467"
+ x="446.35071"
+ y="61.447876"
+ style="fill:#f7bcbc;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect14613" />
+ <text
+ x="450.17773"
+ y="94.80809"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4295"
+ xml:space="preserve"><tspan
+ x="450.17773"
+ y="94.80809"
+ id="tspan4297">UDP/IP</tspan></text>
+ <path
+ d="M 108.41884,49.44787 C 108.41884,46.16778 120.09007,49.28951 120.09007,43.73965 C 120.09007,49.28951 131.7613,46.16778 131.7613,49.44787"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path4315" />
+ <text
+ x="106.76129"
+ y="37.231079"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text5061"
+ xml:space="preserve"><tspan
+ x="106.76129"
+ y="37.231079"
+ id="tspan5063">jitter</tspan></text>
+ <text
+ x="250.83942"
+ y="22.172485"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text5067"
+ xml:space="preserve"><tspan
+ x="250.83942"
+ y="22.172485"
+ id="tspan5069">JITTER</tspan></text>
+ <path
+ d="M 223.91813,49.5406 C 223.91813,36.84555 269.08971,48.9277 269.08971,27.44787 C 269.08971,48.9277 314.2613,36.84555 314.2613,49.5406"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path5800" />
+ <rect
+ width="75.625313"
+ height="59.074764"
+ x="583.76129"
+ y="61.373108"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect7254" />
+ <text
+ x="606.81128"
+ y="80.167145"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text7256"
+ xml:space="preserve"><tspan
+ x="606.81128"
+ y="80.167145"
+ id="tspan7258">PTPd</tspan></text>
+ <text
+ x="334.76129"
+ y="127.23107"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text7994"
+ xml:space="preserve"><tspan
+ x="334.76129"
+ y="127.23107"
+ id="tspan7996">Time</tspan></text>
+ <path
+ d="M 394.8202,162.78483 L 607.7613,162.78483 L 607.7613,110.44787"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path10929" />
+ <rect
+ width="48.382557"
+ height="22.174822"
+ x="593.20868"
+ y="93.447868"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect7986" />
+ <text
+ x="599.93024"
+ y="108.89758"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text7988"
+ xml:space="preserve"><tspan
+ x="599.93024"
+ y="108.89758"
+ id="tspan7990">Servo</tspan></text>
+ <path
+ d="M 275 152.36218 A 25 25 0 1 1 225,152.36218 A 25 25 0 1 1 275 152.36218 z"
+ transform="translate(132.2613,10.0857)"
+ style="fill:#f7baba;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path10904" />
+ <path
+ d="M 270.7613,44.09362 L 270.7613,234.05213"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1"
+ id="path12383" />
+ <path
+ d="M 508.2613,44.09362 L 508.2613,234.05213"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1"
+ id="path13111" />
+ <g
+ transform="translate(7.4373,19.1115)"
+ style="stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g14569">
+ <path
+ d="M 27.5,8.362183 L 27.5,114.33703"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path2784" />
+ <path
+ d="M 31,10.387336 L 31,116.36218"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path2790" />
+ <path
+ d="M 23.17604,116.6083 C 23.17604,116.6083 25.000775,114.29264 27.066426,114.36218 C 29.132078,114.43173 29.374262,116.81621 31.438646,116.88649 C 33.50303,116.95677 35.32396,114.6433 35.32396,114.6433"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path13839" />
+ <path
+ d="M 23.17604,10.083993 C 23.17604,10.083993 25.000775,7.7683326 27.066426,7.8378726 C 29.132078,7.9074226 29.374262,10.291903 31.438646,10.362183 C 33.50303,10.432463 35.32396,8.1189926 35.32396,8.1189926"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path14567" />
+ </g>
+ <g
+ transform="translate(24.4373,19.0598)"
+ style="stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g14575">
+ <path
+ d="M 27.5,8.362183 L 27.5,114.33703"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path14577" />
+ <path
+ d="M 31,10.387336 L 31,116.36218"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path14579" />
+ <path
+ d="M 23.17604,116.6083 C 23.17604,116.6083 25.000775,114.29264 27.066426,114.36218 C 29.132078,114.43173 29.374262,116.81621 31.438646,116.88649 C 33.50303,116.95677 35.32396,114.6433 35.32396,114.6433"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path14581" />
+ <path
+ d="M 23.17604,10.083993 C 23.17604,10.083993 25.000775,7.7683326 27.066426,7.8378726 C 29.132078,7.9074226 29.374262,10.291903 31.438646,10.362183 C 33.50303,10.432463 35.32396,8.1189926 35.32396,8.1189926"
+ style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path14583" />
+ </g>
+ <text
+ x="167.29254"
+ y="216.16565"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text14585"
+ xml:space="preserve"><tspan
+ x="167.29254"
+ y="216.16565"
+ id="tspan14587">Hardware</tspan></text>
+ <text
+ x="344.58942"
+ y="215.04944"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text14589"
+ xml:space="preserve"><tspan
+ x="344.58942"
+ y="215.04944"
+ id="tspan14591">Kernel-Space</tspan></text>
+ <text
+ x="547.29254"
+ y="214.93225"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text14593"
+ xml:space="preserve"><tspan
+ x="547.29254"
+ y="214.93225"
+ id="tspan14595">User-Space</tspan></text>
+ <text
+ x="518.49567"
+ y="80.447876"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text14597"
+ xml:space="preserve"><tspan
+ x="518.49567"
+ y="80.447876"
+ id="tspan14601">send()</tspan></text>
+ <text
+ x="518.05621"
+ y="101.44787"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text14603"
+ xml:space="preserve"><tspan
+ x="518.05621"
+ y="101.44787"
+ id="tspan14605">recv()</tspan></text>
+ <text
+ x="518.11481"
+ y="126.56506"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text14615"
+ xml:space="preserve"><tspan
+ x="518.11481"
+ y="126.56506"
+ id="tspan14617">ioctl()</tspan></text>
+ <text
+ x="518.53082"
+ y="175.96936"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text16071"
+ xml:space="preserve"><tspan
+ x="518.53082"
+ y="175.96936"
+ id="tspan16073">adjtimex()</tspan></text>
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(-0.382906,0,0,0.258652,128.9564,16.5423)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path7553" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(0.382906,0,0,0.258652,50.5662,37.5672)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path8281" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(-0.382906,0,0,0.258652,410.0942,16.5672)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path8283" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(0.382906,0,0,0.258652,331.704,37.5921)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path8285" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(0.382906,0,0,0.258652,331.704,62.5672)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path8287" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(-0.382906,0,0,0.258652,610.8186,16.5672)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path8289" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(0.382906,0,0,0.258652,532.4284,37.5921)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path8291" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(0.382906,0,0,0.258652,532.4284,62.5672)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:3.1775763;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path8293" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(-0.382906,0,0,0.258652,633.8185,111.5423)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path9747" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(-0.382906,0,0,0.258652,461.8185,111.5672)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path9749" />
+ <path
+ d="M 112.44858,196.763 L 102.36214,202.58641 L 92.275712,208.40981 L 92.275712,196.763 L 92.275712,185.11619 L 102.36214,190.9396 L 112.44858,196.763 z "
+ transform="matrix(-0.382906,0,0,0.258652,377.8185,111.5423)"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path9751" />
+ <text
+ x="338.76129"
+ y="80.447876"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text9753"
+ xml:space="preserve"><tspan
+ x="338.76129"
+ y="80.447876"
+ id="tspan9755">Tx</tspan></text>
+ <text
+ x="337.58942"
+ y="101.44787"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text9757"
+ xml:space="preserve"><tspan
+ x="337.58942"
+ y="101.44787"
+ id="tspan9759">Rx</tspan></text>
+ <text
+ x="365.81403"
+ y="166.91565"
+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text1759"
+ xml:space="preserve"><tspan
+ x="365.81403"
+ y="166.91565"
+ id="tspan1761">Clock</tspan></text>
+ </g>
+</svg>
diff --git a/third_party/ptpd-1.1.0/doc/doc.html b/third_party/ptpd-1.1.0/doc/doc.html new file mode 100644 index 0000000..dd3bc33 --- /dev/null +++ b/third_party/ptpd-1.1.0/doc/doc.html @@ -0,0 +1,210 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
+<title>PTPd Source Documentation</title>
+</head>
+
+<body>
+
+<h1>PTPd Source Code Documentation</h1>
+
+<p>
+This is a brief overview of PTPd's source code intended to aid developers looking through PTPd.
+</p>
+
+<p> This documentation is incomplete, and it will be worked on as time permits.
+More information, particularly on PTPd's clock servo, is available in <a
+href="ptpd_2005_1588_conference_paper.pdf">this paper</a> written for the 2005
+Conference on IEEE 1588. </p>
+
+
+<h2>The IEEE 1588 Precision Time Protocol</h2>
+
+<p> The PTP daemon (PTPd) implements the Precision Time protocol (PTP) as
+defined by the IEEE 1588 standard. PTP was developed to provide very precise
+time coordination of LAN connected computers. The IEEE 1558 specification
+dictates most of PTPd's operation, so one should obtain a copy of the spec
+before going through PTPd's source code. PTPd keeps all of the names used in the
+spec, so it should be easy to match up PTPd's source code with the spec.
+Descriptions herein will assume knowledge of the spec. </p>
+
+<h2>Playing with PTPd</h2>
+
+<p> The best way to become familiar with a program is to use it. One should be
+able to run PTPd on standard Linux systems without much trouble. To better
+observe the operation of PTPd, compile it with the PTPD_DBG flag to have the
+program produce debugging output, and run PTPd with the '-c' argument to prevent
+it from backgrounding itself. </p>
+
+<p> PTPd coordinates the local clock by adjusting the effective tick rate, or
+<i>slewing</i>, the clock. This is a slow but precise process. To quickly
+coordinate a local clock that is off by more than one second, PTPd will reset
+the clock instead of slewing. This results in a step change in the time base,
+which can can cause problems for applications that require a smooth and
+monotonically increasing time base. The '-x' option will prevent PTPd from
+resetting the clock, while still allowing it to adjust the clock frequency.
+(This is different from the '-t' option that entirely prevents PTPd from
+adjusting the clock.)</p>
+
+<p> For PTPd to operate, it must be run on at least two computers connected
+through an Ethernet hub or switch. It is possible to have PTPd coordinate two
+(and only two) computers through a routed connection by running PTPd on each
+computer with the '-u' argument followed by the IP address of the other
+computer. </p>
+
+<p> PTPd can send management messages to query PTP nodes on a LAN or a PTPd
+server on the same machine. To send a management message, run PTPd with the '-k
+NUMBER' option, where the number is the management message key to send, or zero
+to send a sweep of different management messages. To query only a local PTPd
+server, bind the program to the loopback device with '-b lo'. </p>
+
+<p> PTPd should be able to coordinate the clocks of your computers within tens
+of microseconds. The default distribution achieved coordination below ten
+microseconds running on fairly busy embedded systems with 66MHz m68k processors.
+For the best performance, you will need to tweak the servo gains with the '-a'
+command line argument. Also, you must compensate for asymmetric inbound versus
+outbound message latency with the '-l' argument. This will remove any constant
+offset in the time coordination. As a rule of thumb, you can eliminate a time
+offset T by specifying an inbound and outbound latency that have a difference of
+2*T. </p>
+
+<p> PTPd's precision is dependent upon the precision of message send and receive
+time stamps. PTPd previously required a kernel patch to improve its precision,
+but now it needs only a Berkeley sockets interface that has the
+<tt>SO_TIMESTAMP</tt> socket option. PTPd uses a few platform specific APIs to
+query network interfaces, but otherwise it should be very portable to any Posix
+platform that implements David Mills' <tt>ntp_adjtime</tt>/<tt>adtimex</tt>
+system call. PTPd runs on Linux, uClinux, NetBSD, and FreeBSD. </p>
+
+<p> While it is fairly easy to get PTPd to provide a precisely coordinated time
+base, it is much more difficult to use the coordinated time base. This is
+because platforms like Linux do not provide interfaces to generate precisely
+timed events. Projects like RTAI are working on 'real-time' turnaround in Linux.
+</p>
+
+<h2>PTPd's Source Code Organization</h2>
+
+<p> PTPd's source is grouped into a few components. The component delineations
+are based on the functionality defined by the spec, but the delineations are not
+specifically defined by the spec. </p>
+
+<p> The following is a block diagram of PTPd's major components, in which
+occlusion indicates interfaces between components. </p>
+
+<p><object type="image/svg+xml" data="organization.svg" width="600" height="300">
+<a href="organization.svg">[organization block diagram]</a></object></p>
+
+<p> In general, PTPd's source is divided into platform-independent and
+platform-dependent code. Platform-independent code is located in the top level
+of the PTPd source tree, and platform-dependent code is located the
+<tt>dep/</tt> sub-directory. </p>
+
+<p> PTPd's major source code components are: </p>
+
+<dl><dt><b>Protocol Engine</b>, <tt>protocol.c</tt></dt>
+
+<dd> The main protocol state machine defined in the spec. The state machine is
+implemented as a forever loop with cases for each state. It is called with
+<tt>protocol()</tt> after start-up, and only returns on an error. Normal
+execution is expected to be halted externally and asynchronously. The loop
+sleeps in a select() call on the network sockets. The primary states, handled by
+<tt>doState()</tt>, are master, slave, inactive, and faulty. State transitions,
+handled by <tt>toState()</tt>, occur primarily due to the results of the BMC
+algorithm. The primary events are message receives, which are checked for in
+<tt>handle()</tt>, and timer expiration. The primary actions are message sends,
+which are done in <tt>issue()</tt>, timer resets, regular runs of the BMC
+algorithm, foreign master data updates, and system clock servo updates after
+sync message receipts. </dd>
+
+<dt><b>BMC</b>, <tt>bmc.c</tt></dt>
+
+<dd> The Best Master Clock algorithm defined by the spec. It is called with
+<tt>bmc()</tt>, and it returns the proper state, master or slave, based on the
+reported clock statistics of other PTP clocks that have sent Sync messages
+(foreign masters). </dd>
+
+<dt><b>Clock Servo</b>, <tt>dep/servo.c</tt></dt>
+
+<dd> The clock servo computes the offset-from-master from the master-to-slave
+delay and slave-to-master delays. It uses the offset-from-master to compute
+clock tick rate adjustments to minimize the offset-from-master. The clock servo
+also performs filtering to remove jitter from its input. </dd>
+
+<dt><b>Message Packer</b>, <tt>dep/msg.c</tt></dt>
+
+<dd> Gathers data into and extracts data from PTP messages, the format of which
+is defined by the spec. </dd>
+
+<dt><b>Network Layer</b>, <tt>dep/net.c</tt></dt>
+
+<dd> Initializes connections, sends, and receives data between PTP clocks.
+The network layer also retrieves time stamps for Event messages from the Time
+Stamp component. </dd>
+
+<dt><b>Time Stamp</b></dt>
+
+<dd> Records message send and receive times. The send and receive times are used
+to compute the master-to-slave and slave-to-master delay. The delays are then
+used to coordinate slave clocks with master clock time. Time stamps should be
+recorded as close to the networking hardware as possible. This minimizes jitter
+in the time stamps, which is the most significant detriment to PTPd's clock
+coordination. </dd>
+
+<dt><b>Timer</b>, <tt>dep/timer.c</tt></dt>
+
+<dd> Low resolution interval timers used in the protocol engine. The timers
+control periodic Sync message sends by masters, Delay Request sends by slaves, periodic
+runs of the BMC (state change events), and Sync receive timeouts. </dd>
+
+<dt><b>Start-up</b>, <tt>dep/startup.c</tt></dt>
+
+<dd> Sets the program's execution state, and retrieves run-time options from the
+user. </dd>
+
+<dt><b>Other code</b></dt>
+
+<dd> The <tt>ptpd.c</tt> file contains the execution entry point. The
+<tt>ptpd</tt> header files contain function prototype declarations. The
+<tt>datatypes</tt> header files contain structure and data type declarations.
+Finally, the <tt>constants</tt> header files contain constant declarations.
+</dd></dl>
+
+<h2>PTPd's Clock Servo</h2>
+
+<p> The IEEE 1588 spec does not define how the offset from master produced by a
+PTP slave is used to bring the slave clock into coordination with master clock
+time. This procedure, called clock discipline, is not trivial, and there are
+many possible design approaches and trade-offs. For these reasons, this
+documentation devotes a section exclusively to the clock servo component. </p>
+
+<p> The following shows the message send and receive paths in a typical system
+running PTPd, along with the associated time stamps that form the basis of the
+master-to-slave and slave-to-master delay measurements. </p>
+
+<p>
+<object type="image/svg+xml" data="data_paths.svg" width="700" height="250">
+<a href="data_paths.svg">[data path diagram]</a></object>
+</p>
+
+<p> The following is a system diagram of PTPd's clock servo. The FIR filtering
+of the offset from master input is a simple, two-sample average. The IIR
+filtering of the input one-way delay is described below. The PI controller that
+mediates the tick rate adjustment output has the difference equation: <tt>y[n] =
+e[n]/Ap + a[n]</tt>, <tt>a[n] = e[n]/Ai + a[n-1]</tt>. </p>
+
+<p><object type="image/svg+xml" data="clock_servo.svg" width="700" height="250">
+<a href="clock_servo.svg">[clock servo system diagram]</a></object></p>
+
+<p> The following are plots of the frequency response of the one-way delay
+filter. It is a variable cutoff/delay low-pass, infinite impulse response (IIR)
+filter. The one-way delay filter has the difference equation: <tt>s*y[n] -
+(s-1)*y[n-1] = x[n]/2 + x[n-1]/2</tt>, where increasing the stiffness
+(<tt>s</tt>) lowers the cutoff and increases the delay. </p>
+
+<p><object type="image/svg+xml" data="filter.svg" width="640" height="512">
+<a href="filter.svg">[offset filter plot]</a></object></p>
+
+</body>
+</html>
+
diff --git a/third_party/ptpd-1.1.0/doc/filter.svg b/third_party/ptpd-1.1.0/doc/filter.svg new file mode 100644 index 0000000..0bdd38a --- /dev/null +++ b/third_party/ptpd-1.1.0/doc/filter.svg @@ -0,0 +1,483 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.0"
+ width="480pt"
+ height="384pt"
+ id="svg7055">
+ <defs
+ id="defs7057" />
+ <g
+ id="layer1">
+ <path
+ d="M 74.5,426 L 574.5,426 L 574.5,256 L 74.5,256 L 74.5,426"
+ style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:currentColor;stroke-width:1"
+ id="path18117" />
+ <path
+ d="M 74.5,426 L 574.5,426 L 574.5,256 L 74.5,256 L 74.5,426"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18033" />
+ <path
+ d="M 74.5,418 L 83.5,418 M 574.5,418 L 565.5,418"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18039" />
+ <g
+ transform="translate(66.5,422)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18041">
+ <text
+ id="text18043">-3</text>
+ </g>
+ <path
+ d="M 74.5,391 L 83.5,391 M 574.5,391 L 565.5,391"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18045" />
+ <g
+ transform="translate(66.5,395)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18047">
+ <text
+ id="text18049">-2.5</text>
+ </g>
+ <path
+ d="M 74.5,364 L 83.5,364 M 574.5,364 L 565.5,364"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18051" />
+ <g
+ transform="translate(66.5,368)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18053">
+ <text
+ id="text18055">-2</text>
+ </g>
+ <path
+ d="M 74.5,337 L 83.5,337 M 574.5,337 L 565.5,337"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18057" />
+ <g
+ transform="translate(66.5,341)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18059">
+ <text
+ id="text18061">-1.5</text>
+ </g>
+ <path
+ d="M 74.5,310 L 83.5,310 M 574.5,310 L 565.5,310"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18063" />
+ <g
+ transform="translate(66.5,314)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18065">
+ <text
+ id="text18067">-1</text>
+ </g>
+ <path
+ d="M 74.5,283 L 83.5,283 M 574.5,283 L 565.5,283"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18069" />
+ <g
+ transform="translate(66.5,287)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18071">
+ <text
+ id="text18073">-0.5</text>
+ </g>
+ <path
+ d="M 74.5,256 L 83.5,256 M 574.5,256 L 565.5,256"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18075" />
+ <g
+ transform="translate(66.5,260)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18077">
+ <text
+ id="text18079">0</text>
+ </g>
+ <path
+ d="M 74.5,426 L 74.5,417 M 74.5,256 L 74.5,265"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18081" />
+ <g
+ transform="translate(74.5,448)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18083">
+ <text
+ id="text18085">1e-05</text>
+ </g>
+ <path
+ d="M 104.5,426 L 104.5,422 M 104.5,256 L 104.5,260 M 144.5,426 L 144.5,422 M 144.5,256 L 144.5,260 M 164.5,426 L 164.5,422 M 164.5,256 L 164.5,260 M 174.5,426 L 174.5,417 M 174.5,256 L 174.5,265"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18087" />
+ <g
+ transform="translate(174.5,448)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18089">
+ <text
+ id="text18091">1e-04</text>
+ </g>
+ <path
+ d="M 204.5,426 L 204.5,422 M 204.5,256 L 204.5,260 M 244.5,426 L 244.5,422 M 244.5,256 L 244.5,260 M 264.5,426 L 264.5,422 M 264.5,256 L 264.5,260 M 274.5,426 L 274.5,417 M 274.5,256 L 274.5,265"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18093" />
+ <g
+ transform="translate(274.5,448)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18095">
+ <text
+ id="text18097">0.001</text>
+ </g>
+ <path
+ d="M 304.5,426 L 304.5,422 M 304.5,256 L 304.5,260 M 344.5,426 L 344.5,422 M 344.5,256 L 344.5,260 M 364.5,426 L 364.5,422 M 364.5,256 L 364.5,260 M 374.5,426 L 374.5,417 M 374.5,256 L 374.5,265"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18099" />
+ <g
+ transform="translate(374.5,448)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18101">
+ <text
+ id="text18103">0.01</text>
+ </g>
+ <path
+ d="M 404.5,426 L 404.5,422 M 404.5,256 L 404.5,260 M 444.5,426 L 444.5,422 M 444.5,256 L 444.5,260 M 464.5,426 L 464.5,422 M 464.5,256 L 464.5,260 M 474.5,426 L 474.5,417 M 474.5,256 L 474.5,265"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18105" />
+ <g
+ transform="translate(474.5,448)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18107">
+ <text
+ id="text18109">0.1</text>
+ </g>
+ <path
+ d="M 504.5,426 L 504.5,422 M 504.5,256 L 504.5,260 M 544.5,426 L 544.5,422 M 544.5,256 L 544.5,260 M 564.5,426 L 564.5,422 M 564.5,256 L 564.5,260 M 574.5,426 L 574.5,417 M 574.5,256 L 574.5,265"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path18111" />
+ <g
+ transform="translate(574.5,448)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18113">
+ <text
+ id="text18115">1</text>
+ </g>
+ <g
+ transform="matrix(0,-1,1,0,21.5,341)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18119">
+ <text
+ id="text18121">phase (rad)</text>
+ </g>
+ <g
+ transform="translate(324.5,475)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g18123">
+ <text
+ id="text18125">frequency</text>
+ </g>
+ <path
+ d="M 74.5,186 L 574.5,186 L 574.5,16 L 74.5,16 L 74.5,186"
+ style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:currentColor;stroke-width:1"
+ id="path5364" />
+ <path
+ d="M 74.5,158 L 83.5,158 M 574.5,158 L 565.5,158"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5238" />
+ <g
+ transform="translate(66.5,162)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5240">
+ <text
+ id="text5242">-200</text>
+ </g>
+ <path
+ d="M 74.5,122 L 83.5,122 M 574.5,122 L 565.5,122"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5244" />
+ <g
+ transform="translate(66.5,126)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5246">
+ <text
+ id="text5248">-150</text>
+ </g>
+ <path
+ d="M 74.5,87 L 83.5,87 M 574.5,87 L 565.5,87"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5250" />
+ <g
+ transform="translate(66.5,91)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5252">
+ <text
+ id="text5254">-100</text>
+ </g>
+ <path
+ d="M 74.5,51 L 83.5,51 M 574.5,51 L 565.5,51"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5256" />
+ <g
+ transform="translate(66.5,55)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5258">
+ <text
+ id="text5260">-50</text>
+ </g>
+ <path
+ d="M 74.5,16 L 83.5,16 M 574.5,16 L 565.5,16"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5262" />
+ <g
+ transform="translate(66.5,20)"
+ style="font-size:12px;text-anchor:end;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5264">
+ <text
+ id="text5266">0</text>
+ </g>
+ <path
+ d="M 74.5,186 L 74.5,177 M 74.5,16 L 74.5,25"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5268" />
+ <g
+ transform="translate(74.5,208)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5270">
+ <text
+ id="text5272">1e-05</text>
+ </g>
+ <path
+ d="M 104.5,186 L 104.5,182 M 104.5,16 L 104.5,20 M 144.5,186 L 144.5,182 M 144.5,16 L 144.5,20 M 164.5,186 L 164.5,182 M 164.5,16 L 164.5,20 M 174.5,186 L 174.5,177 M 174.5,16 L 174.5,25"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5274" />
+ <g
+ transform="translate(174.5,208)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5276">
+ <text
+ id="text5278">1e-04</text>
+ </g>
+ <path
+ d="M 204.5,186 L 204.5,182 M 204.5,16 L 204.5,20 M 244.5,186 L 244.5,182 M 244.5,16 L 244.5,20 M 264.5,186 L 264.5,182 M 264.5,16 L 264.5,20 M 274.5,186 L 274.5,177 M 274.5,16 L 274.5,25"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5280" />
+ <g
+ transform="translate(274.5,208)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5282">
+ <text
+ id="text5284">0.001</text>
+ </g>
+ <path
+ d="M 304.5,186 L 304.5,182 M 304.5,16 L 304.5,20 M 344.5,186 L 344.5,182 M 344.5,16 L 344.5,20 M 364.5,186 L 364.5,182 M 364.5,16 L 364.5,20 M 374.5,186 L 374.5,177 M 374.5,16 L 374.5,25"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5286" />
+ <g
+ transform="translate(374.5,208)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5288">
+ <text
+ id="text5290">0.01</text>
+ </g>
+ <path
+ d="M 404.5,186 L 404.5,182 M 404.5,16 L 404.5,20 M 444.5,186 L 444.5,182 M 444.5,16 L 444.5,20 M 464.5,186 L 464.5,182 M 464.5,16 L 464.5,20 M 474.5,186 L 474.5,177 M 474.5,16 L 474.5,25"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5292" />
+ <g
+ transform="translate(474.5,208)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5294">
+ <text
+ id="text5296">0.1</text>
+ </g>
+ <path
+ d="M 504.5,186 L 504.5,182 M 504.5,16 L 504.5,20 M 544.5,186 L 544.5,182 M 544.5,16 L 544.5,20 M 564.5,186 L 564.5,182 M 564.5,16 L 564.5,20 M 574.5,186 L 574.5,177 M 574.5,16 L 574.5,25"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5298" />
+ <g
+ transform="translate(574.5,208)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5300">
+ <text
+ id="text5302">1</text>
+ </g>
+ <path
+ d="M 74.5,186 L 574.5,186 L 574.5,16 L 74.5,16 L 74.5,186"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="path5304" />
+ <g
+ transform="matrix(0,-1,1,0,21.5,101)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5306">
+ <text
+ id="text5308">gain (dB)</text>
+ </g>
+ <g
+ transform="translate(324.5,235)"
+ style="font-size:12px;text-anchor:middle;color:#000000;fill:#000000;stroke:none;stroke-width:1;font-family:Arial"
+ id="g5310">
+ <text
+ id="text5312">frequency</text>
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g5316">
+ <g
+ transform="translate(147,118)"
+ style="font-size:12px;text-anchor:end;fill:#000000;stroke:none;font-family:Arial"
+ id="g5318">
+ <text
+ id="text5320">s = 2^0</text>
+ </g>
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#ff0000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g5322">
+ <path
+ d="M 155,114 L 196,114 M 75,16 L 105,16 L 123,16 L 135,16 L 145,16 L 153,16 L 160,16 L 165,16 L 170,16 L 175,16 L 179,16 L 183,16 L 186,16 L 190,16 L 193,16 L 195,16 L 198,16 L 201,16 L 203,16 L 205,16 L 207,16 L 209,16 L 211,16 L 213,16 L 215,16 L 216,16 L 218,16 L 220,16 L 221,16 L 223,16 L 224,16 L 226,16 L 227,16 L 228,16 L 229,16 L 231,16 L 232,16 L 233,16 L 234,16 L 235,16 L 236,16 L 237,16 L 238,16 L 239,16 L 240,16 L 241,16 L 242,16 L 243,16 L 244,16 L 245,16 L 246,16 L 247,16 L 248,16 L 249,16 L 250,16 L 251,16 L 252,16 L 253,16 L 254,16 L 255,16 L 256,16 L 257,16 L 258,16 L 259,16 L 260,16 L 261,16 L 262,16 L 263,16 L 264,16 L 265,16 L 266,16 L 267,16 L 268,16 L 269,16 L 270,16 L 271,16 L 272,16 L 273,16 L 274,16 L 275,16 L 276,16 L 277,16 L 278,16 L 279,16 L 280,16 L 281,16 L 282,16 L 283,16 L 284,16 L 285,16 L 286,16 L 287,16 L 288,16 L 289,16 L 290,16 L 291,16 L 292,16 L 293,16 L 294,16 L 295,16 L 296,16 L 297,16 L 298,16 L 299,16 L 300,16 L 301,16 L 302,16 L 303,16 L 304,16 L 305,16 L 306,16 L 307,16 L 308,16 L 309,16 L 310,16 L 311,16 L 312,16 L 313,16 L 314,16 L 315,16 L 316,16 L 317,16 L 318,16 L 319,16 L 320,16 L 321,16 L 322,16 L 323,16 L 324,16 L 325,16 L 326,16 L 327,16 L 328,16 L 329,16 L 330,16 L 331,16 L 332,16 L 333,16 L 334,16 L 335,16 L 336,16 L 337,16 L 338,16 L 339,16 L 340,16 L 341,16 L 342,16 L 343,16 L 344,16 L 345,16 L 346,16 L 347,16 L 348,16 L 349,16 L 350,16 L 351,16 L 352,16 L 353,16 L 354,16 L 355,16 L 356,16 L 357,16 L 358,16 L 359,16 L 360,16 L 361,16 L 362,16 L 363,16 L 364,16 L 365,16 L 366,16 L 367,16 L 368,16 L 369,16 L 370,16 L 371,16 L 372,16 L 373,16 L 374,16 L 375,16 L 376,16 L 377,16 L 378,16 L 379,16 L 380,16 L 381,16 L 382,16 L 383,16 L 384,16 L 385,16 L 386,16 L 387,16 L 388,16 L 389,16 L 390,16 L 391,16 L 392,16 L 393,16 L 394,16 L 395,16 L 396,16 L 397,16 L 398,16 L 399,16 L 400,16 L 401,16 L 402,16 L 403,16 L 404,16 L 405,16 L 406,16 L 407,16 L 408,16 L 409,16 L 410,16 L 411,16 L 412,16 L 413,16 L 414,16 L 415,16 L 416,16 L 417,16 L 418,16 L 419,16 L 420,16 L 421,16 L 422,16 L 423,16 L 424,16 L 425,16 L 426,16 L 427,16 L 428,16 L 429,16 L 430,16 L 431,16 L 432,16 L 433,16 L 434,16 L 435,16 L 436,16 L 437,16 L 438,16 L 439,16 L 440,16 L 441,16 L 442,16 L 443,16 L 444,16 L 445,16 L 446,16 L 447,16 L 448,16 L 449,16 L 450,16 L 451,16 L 452,16 L 453,16 L 454,16 L 455,16 L 456,16 L 457,16 L 458,16 L 459,16 L 460,16 L 461,16 L 462,16 L 463,16 L 464,16 L 465,16 L 466,16 L 467,16 L 468,16 L 469,16 L 470,16 L 471,16 L 472,16 L 473,16 L 474,16 L 475,16 L 476,16 L 477,16 L 478,16 L 479,16 L 480,16 L 481,16 L 482,16 L 483,16 L 484,16 L 485,16 L 486,16 L 487,16 L 488,16 L 489,16 L 490,16 L 491,16 L 492,16 L 493,16 L 494,16 L 495,16 L 496,16 L 497,16 L 498,16 L 498,17 L 499,17 L 500,17 L 501,17 L 502,17 L 503,17 L 504,17 L 505,17 L 506,17 L 507,17 L 508,17 L 509,17 L 510,17 L 511,17 L 512,17 L 513,17 L 514,17 L 515,17 L 516,17 L 517,17 L 518,17 L 519,17 L 520,17 L 521,17 L 521,18 L 522,18 L 523,18 L 524,18 L 525,18 L 526,18 L 527,18 L 528,18 L 529,18 L 530,18 L 531,18 L 531,19 L 532,19 L 533,19 L 534,19 L 535,19 L 536,19 L 537,19 L 538,19 L 538,20 L 539,20 L 540,20 L 541,20 L 542,20 L 543,20 L 543,21 L 544,21 L 545,21 L 546,21 L 547,21 L 547,22 L 548,22 L 549,22 L 550,22 L 550,23 L 551,23 L 552,23 L 553,23 L 553,24 L 554,24 L 555,24 L 555,25 L 556,25 L 557,25 L 557,26 L 558,26 L 558,27 L 559,27 L 560,27 L 560,28 L 561,28 L 561,29 L 562,29 L 562,30 L 563,30 L 563,31 L 564,31 L 564,32 L 565,32 L 565,33 L 566,33 L 566,34 L 567,34 L 567,35 L 567,36 L 568,36 L 568,37 L 568,38 L 569,38 L 569,39 L 569,40 L 570,40 L 570,41 L 570,42 L 570,43 L 571,43 L 571,44 L 571,45 L 571,46 L 572,46 L 572,47 L 572,48 L 572,49 L 572,50 L 573,50 L 573,51 L 573,52 L 573,53 L 573,54 L 573,55 L 573,56 L 573,57 L 573,58 L 574,58 L 574,59 L 574,60 L 574,61 L 574,62 L 574,63 L 574,64 L 574,65 L 574,66 L 574,67 L 574,68 L 574,69 L 574,70 L 574,71 L 574,72 L 574,73 L 575,73 L 575,74 L 575,75 L 575,76 L 575,77 L 575,78 L 575,79 L 575,80 L 575,81 L 575,82 L 575,83 L 575,84 L 575,85 L 575,86 L 575,87 L 575,88 L 575,89 L 575,90 L 575,91 L 575,92 L 575,93 L 575,94 L 575,95 L 575,96 L 575,97 L 575,98 L 575,99 L 575,100 L 575,101 L 575,102 L 575,103 L 575,104 L 575,105 L 575,106 L 575,107 L 575,108 L 575,109 L 575,110 L 575,111 L 575,112 L 575,113 L 575,114 L 575,115 L 575,116 L 575,117 L 575,118 L 575,119 L 575,120 L 575,121 L 575,122 L 575,123 L 575,124 L 575,125 L 575,126 L 575,127 L 575,128 L 575,129 L 575,130 L 575,131 L 575,132 L 575,133 L 575,134 L 575,135 L 575,136 L 575,137 L 575,139 L 575,140 L 575,142 L 575,143 L 575,145 L 575,147 L 575,150 L 575,153 L 575,157 L 575,163 L 575,173"
+ id="path5324" />
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g5328">
+ <g
+ transform="translate(147,136)"
+ style="font-size:12px;text-anchor:end;fill:#000000;stroke:none;font-family:Arial"
+ id="g5330">
+ <text
+ id="text5332">s = 2^4</text>
+ </g>
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#008000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g5334">
+ <path
+ d="M 155,132 L 196,132 M 75,16 L 105,16 L 123,16 L 135,16 L 145,16 L 153,16 L 160,16 L 165,16 L 170,16 L 175,16 L 179,16 L 183,16 L 186,16 L 190,16 L 193,16 L 195,16 L 198,16 L 201,16 L 203,16 L 205,16 L 207,16 L 209,16 L 211,16 L 213,16 L 215,16 L 216,16 L 218,16 L 220,16 L 221,16 L 223,16 L 224,16 L 226,16 L 227,16 L 228,16 L 229,16 L 231,16 L 232,16 L 233,16 L 234,16 L 235,16 L 236,16 L 237,16 L 238,16 L 239,16 L 240,16 L 241,16 L 242,16 L 243,16 L 244,16 L 245,16 L 246,16 L 247,16 L 248,16 L 249,16 L 250,16 L 251,16 L 252,16 L 253,16 L 254,16 L 255,16 L 256,16 L 257,16 L 258,16 L 259,16 L 260,16 L 261,16 L 262,16 L 263,16 L 264,16 L 265,16 L 266,16 L 267,16 L 268,16 L 269,16 L 270,16 L 271,16 L 272,16 L 273,16 L 274,16 L 275,16 L 276,16 L 277,16 L 278,16 L 279,16 L 280,16 L 281,16 L 282,16 L 283,16 L 284,16 L 285,16 L 286,16 L 287,16 L 288,16 L 289,16 L 290,16 L 291,16 L 292,16 L 293,16 L 294,16 L 295,16 L 296,16 L 297,16 L 298,16 L 299,16 L 300,16 L 301,16 L 302,16 L 303,16 L 304,16 L 305,16 L 306,16 L 307,16 L 308,16 L 309,16 L 310,16 L 311,16 L 312,16 L 313,16 L 314,16 L 315,16 L 316,16 L 317,16 L 318,16 L 319,16 L 320,16 L 321,16 L 322,16 L 323,16 L 324,16 L 325,16 L 326,16 L 327,16 L 328,16 L 329,16 L 330,16 L 331,16 L 332,16 L 333,16 L 334,16 L 335,16 L 336,16 L 337,16 L 338,16 L 339,16 L 340,16 L 341,16 L 342,16 L 343,16 L 344,16 L 345,16 L 346,16 L 347,16 L 348,16 L 349,16 L 350,17 L 351,17 L 352,17 L 353,17 L 354,17 L 355,17 L 356,17 L 357,17 L 358,17 L 359,17 L 360,17 L 361,17 L 362,17 L 363,17 L 364,17 L 365,17 L 366,17 L 367,17 L 368,17 L 369,17 L 370,17 L 371,17 L 372,17 L 373,17 L 374,17 L 375,17 L 375,18 L 376,18 L 377,18 L 378,18 L 379,18 L 380,18 L 381,18 L 382,18 L 383,18 L 384,18 L 385,18 L 386,18 L 387,18 L 388,18 L 388,19 L 389,19 L 390,19 L 391,19 L 392,19 L 393,19 L 394,19 L 395,19 L 396,19 L 397,19 L 397,20 L 398,20 L 399,20 L 400,20 L 401,20 L 402,20 L 403,20 L 404,20 L 404,21 L 405,21 L 406,21 L 407,21 L 408,21 L 409,21 L 410,21 L 410,22 L 411,22 L 412,22 L 413,22 L 414,22 L 415,22 L 415,23 L 416,23 L 417,23 L 418,23 L 419,23 L 420,23 L 420,24 L 421,24 L 422,24 L 423,24 L 424,24 L 424,25 L 425,25 L 426,25 L 427,25 L 428,25 L 429,25 L 429,26 L 430,26 L 431,26 L 432,26 L 433,26 L 433,27 L 434,27 L 435,27 L 436,27 L 437,27 L 437,28 L 438,28 L 439,28 L 440,28 L 440,29 L 441,29 L 442,29 L 443,29 L 444,29 L 444,30 L 445,30 L 446,30 L 447,30 L 448,30 L 448,31 L 449,31 L 450,31 L 451,31 L 451,32 L 452,32 L 453,32 L 454,32 L 454,33 L 455,33 L 456,33 L 457,33 L 458,33 L 458,34 L 459,34 L 460,34 L 461,34 L 461,35 L 462,35 L 463,35 L 464,35 L 464,36 L 465,36 L 466,36 L 467,36 L 468,36 L 468,37 L 469,37 L 470,37 L 471,37 L 471,38 L 472,38 L 473,38 L 474,38 L 474,39 L 475,39 L 476,39 L 477,39 L 477,40 L 478,40 L 479,40 L 480,40 L 480,41 L 481,41 L 482,41 L 483,41 L 483,42 L 484,42 L 485,42 L 486,42 L 486,43 L 487,43 L 488,43 L 489,43 L 489,44 L 490,44 L 491,44 L 492,44 L 492,45 L 493,45 L 494,45 L 495,45 L 495,46 L 496,46 L 497,46 L 498,46 L 498,47 L 499,47 L 500,47 L 501,47 L 501,48 L 502,48 L 503,48 L 504,48 L 504,49 L 505,49 L 506,49 L 507,49 L 507,50 L 508,50 L 509,50 L 510,50 L 510,51 L 511,51 L 512,51 L 513,51 L 513,52 L 514,52 L 515,52 L 516,52 L 516,53 L 517,53 L 518,53 L 518,54 L 519,54 L 520,54 L 521,54 L 521,55 L 522,55 L 523,55 L 524,55 L 524,56 L 525,56 L 526,56 L 526,57 L 527,57 L 528,57 L 529,57 L 529,58 L 530,58 L 531,58 L 531,59 L 532,59 L 533,59 L 534,59 L 534,60 L 535,60 L 536,60 L 536,61 L 537,61 L 538,61 L 538,62 L 539,62 L 540,62 L 540,63 L 541,63 L 542,63 L 543,63 L 543,64 L 544,64 L 545,64 L 545,65 L 546,65 L 547,65 L 547,66 L 548,66 L 548,67 L 549,67 L 550,67 L 550,68 L 551,68 L 552,68 L 552,69 L 553,69 L 553,70 L 554,70 L 555,70 L 555,71 L 556,71 L 556,72 L 557,72 L 557,73 L 558,73 L 559,73 L 559,74 L 560,74 L 560,75 L 561,75 L 561,76 L 562,76 L 562,77 L 563,77 L 563,78 L 564,78 L 564,79 L 565,79 L 565,80 L 565,81 L 566,81 L 566,82 L 567,82 L 567,83 L 567,84 L 568,84 L 568,85 L 568,86 L 569,86 L 569,87 L 569,88 L 570,88 L 570,89 L 570,90 L 570,91 L 571,91 L 571,92 L 571,93 L 571,94 L 572,94 L 572,95 L 572,96 L 572,97 L 572,98 L 572,99 L 573,99 L 573,100 L 573,101 L 573,102 L 573,103 L 573,104 L 573,105 L 573,106 L 574,106 L 574,107 L 574,108 L 574,109 L 574,110 L 574,111 L 574,112 L 574,113 L 574,114 L 574,115 L 574,116 L 574,117 L 574,118 L 574,119 L 574,120 L 574,121 L 574,122 L 575,122 L 575,123 L 575,124 L 575,125 L 575,126 L 575,127 L 575,128 L 575,129 L 575,130 L 575,131 L 575,132 L 575,133 L 575,134 L 575,135 L 575,136 L 575,137 L 575,138 L 575,139 L 575,140 L 575,141 L 575,142 L 575,143 L 575,144 L 575,145 L 575,146 L 575,147 L 575,148 L 575,149 L 575,150 L 575,151 L 575,152 L 575,153 L 575,154 L 575,155 L 575,156 L 575,157 L 575,158 L 575,159 L 575,160 L 575,161 L 575,162 L 575,163 L 575,164 L 575,165 L 575,166 L 575,167 L 575,168 L 575,169 L 575,170 L 575,171 L 575,172 L 575,173 L 575,174 L 575,175 L 575,176 L 575,177 L 575,178 L 575,179 L 575,180 L 575,181 L 575,182 L 575,183 L 575,184 L 575,185 L 575,186"
+ id="path5336" />
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g5340">
+ <g
+ transform="translate(147,154)"
+ style="font-size:12px;text-anchor:end;fill:#000000;stroke:none;font-family:Arial"
+ id="g5342">
+ <text
+ id="text5344">s = 2^8</text>
+ </g>
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#0000ff;fill:none;stroke:currentColor;stroke-width:1"
+ id="g5346">
+ <path
+ d="M 155,150 L 196,150 M 75,16 L 105,16 L 123,16 L 135,16 L 145,16 L 153,16 L 160,16 L 165,16 L 170,16 L 175,16 L 179,16 L 183,16 L 186,16 L 190,16 L 193,16 L 195,16 L 198,16 L 201,16 L 203,16 L 205,16 L 207,16 L 209,16 L 211,16 L 213,16 L 215,16 L 216,16 L 218,16 L 220,16 L 221,16 L 223,16 L 224,16 L 226,16 L 227,16 L 228,17 L 229,17 L 231,17 L 232,17 L 233,17 L 234,17 L 235,17 L 236,17 L 237,17 L 238,17 L 239,17 L 240,17 L 241,17 L 242,17 L 243,17 L 244,17 L 245,17 L 246,17 L 247,17 L 248,17 L 249,17 L 250,17 L 251,17 L 252,17 L 253,17 L 254,18 L 255,18 L 256,18 L 257,18 L 258,18 L 259,18 L 260,18 L 261,18 L 262,18 L 263,18 L 264,18 L 265,18 L 266,18 L 266,19 L 267,19 L 268,19 L 269,19 L 270,19 L 271,19 L 272,19 L 273,19 L 274,19 L 275,19 L 275,20 L 276,20 L 277,20 L 278,20 L 279,20 L 280,20 L 281,20 L 282,20 L 282,21 L 283,21 L 284,21 L 285,21 L 286,21 L 287,21 L 288,21 L 288,22 L 289,22 L 290,22 L 291,22 L 292,22 L 293,22 L 293,23 L 294,23 L 295,23 L 296,23 L 297,23 L 298,23 L 298,24 L 299,24 L 300,24 L 301,24 L 302,24 L 303,24 L 303,25 L 304,25 L 305,25 L 306,25 L 307,25 L 307,26 L 308,26 L 309,26 L 310,26 L 311,26 L 311,27 L 312,27 L 313,27 L 314,27 L 315,27 L 315,28 L 316,28 L 317,28 L 318,28 L 319,28 L 319,29 L 320,29 L 321,29 L 322,29 L 323,30 L 324,30 L 325,30 L 326,30 L 326,31 L 327,31 L 328,31 L 329,31 L 330,32 L 331,32 L 332,32 L 333,32 L 333,33 L 334,33 L 335,33 L 336,33 L 336,34 L 337,34 L 338,34 L 339,34 L 340,34 L 340,35 L 341,35 L 342,35 L 343,35 L 343,36 L 344,36 L 345,36 L 346,36 L 346,37 L 347,37 L 348,37 L 349,37 L 349,38 L 350,38 L 351,38 L 352,38 L 353,38 L 353,39 L 354,39 L 355,39 L 356,39 L 356,40 L 357,40 L 358,40 L 359,40 L 359,41 L 360,41 L 361,41 L 362,41 L 362,42 L 363,42 L 364,42 L 365,42 L 365,43 L 366,43 L 367,43 L 368,43 L 368,44 L 369,44 L 370,44 L 371,44 L 372,44 L 372,45 L 373,45 L 374,45 L 375,45 L 375,46 L 376,46 L 377,46 L 378,46 L 378,47 L 379,47 L 380,47 L 381,47 L 381,48 L 382,48 L 383,48 L 384,48 L 384,49 L 385,49 L 386,49 L 387,49 L 387,50 L 388,50 L 389,50 L 390,50 L 390,51 L 391,51 L 392,51 L 393,51 L 393,52 L 394,52 L 395,52 L 396,52 L 396,53 L 397,53 L 398,53 L 399,53 L 399,54 L 400,54 L 401,54 L 402,54 L 402,55 L 403,55 L 404,55 L 405,55 L 406,55 L 406,56 L 407,56 L 408,56 L 409,56 L 409,57 L 410,57 L 411,57 L 412,57 L 412,58 L 413,58 L 414,58 L 415,58 L 415,59 L 416,59 L 417,59 L 418,59 L 418,60 L 419,60 L 420,60 L 421,60 L 421,61 L 422,61 L 423,61 L 424,61 L 424,62 L 425,62 L 426,62 L 427,62 L 427,63 L 428,63 L 429,63 L 430,63 L 430,64 L 431,64 L 432,64 L 433,64 L 433,65 L 434,65 L 435,65 L 436,65 L 436,66 L 437,66 L 438,66 L 439,66 L 439,67 L 440,67 L 441,67 L 442,67 L 442,68 L 443,68 L 444,68 L 445,68 L 445,69 L 446,69 L 447,69 L 448,69 L 448,70 L 449,70 L 450,70 L 451,70 L 451,71 L 452,71 L 453,71 L 454,71 L 455,71 L 455,72 L 456,72 L 457,72 L 458,72 L 458,73 L 459,73 L 460,73 L 461,73 L 461,74 L 462,74 L 463,74 L 464,74 L 464,75 L 465,75 L 466,75 L 467,75 L 467,76 L 468,76 L 469,76 L 470,76 L 470,77 L 471,77 L 472,77 L 473,77 L 473,78 L 474,78 L 475,78 L 476,78 L 476,79 L 477,79 L 478,79 L 479,79 L 479,80 L 480,80 L 481,80 L 482,80 L 482,81 L 483,81 L 484,81 L 485,81 L 485,82 L 486,82 L 487,82 L 488,82 L 488,83 L 489,83 L 490,83 L 491,83 L 491,84 L 492,84 L 493,84 L 494,84 L 494,85 L 495,85 L 496,85 L 497,85 L 497,86 L 498,86 L 499,86 L 500,86 L 500,87 L 501,87 L 502,87 L 502,88 L 503,88 L 504,88 L 505,88 L 505,89 L 506,89 L 507,89 L 508,89 L 508,90 L 509,90 L 510,90 L 511,90 L 511,91 L 512,91 L 513,91 L 514,91 L 514,92 L 515,92 L 516,92 L 517,92 L 517,93 L 518,93 L 519,93 L 519,94 L 520,94 L 521,94 L 522,94 L 522,95 L 523,95 L 524,95 L 525,95 L 525,96 L 526,96 L 527,96 L 527,97 L 528,97 L 529,97 L 530,97 L 530,98 L 531,98 L 532,98 L 532,99 L 533,99 L 534,99 L 534,100 L 535,100 L 536,100 L 537,100 L 537,101 L 538,101 L 539,101 L 539,102 L 540,102 L 541,102 L 541,103 L 542,103 L 543,103 L 543,104 L 544,104 L 545,104 L 545,105 L 546,105 L 547,105 L 547,106 L 548,106 L 549,106 L 549,107 L 550,107 L 551,107 L 551,108 L 552,108 L 552,109 L 553,109 L 554,109 L 554,110 L 555,110 L 555,111 L 556,111 L 557,111 L 557,112 L 558,112 L 558,113 L 559,113 L 559,114 L 560,114 L 560,115 L 561,115 L 561,116 L 562,116 L 562,117 L 563,117 L 563,118 L 564,118 L 564,119 L 565,119 L 565,120 L 565,121 L 566,121 L 566,122 L 567,122 L 567,123 L 567,124 L 568,124 L 568,125 L 568,126 L 569,126 L 569,127 L 569,128 L 570,128 L 570,129 L 570,130 L 570,131 L 571,131 L 571,132 L 571,133 L 571,134 L 572,134 L 572,135 L 572,136 L 572,137 L 572,138 L 572,139 L 573,139 L 573,140 L 573,141 L 573,142 L 573,143 L 573,144 L 573,145 L 573,146 L 574,146 L 574,147 L 574,148 L 574,149 L 574,150 L 574,151 L 574,152 L 574,153 L 574,154 L 574,155 L 574,156 L 574,157 L 574,158 L 574,159 L 574,160 L 574,161 L 575,161 L 575,162 L 575,163 L 575,164 L 575,165 L 575,166 L 575,167 L 575,168 L 575,169 L 575,170 L 575,171 L 575,172 L 575,173 L 575,174 L 575,175 L 575,176 L 575,177 L 575,178 L 575,179 L 575,180 L 575,181 L 575,182 L 575,183 L 575,184 L 575,185 L 575,186"
+ id="path5348" />
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g5352">
+ <g
+ transform="translate(147,172)"
+ style="font-size:12px;text-anchor:end;fill:#000000;stroke:none;font-family:Arial"
+ id="g5354">
+ <text
+ id="text5356">s = 2^16</text>
+ </g>
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#00ffff;fill:none;stroke:currentColor;stroke-width:1"
+ id="g5358">
+ <path
+ d="M 155,168 L 196,168 M 75,16 L 105,16 L 123,17 L 135,18 L 145,18 L 153,19 L 160,20 L 165,21 L 170,22 L 175,23 L 179,24 L 183,25 L 186,25 L 190,26 L 193,27 L 195,28 L 198,28 L 201,29 L 203,30 L 205,30 L 207,31 L 209,32 L 211,32 L 213,33 L 215,33 L 216,34 L 218,34 L 220,35 L 221,35 L 223,36 L 224,36 L 226,36 L 227,37 L 228,37 L 229,38 L 231,38 L 232,38 L 233,39 L 234,39 L 235,39 L 236,40 L 237,40 L 238,40 L 239,41 L 240,41 L 241,41 L 242,42 L 243,42 L 244,42 L 245,43 L 246,43 L 247,43 L 248,44 L 249,44 L 250,44 L 251,44 L 251,45 L 252,45 L 253,45 L 254,45 L 254,46 L 255,46 L 256,46 L 257,46 L 258,47 L 259,47 L 260,47 L 261,48 L 262,48 L 263,48 L 264,49 L 265,49 L 266,49 L 267,50 L 268,50 L 269,50 L 270,51 L 271,51 L 272,51 L 273,52 L 274,52 L 275,52 L 276,53 L 277,53 L 278,53 L 279,53 L 279,54 L 280,54 L 281,54 L 282,54 L 282,55 L 283,55 L 284,55 L 285,55 L 285,56 L 286,56 L 287,56 L 288,56 L 288,57 L 289,57 L 290,57 L 291,57 L 291,58 L 292,58 L 293,58 L 294,58 L 294,59 L 295,59 L 296,59 L 297,59 L 298,60 L 299,60 L 300,60 L 301,61 L 302,61 L 303,61 L 304,62 L 305,62 L 306,62 L 307,63 L 308,63 L 309,63 L 310,63 L 310,64 L 311,64 L 312,64 L 313,64 L 313,65 L 314,65 L 315,65 L 316,65 L 316,66 L 317,66 L 318,66 L 319,66 L 319,67 L 320,67 L 321,67 L 322,67 L 322,68 L 323,68 L 324,68 L 325,68 L 325,69 L 326,69 L 327,69 L 328,69 L 328,70 L 329,70 L 330,70 L 331,70 L 331,71 L 332,71 L 333,71 L 334,71 L 334,72 L 335,72 L 336,72 L 337,72 L 337,73 L 338,73 L 339,73 L 340,73 L 340,74 L 341,74 L 342,74 L 343,74 L 343,75 L 344,75 L 345,75 L 346,75 L 347,76 L 348,76 L 349,76 L 350,76 L 350,77 L 351,77 L 352,77 L 353,77 L 353,78 L 354,78 L 355,78 L 356,78 L 356,79 L 357,79 L 358,79 L 359,79 L 359,80 L 360,80 L 361,80 L 362,80 L 362,81 L 363,81 L 364,81 L 365,81 L 365,82 L 366,82 L 367,82 L 368,82 L 368,83 L 369,83 L 370,83 L 371,83 L 371,84 L 372,84 L 373,84 L 374,84 L 374,85 L 375,85 L 376,85 L 377,85 L 377,86 L 378,86 L 379,86 L 380,86 L 380,87 L 381,87 L 382,87 L 383,87 L 383,88 L 384,88 L 385,88 L 386,88 L 386,89 L 387,89 L 388,89 L 389,89 L 389,90 L 390,90 L 391,90 L 392,90 L 392,91 L 393,91 L 394,91 L 395,91 L 396,92 L 397,92 L 398,92 L 399,92 L 399,93 L 400,93 L 401,93 L 402,93 L 402,94 L 403,94 L 404,94 L 405,94 L 405,95 L 406,95 L 407,95 L 408,95 L 408,96 L 409,96 L 410,96 L 411,96 L 411,97 L 412,97 L 413,97 L 414,97 L 414,98 L 415,98 L 416,98 L 417,98 L 417,99 L 418,99 L 419,99 L 420,99 L 420,100 L 421,100 L 422,100 L 423,100 L 423,101 L 424,101 L 425,101 L 426,101 L 426,102 L 427,102 L 428,102 L 429,102 L 429,103 L 430,103 L 431,103 L 432,103 L 432,104 L 433,104 L 434,104 L 435,104 L 435,105 L 436,105 L 437,105 L 438,105 L 438,106 L 439,106 L 440,106 L 441,106 L 441,107 L 442,107 L 443,107 L 444,107 L 444,108 L 445,108 L 446,108 L 447,108 L 448,108 L 448,109 L 449,109 L 450,109 L 451,109 L 451,110 L 452,110 L 453,110 L 454,110 L 454,111 L 455,111 L 456,111 L 457,111 L 457,112 L 458,112 L 459,112 L 460,112 L 460,113 L 461,113 L 462,113 L 463,113 L 463,114 L 464,114 L 465,114 L 466,114 L 466,115 L 467,115 L 468,115 L 469,115 L 469,116 L 470,116 L 471,116 L 472,116 L 472,117 L 473,117 L 474,117 L 475,117 L 475,118 L 476,118 L 477,118 L 478,118 L 478,119 L 479,119 L 480,119 L 481,119 L 481,120 L 482,120 L 483,120 L 484,120 L 484,121 L 485,121 L 486,121 L 487,121 L 487,122 L 488,122 L 489,122 L 490,122 L 490,123 L 491,123 L 492,123 L 493,123 L 493,124 L 494,124 L 495,124 L 496,124 L 496,125 L 497,125 L 498,125 L 499,125 L 499,126 L 500,126 L 501,126 L 502,126 L 502,127 L 503,127 L 504,127 L 504,128 L 505,128 L 506,128 L 507,128 L 507,129 L 508,129 L 509,129 L 510,129 L 510,130 L 511,130 L 512,130 L 513,130 L 513,131 L 514,131 L 515,131 L 516,131 L 516,132 L 517,132 L 518,132 L 518,133 L 519,133 L 520,133 L 521,133 L 521,134 L 522,134 L 523,134 L 524,134 L 524,135 L 525,135 L 526,135 L 526,136 L 527,136 L 528,136 L 529,136 L 529,137 L 530,137 L 531,137 L 531,138 L 532,138 L 533,138 L 534,138 L 534,139 L 535,139 L 536,139 L 536,140 L 537,140 L 538,140 L 538,141 L 539,141 L 540,141 L 540,142 L 541,142 L 542,142 L 543,142 L 543,143 L 544,143 L 545,143 L 545,144 L 546,144 L 547,144 L 547,145 L 548,145 L 548,146 L 549,146 L 550,146 L 550,147 L 551,147 L 552,147 L 552,148 L 553,148 L 553,149 L 554,149 L 555,149 L 555,150 L 556,150 L 556,151 L 557,151 L 557,152 L 558,152 L 559,152 L 559,153 L 560,153 L 560,154 L 561,154 L 561,155 L 562,155 L 562,156 L 563,156 L 563,157 L 564,157 L 564,158 L 565,158 L 565,159 L 565,160 L 566,160 L 566,161 L 567,161 L 567,162 L 567,163 L 568,163 L 568,164 L 568,165 L 569,165 L 569,166 L 569,167 L 570,167 L 570,168 L 570,169 L 570,170 L 571,170 L 571,171 L 571,172 L 571,173 L 572,173 L 572,174 L 572,175 L 572,176 L 572,177 L 572,178 L 573,178 L 573,179 L 573,180 L 573,181 L 573,182 L 573,183 L 573,184 L 573,185 L 574,185 L 574,186"
+ id="path5360" />
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g7002">
+ <g
+ transform="translate(147,358)"
+ style="font-size:12px;text-anchor:end;fill:#000000;stroke:none;font-family:Arial"
+ id="g7004">
+ <text
+ id="text7006">s = 2^0</text>
+ </g>
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#ff0000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g7008">
+ <path
+ d="M 155,354 L 196,354 M 75,256 L 105,256 L 123,256 L 135,256 L 145,256 L 153,256 L 160,256 L 165,256 L 170,256 L 175,256 L 179,256 L 183,256 L 186,256 L 190,256 L 193,256 L 195,256 L 198,256 L 201,256 L 203,256 L 205,256 L 207,256 L 209,256 L 211,256 L 213,256 L 215,256 L 216,256 L 218,256 L 220,256 L 221,256 L 223,256 L 224,256 L 226,256 L 227,256 L 228,256 L 229,256 L 231,256 L 232,256 L 233,256 L 234,256 L 235,256 L 236,256 L 237,256 L 238,256 L 239,256 L 240,256 L 241,256 L 242,256 L 243,256 L 244,256 L 245,256 L 246,256 L 247,256 L 248,256 L 249,256 L 250,256 L 251,256 L 252,256 L 253,256 L 254,256 L 255,256 L 256,256 L 257,256 L 258,256 L 259,256 L 260,256 L 261,256 L 262,256 L 263,256 L 264,256 L 265,256 L 266,256 L 267,256 L 268,256 L 269,256 L 270,256 L 271,256 L 272,256 L 273,256 L 274,256 L 275,256 L 276,256 L 277,256 L 278,256 L 279,256 L 280,256 L 281,256 L 282,256 L 283,256 L 284,256 L 285,256 L 286,256 L 287,256 L 288,256 L 289,256 L 290,256 L 291,256 L 292,256 L 293,256 L 294,256 L 295,256 L 296,256 L 297,256 L 298,256 L 299,256 L 300,256 L 301,256 L 302,256 L 303,256 L 304,256 L 305,256 L 306,256 L 307,256 L 308,256 L 309,256 L 310,256 L 311,256 L 312,256 L 313,256 L 314,256 L 315,256 L 316,256 L 317,256 L 318,256 L 319,256 L 320,256 L 321,256 L 322,256 L 323,256 L 324,256 L 325,256 L 326,256 L 327,256 L 328,256 L 329,256 L 330,256 L 331,256 L 332,256 L 333,256 L 334,256 L 335,256 L 336,256 L 337,256 L 338,256 L 339,256 L 340,256 L 341,256 L 342,256 L 343,256 L 344,256 L 345,256 L 346,256 L 347,256 L 348,256 L 349,256 L 350,256 L 351,256 L 352,256 L 352,257 L 353,257 L 354,257 L 355,257 L 356,257 L 357,257 L 358,257 L 359,257 L 360,257 L 361,257 L 362,257 L 363,257 L 364,257 L 365,257 L 366,257 L 367,257 L 368,257 L 369,257 L 370,257 L 371,257 L 372,257 L 373,257 L 374,257 L 375,257 L 376,257 L 377,257 L 378,257 L 379,257 L 380,257 L 381,257 L 382,257 L 383,257 L 384,257 L 385,257 L 386,257 L 387,257 L 388,257 L 389,257 L 390,257 L 391,257 L 392,257 L 393,257 L 394,257 L 395,257 L 396,257 L 397,257 L 398,257 L 399,257 L 400,257 L 400,258 L 401,258 L 402,258 L 403,258 L 404,258 L 405,258 L 406,258 L 407,258 L 408,258 L 409,258 L 410,258 L 411,258 L 412,258 L 413,258 L 414,258 L 415,258 L 416,258 L 417,258 L 418,258 L 419,258 L 420,258 L 421,258 L 422,258 L 422,259 L 423,259 L 424,259 L 425,259 L 426,259 L 427,259 L 428,259 L 429,259 L 430,259 L 431,259 L 432,259 L 433,259 L 434,259 L 435,259 L 436,259 L 436,260 L 437,260 L 438,260 L 439,260 L 440,260 L 441,260 L 442,260 L 443,260 L 444,260 L 445,260 L 446,260 L 447,260 L 447,261 L 448,261 L 449,261 L 450,261 L 451,261 L 452,261 L 453,261 L 454,261 L 455,261 L 456,261 L 456,262 L 457,262 L 458,262 L 459,262 L 460,262 L 461,262 L 462,262 L 463,262 L 463,263 L 464,263 L 465,263 L 466,263 L 467,263 L 468,263 L 469,263 L 470,263 L 470,264 L 471,264 L 472,264 L 473,264 L 474,264 L 475,264 L 475,265 L 476,265 L 477,265 L 478,265 L 479,265 L 480,265 L 480,266 L 481,266 L 482,266 L 483,266 L 484,266 L 484,267 L 485,267 L 486,267 L 487,267 L 488,267 L 488,268 L 489,268 L 490,268 L 491,268 L 492,268 L 492,269 L 493,269 L 494,269 L 495,269 L 495,270 L 496,270 L 497,270 L 498,270 L 498,271 L 499,271 L 500,271 L 501,271 L 501,272 L 502,272 L 503,272 L 504,272 L 504,273 L 505,273 L 506,273 L 506,274 L 507,274 L 508,274 L 509,274 L 509,275 L 510,275 L 511,275 L 511,276 L 512,276 L 513,276 L 513,277 L 514,277 L 515,277 L 515,278 L 516,278 L 517,278 L 517,279 L 518,279 L 519,279 L 519,280 L 520,280 L 521,280 L 521,281 L 522,281 L 523,281 L 523,282 L 524,282 L 524,283 L 525,283 L 526,283 L 526,284 L 527,284 L 528,284 L 528,285 L 529,285 L 529,286 L 530,286 L 530,287 L 531,287 L 532,287 L 532,288 L 533,288 L 533,289 L 534,289 L 535,289 L 535,290 L 536,290 L 536,291 L 537,291 L 537,292 L 538,292 L 538,293 L 539,293 L 539,294 L 540,294 L 541,294 L 541,295 L 542,295 L 542,296 L 543,296 L 543,297 L 544,297 L 544,298 L 545,298 L 545,299 L 546,299 L 546,300 L 547,300 L 547,301 L 548,301 L 548,302 L 549,302 L 549,303 L 550,303 L 550,304 L 551,304 L 551,305 L 552,305 L 552,306 L 552,307 L 553,307 L 553,308 L 554,308 L 554,309 L 555,309 L 555,310 L 556,310 L 556,311 L 556,312 L 557,312 L 557,313 L 558,313 L 558,314 L 559,314 L 559,315 L 560,315 L 560,316 L 560,317 L 561,317 L 561,318 L 562,318 L 562,319 L 562,320 L 563,320 L 563,321 L 564,321 L 564,322 L 564,323 L 565,323 L 565,324 L 566,324 L 566,325 L 566,326 L 567,326 L 567,327 L 567,328 L 568,328 L 568,329 L 569,329 L 569,330 L 569,331 L 570,331 L 570,332 L 570,333 L 571,333 L 571,334 L 572,334 L 572,335 L 572,336 L 573,336 L 573,337 L 573,338 L 574,338 L 574,339 L 574,340 L 575,340 L 575,341"
+ id="path7010" />
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g7014">
+ <g
+ transform="translate(147,376)"
+ style="font-size:12px;text-anchor:end;fill:#000000;stroke:none;font-family:Arial"
+ id="g7016">
+ <text
+ id="text7018">s = 2^4</text>
+ </g>
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#008000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g7020">
+ <path
+ d="M 155,372 L 196,372 M 75,256 L 105,256 L 123,256 L 135,256 L 145,256 L 153,256 L 160,256 L 165,256 L 170,256 L 175,256 L 179,256 L 183,256 L 186,256 L 190,256 L 193,256 L 195,256 L 198,256 L 201,256 L 203,257 L 205,257 L 207,257 L 209,257 L 211,257 L 213,257 L 215,257 L 216,257 L 218,257 L 220,257 L 221,257 L 223,257 L 224,257 L 226,257 L 227,257 L 228,257 L 229,257 L 231,257 L 232,257 L 233,257 L 234,257 L 235,257 L 236,257 L 237,257 L 238,257 L 239,257 L 240,257 L 241,257 L 242,257 L 243,257 L 244,257 L 245,257 L 246,257 L 247,257 L 248,257 L 249,257 L 250,257 L 251,258 L 252,258 L 253,258 L 254,258 L 255,258 L 256,258 L 257,258 L 258,258 L 259,258 L 260,258 L 261,258 L 262,258 L 263,258 L 264,258 L 265,258 L 266,258 L 267,258 L 268,258 L 269,258 L 270,258 L 271,258 L 272,258 L 273,259 L 274,259 L 275,259 L 276,259 L 277,259 L 278,259 L 279,259 L 280,259 L 281,259 L 282,259 L 283,259 L 284,259 L 285,259 L 286,259 L 287,259 L 288,260 L 289,260 L 290,260 L 291,260 L 292,260 L 293,260 L 294,260 L 295,260 L 296,260 L 297,260 L 298,260 L 299,261 L 300,261 L 301,261 L 302,261 L 303,261 L 304,261 L 305,261 L 306,261 L 307,261 L 307,262 L 308,262 L 309,262 L 310,262 L 311,262 L 312,262 L 313,262 L 314,262 L 314,263 L 315,263 L 316,263 L 317,263 L 318,263 L 319,263 L 320,263 L 321,263 L 321,264 L 322,264 L 323,264 L 324,264 L 325,264 L 326,264 L 326,265 L 327,265 L 328,265 L 329,265 L 330,265 L 331,265 L 331,266 L 332,266 L 333,266 L 334,266 L 335,266 L 336,266 L 336,267 L 337,267 L 338,267 L 339,267 L 340,267 L 340,268 L 341,268 L 342,268 L 343,268 L 343,269 L 344,269 L 345,269 L 346,269 L 347,269 L 347,270 L 348,270 L 349,270 L 350,270 L 350,271 L 351,271 L 352,271 L 353,271 L 353,272 L 354,272 L 355,272 L 356,272 L 356,273 L 357,273 L 358,273 L 359,273 L 359,274 L 360,274 L 361,274 L 361,275 L 362,275 L 363,275 L 364,275 L 364,276 L 365,276 L 366,276 L 366,277 L 367,277 L 368,277 L 369,277 L 369,278 L 370,278 L 371,278 L 371,279 L 372,279 L 373,279 L 373,280 L 374,280 L 375,280 L 375,281 L 376,281 L 377,281 L 377,282 L 378,282 L 379,282 L 379,283 L 380,283 L 381,283 L 381,284 L 382,284 L 383,284 L 383,285 L 384,285 L 385,285 L 385,286 L 386,286 L 386,287 L 387,287 L 388,287 L 388,288 L 389,288 L 390,288 L 390,289 L 391,289 L 392,290 L 393,290 L 393,291 L 394,291 L 395,291 L 395,292 L 396,292 L 397,292 L 397,293 L 398,293 L 398,294 L 399,294 L 400,294 L 400,295 L 401,295 L 401,296 L 402,296 L 403,296 L 403,297 L 404,297 L 405,297 L 405,298 L 406,298 L 406,299 L 407,299 L 408,299 L 408,300 L 409,300 L 409,301 L 410,301 L 411,301 L 411,302 L 412,302 L 413,302 L 413,303 L 414,303 L 414,304 L 415,304 L 416,304 L 416,305 L 417,305 L 418,305 L 418,306 L 419,306 L 419,307 L 420,307 L 421,307 L 421,308 L 422,308 L 423,308 L 423,309 L 424,309 L 424,310 L 425,310 L 426,310 L 426,311 L 427,311 L 428,311 L 428,312 L 429,312 L 430,312 L 430,313 L 431,313 L 432,313 L 432,314 L 433,314 L 434,314 L 434,315 L 435,315 L 435,316 L 436,316 L 437,316 L 437,317 L 438,317 L 439,317 L 440,317 L 440,318 L 441,318 L 442,318 L 442,319 L 443,319 L 444,319 L 444,320 L 445,320 L 446,320 L 446,321 L 447,321 L 448,321 L 449,321 L 449,322 L 450,322 L 451,322 L 451,323 L 452,323 L 453,323 L 454,323 L 454,324 L 455,324 L 456,324 L 456,325 L 457,325 L 458,325 L 459,325 L 459,326 L 460,326 L 461,326 L 462,326 L 462,327 L 463,327 L 464,327 L 465,327 L 465,328 L 466,328 L 467,328 L 468,328 L 469,328 L 469,329 L 470,329 L 471,329 L 472,329 L 473,329 L 473,330 L 474,330 L 475,330 L 476,330 L 477,330 L 477,331 L 478,331 L 479,331 L 480,331 L 481,331 L 481,332 L 482,332 L 483,332 L 484,332 L 485,332 L 486,332 L 486,333 L 487,333 L 488,333 L 489,333 L 490,333 L 491,333 L 491,334 L 492,334 L 493,334 L 494,334 L 495,334 L 496,334 L 497,334 L 497,335 L 498,335 L 499,335 L 500,335 L 501,335 L 502,335 L 503,335 L 504,335 L 504,336 L 505,336 L 506,336 L 507,336 L 508,336 L 509,336 L 510,336 L 511,336 L 512,336 L 512,337 L 513,337 L 514,337 L 515,337 L 516,337 L 517,337 L 518,337 L 519,337 L 520,337 L 521,337 L 522,337 L 522,338 L 523,338 L 524,338 L 525,338 L 526,338 L 527,338 L 528,338 L 529,338 L 530,338 L 531,338 L 532,338 L 533,338 L 534,338 L 534,339 L 535,339 L 536,339 L 537,339 L 538,339 L 539,339 L 540,339 L 541,339 L 542,339 L 543,339 L 544,339 L 545,339 L 546,339 L 547,339 L 548,339 L 549,339 L 549,340 L 550,340 L 551,340 L 552,340 L 553,340 L 554,340 L 555,340 L 556,340 L 557,340 L 558,340 L 559,340 L 560,340 L 561,340 L 562,340 L 563,340 L 564,340 L 565,340 L 566,340 L 567,340 L 567,341 L 568,341 L 569,341 L 570,341 L 571,341 L 572,341 L 573,341 L 574,341 L 575,341"
+ id="path7022" />
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g7026">
+ <g
+ transform="translate(147,394)"
+ style="font-size:12px;text-anchor:end;fill:#000000;stroke:none;font-family:Arial"
+ id="g7028">
+ <text
+ id="text7030">s = 2^8</text>
+ </g>
+ </g>
+ <g
+ transform="translate(-1,0)"
+ style="color:#0000ff;fill:none;stroke:currentColor;stroke-width:1"
+ id="g7032">
+ <path
+ d="M 155,390 L 196,390 M 75,256 L 105,257 L 123,257 L 135,258 L 145,258 L 153,259 L 160,259 L 165,259 L 170,260 L 175,260 L 179,261 L 183,261 L 186,262 L 190,262 L 193,262 L 195,263 L 198,263 L 201,264 L 203,264 L 205,265 L 207,265 L 209,265 L 211,266 L 213,266 L 215,267 L 216,267 L 218,268 L 220,268 L 221,268 L 223,269 L 224,269 L 226,270 L 227,270 L 228,270 L 229,271 L 231,271 L 232,272 L 233,272 L 234,272 L 235,273 L 236,273 L 237,274 L 238,274 L 239,274 L 240,275 L 241,275 L 242,276 L 243,276 L 244,276 L 245,277 L 246,277 L 247,277 L 247,278 L 248,278 L 249,278 L 250,279 L 251,279 L 251,280 L 252,280 L 253,280 L 254,281 L 255,281 L 256,282 L 257,282 L 258,283 L 259,283 L 260,284 L 261,284 L 261,285 L 262,285 L 263,285 L 263,286 L 264,286 L 265,287 L 266,287 L 267,288 L 268,288 L 268,289 L 269,289 L 270,290 L 271,290 L 272,291 L 273,291 L 273,292 L 274,292 L 275,292 L 275,293 L 276,293 L 277,294 L 278,294 L 278,295 L 279,295 L 280,295 L 280,296 L 281,296 L 281,297 L 282,297 L 283,297 L 283,298 L 284,298 L 285,299 L 286,299 L 286,300 L 287,300 L 288,300 L 288,301 L 289,301 L 290,302 L 291,302 L 291,303 L 292,303 L 293,303 L 293,304 L 294,304 L 294,305 L 295,305 L 296,305 L 296,306 L 297,306 L 298,306 L 298,307 L 299,307 L 299,308 L 300,308 L 301,308 L 301,309 L 302,309 L 303,309 L 303,310 L 304,310 L 305,311 L 306,311 L 306,312 L 307,312 L 308,312 L 308,313 L 309,313 L 310,313 L 310,314 L 311,314 L 312,314 L 312,315 L 313,315 L 314,315 L 314,316 L 315,316 L 316,316 L 316,317 L 317,317 L 318,317 L 318,318 L 319,318 L 320,318 L 320,319 L 321,319 L 322,319 L 322,320 L 323,320 L 324,320 L 325,321 L 326,321 L 327,321 L 327,322 L 328,322 L 329,322 L 330,323 L 331,323 L 332,323 L 332,324 L 333,324 L 334,324 L 335,324 L 335,325 L 336,325 L 337,325 L 338,325 L 338,326 L 339,326 L 340,326 L 341,326 L 341,327 L 342,327 L 343,327 L 344,327 L 344,328 L 345,328 L 346,328 L 347,328 L 347,329 L 348,329 L 349,329 L 350,329 L 351,329 L 351,330 L 352,330 L 353,330 L 354,330 L 355,330 L 355,331 L 356,331 L 357,331 L 358,331 L 359,331 L 360,331 L 360,332 L 361,332 L 362,332 L 363,332 L 364,332 L 365,332 L 365,333 L 366,333 L 367,333 L 368,333 L 369,333 L 370,333 L 370,334 L 371,334 L 372,334 L 373,334 L 374,334 L 375,334 L 376,334 L 376,335 L 377,335 L 378,335 L 379,335 L 380,335 L 381,335 L 382,335 L 383,335 L 384,335 L 384,336 L 385,336 L 386,336 L 387,336 L 388,336 L 389,336 L 390,336 L 391,336 L 392,336 L 392,337 L 393,337 L 394,337 L 395,337 L 396,337 L 397,337 L 398,337 L 399,337 L 400,337 L 401,337 L 402,337 L 403,337 L 403,338 L 404,338 L 405,338 L 406,338 L 407,338 L 408,338 L 409,338 L 410,338 L 411,338 L 412,338 L 413,338 L 414,338 L 415,338 L 416,338 L 417,338 L 418,338 L 418,339 L 419,339 L 420,339 L 421,339 L 422,339 L 423,339 L 424,339 L 425,339 L 426,339 L 427,339 L 428,339 L 429,339 L 430,339 L 431,339 L 432,339 L 433,339 L 434,339 L 435,339 L 436,339 L 437,339 L 438,339 L 439,339 L 440,339 L 440,340 L 441,340 L 442,340 L 443,340 L 444,340 L 445,340 L 446,340 L 447,340 L 448,340 L 449,340 L 450,340 L 451,340 L 452,340 L 453,340 L 454,340 L 455,340 L 456,340 L 457,340 L 458,340 L 459,340 L 460,340 L 461,340 L 462,340 L 463,340 L 464,340 L 465,340 L 466,340 L 467,340 L 468,340 L 469,340 L 470,340 L 471,340 L 472,340 L 473,340 L 474,340 L 475,340 L 476,340 L 477,340 L 478,340 L 479,340 L 480,340 L 481,340 L 482,340 L 483,340 L 484,340 L 485,340 L 486,340 L 487,340 L 487,341 L 488,341 L 489,341 L 490,341 L 491,341 L 492,341 L 493,341 L 494,341 L 495,341 L 496,341 L 497,341 L 498,341 L 499,341 L 500,341 L 501,341 L 502,341 L 503,341 L 504,341 L 505,341 L 506,341 L 507,341 L 508,341 L 509,341 L 510,341 L 511,341 L 512,341 L 513,341 L 514,341 L 515,341 L 516,341 L 517,341 L 518,341 L 519,341 L 520,341 L 521,341 L 522,341 L 523,341 L 524,341 L 525,341 L 526,341 L 527,341 L 528,341 L 529,341 L 530,341 L 531,341 L 532,341 L 533,341 L 534,341 L 535,341 L 536,341 L 537,341 L 538,341 L 539,341 L 540,341 L 541,341 L 542,341 L 543,341 L 544,341 L 545,341 L 546,341 L 547,341 L 548,341 L 549,341 L 550,341 L 551,341 L 552,341 L 553,341 L 554,341 L 555,341 L 556,341 L 557,341 L 558,341 L 559,341 L 560,341 L 561,341 L 562,341 L 563,341 L 564,341 L 565,341 L 566,341 L 567,341 L 568,341 L 569,341 L 570,341 L 571,341 L 572,341 L 573,341 L 574,341 L 575,341"
+ id="path7034" />
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#000000;fill:none;stroke:currentColor;stroke-width:1"
+ id="g7038">
+ <g
+ transform="translate(147,412)"
+ style="font-size:12px;text-anchor:end;fill:#000000;stroke:none;font-family:Arial"
+ id="g7040">
+ <text
+ id="text7042">s = 2^16</text>
+ </g>
+ </g>
+ <g
+ transform="translate(-0.5,0)"
+ style="color:#00ffff;fill:none;stroke:currentColor;stroke-width:1"
+ id="g7044">
+ <path
+ d="M 155,408 L 196,408 M 75,263 L 105,270 L 123,276 L 135,282 L 145,287 L 153,292 L 160,296 L 165,299 L 170,302 L 175,305 L 179,308 L 183,310 L 186,312 L 190,314 L 193,315 L 195,317 L 198,318 L 201,319 L 203,320 L 205,321 L 207,322 L 209,323 L 211,323 L 213,324 L 215,325 L 216,325 L 218,326 L 220,326 L 221,327 L 223,327 L 224,328 L 226,328 L 227,328 L 228,329 L 229,329 L 231,329 L 232,330 L 233,330 L 234,330 L 235,331 L 236,331 L 237,331 L 238,331 L 239,332 L 240,332 L 241,332 L 242,332 L 243,332 L 244,332 L 245,333 L 246,333 L 247,333 L 248,333 L 249,333 L 250,334 L 251,334 L 252,334 L 253,334 L 254,334 L 255,334 L 256,334 L 256,335 L 257,335 L 258,335 L 259,335 L 260,335 L 261,335 L 262,335 L 263,335 L 264,336 L 265,336 L 266,336 L 267,336 L 268,336 L 269,336 L 270,336 L 271,336 L 272,336 L 272,337 L 273,337 L 274,337 L 275,337 L 276,337 L 277,337 L 278,337 L 279,337 L 280,337 L 281,337 L 282,337 L 283,337 L 283,338 L 284,338 L 285,338 L 286,338 L 287,338 L 288,338 L 289,338 L 290,338 L 291,338 L 292,338 L 293,338 L 294,338 L 295,338 L 296,338 L 297,338 L 298,338 L 298,339 L 299,339 L 300,339 L 301,339 L 302,339 L 303,339 L 304,339 L 305,339 L 306,339 L 307,339 L 308,339 L 309,339 L 310,339 L 311,339 L 312,339 L 313,339 L 314,339 L 315,339 L 316,339 L 317,339 L 318,339 L 319,339 L 320,339 L 320,340 L 321,340 L 322,340 L 323,340 L 324,340 L 325,340 L 326,340 L 327,340 L 328,340 L 329,340 L 330,340 L 331,340 L 332,340 L 333,340 L 334,340 L 335,340 L 336,340 L 337,340 L 338,340 L 339,340 L 340,340 L 341,340 L 342,340 L 343,340 L 344,340 L 345,340 L 346,340 L 347,340 L 348,340 L 349,340 L 350,340 L 351,340 L 352,340 L 353,340 L 354,340 L 355,340 L 356,340 L 357,340 L 358,340 L 359,340 L 360,340 L 361,340 L 362,340 L 363,340 L 364,340 L 365,340 L 366,340 L 367,340 L 367,341 L 368,341 L 369,341 L 370,341 L 371,341 L 372,341 L 373,341 L 374,341 L 375,341 L 376,341 L 377,341 L 378,341 L 379,341 L 380,341 L 381,341 L 382,341 L 383,341 L 384,341 L 385,341 L 386,341 L 387,341 L 388,341 L 389,341 L 390,341 L 391,341 L 392,341 L 393,341 L 394,341 L 395,341 L 396,341 L 397,341 L 398,341 L 399,341 L 400,341 L 401,341 L 402,341 L 403,341 L 404,341 L 405,341 L 406,341 L 407,341 L 408,341 L 409,341 L 410,341 L 411,341 L 412,341 L 413,341 L 414,341 L 415,341 L 416,341 L 417,341 L 418,341 L 419,341 L 420,341 L 421,341 L 422,341 L 423,341 L 424,341 L 425,341 L 426,341 L 427,341 L 428,341 L 429,341 L 430,341 L 431,341 L 432,341 L 433,341 L 434,341 L 435,341 L 436,341 L 437,341 L 438,341 L 439,341 L 440,341 L 441,341 L 442,341 L 443,341 L 444,341 L 445,341 L 446,341 L 447,341 L 448,341 L 449,341 L 450,341 L 451,341 L 452,341 L 453,341 L 454,341 L 455,341 L 456,341 L 457,341 L 458,341 L 459,341 L 460,341 L 461,341 L 462,341 L 463,341 L 464,341 L 465,341 L 466,341 L 467,341 L 468,341 L 469,341 L 470,341 L 471,341 L 472,341 L 473,341 L 474,341 L 475,341 L 476,341 L 477,341 L 478,341 L 479,341 L 480,341 L 481,341 L 482,341 L 483,341 L 484,341 L 485,341 L 486,341 L 487,341 L 488,341 L 489,341 L 490,341 L 491,341 L 492,341 L 493,341 L 494,341 L 495,341 L 496,341 L 497,341 L 498,341 L 499,341 L 500,341 L 501,341 L 502,341 L 503,341 L 504,341 L 505,341 L 506,341 L 507,341 L 508,341 L 509,341 L 510,341 L 511,341 L 512,341 L 513,341 L 514,341 L 515,341 L 516,341 L 517,341 L 518,341 L 519,341 L 520,341 L 521,341 L 522,341 L 523,341 L 524,341 L 525,341 L 526,341 L 527,341 L 528,341 L 529,341 L 530,341 L 531,341 L 532,341 L 533,341 L 534,341 L 535,341 L 536,341 L 537,341 L 538,341 L 539,341 L 540,341 L 541,341 L 542,341 L 543,341 L 544,341 L 545,341 L 546,341 L 547,341 L 548,341 L 549,341 L 550,341 L 551,341 L 552,341 L 553,341 L 554,341 L 555,341 L 556,341 L 557,341 L 558,341 L 559,341 L 560,341 L 561,341 L 562,341 L 563,341 L 564,341 L 565,341 L 566,341 L 567,341 L 568,341 L 569,341 L 570,341 L 571,341 L 572,341 L 573,341 L 574,341 L 575,341"
+ id="path7046" />
+ </g>
+ </g>
+</svg>
diff --git a/third_party/ptpd-1.1.0/doc/index.html b/third_party/ptpd-1.1.0/doc/index.html new file mode 100644 index 0000000..5c39e94 --- /dev/null +++ b/third_party/ptpd-1.1.0/doc/index.html @@ -0,0 +1,125 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+<title>PTPd - Precision Time Protocol daemon</title>
+<link href="stylesheet.css" rel="stylesheet" type="text/css" />
+</head>
+
+<body>
+
+<!-- begin header -->
+<table width="100%" border="0" cellpadding="4" cellspacing="0" class="info_table">
+<tr>
+<td>
+<center><p class="info_text">
+Last site update: 12 October 2010 | Latest PTPd version 1: <a
+ class="info_text"
+ href="http://sourceforge.net/projects/ptpd/files/ptpd/1.1.0/ptpd-1.1.0.tar.gz/download">1.1.0</a> Latest PTPd version 2: <a class="info_text" href="http://sourceforge.net/projects/ptpd/files/ptpd/2.1.0/ptpd-2.1.0.tar.gz/download">2.1.0</a>
+| PTPd is hosted by
+<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=139814&type=2" width="125" height="37" border="0" alt="SourceForge.net Logo" align="absmiddle"/></a>
+</p>
+</center>
+</td>
+</tr>
+</table>
+
+<table width="100%" border="0" cellpadding="20" cellspacing="0">
+<tr>
+<td>
+<center><font class="title_text">PTPd</font></center>
+<center<font class="subtitle_text"> (Version 1 and Version 2)</font></center>
+</td>
+</tr>
+</table>
+<!-- end header -->
+
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+<tr>
+
+<td valign="top">
+
+<!-- begin sidebar -->
+<table border="0" cellpadding="0" cellspacing="0" class="sidebar_table">
+<tr>
+<td class="sidebar_heading">PTPd</td>
+</tr>
+<tr>
+<td><a class="sidebar_link" href="http://sourceforge.net/projects/ptpd/">Project Page</a></td>
+</tr>
+<tr>
+<td><a class="sidebar_link" href="http://sourceforge.net/project/showfiles.php?group_id=139814">Download</a></td>
+</tr>
+<tr>
+<td><a class="sidebar_link" href="http://ptpd.svn.sourceforge.net/">Browse Source</a></td>
+</tr>
+<tr>
+<td><a class="sidebar_link" href="doc.html">Documentation</a></td>
+</tr>
+<tr><td> </td></tr>
+<tr>
+<td class="sidebar_heading">Related Projects</td>
+</tr>
+<tr>
+<td><a class="sidebar_link" href="http://ieee1588.nist.gov/">IEEE 1588</a></td>
+</tr>
+<tr>
+<td><a class="sidebar_link" href="http://www.lxistandard.org/">LXI Consortium</a></td>
+</tr>
+<tr>
+<td><a class="sidebar_link" href="http://www.ntp.org/">NTP</a></td>
+</tr>
+</table>
+<!-- end sidebar -->
+
+</td>
+
+<td class="vline"></td>
+<td valign="top">
+
+<!-- begin body -->
+<table border="0" cellpadding="0" cellspacing="0" class="content_table">
+<tr><td>
+
+<p> The PTP daemon (PTPd) implements the Precision Time protocol (PTP)
+as defined by the relevant IEEE 1588 standard. PTP Version 1
+implements IEEE-1588-2002, and PTP Version 2 implements
+IEEE-1588-2008. PTP was developed to provide very precise time
+coordination of LAN connected computers. </p>
+
+<p> PTPd is a complete implementation of the IEEE 1588 specification
+for a standard (non-boundary) clock. PTPd has been tested with and is
+known to work properly with other IEEE 1588 implementations. The
+source code for PTPd is freely available under a BSD-style
+license. Thanks to contributions from users, PTPd is becoming an
+increasingly portable, interoperable, and stable IEEE 1588
+implementation. </p>
+
+<p> PTPd can run on most 32-bit or 64-bit, little- or big-endian processors. It
+does not require an FPU, so it is great for embedded processors. PTPd
+currently runs on Linux, uClinux, FreeBSD, and NetBSD. It should also
+be easy to port to other platforms. </p>
+
+<p>PTPd is free. Everyone is welcome to use and contribute to PTPd. </p>
+
+<p>The PTPd project would like to thank the following for their kind
+ donations of equipment and time:
+
+ <dl>
+ <dt><a href="http://www.meinberg.de/english" >Meinberg Corp </a>
+ <dd>Donation of an m600 PTPv2 GPS Grandmaster Clock
+ <dt><a href="https://ssl.sentex.ca/" >Sentex Data Communications</a>
+ <dd>Hosting the FreeBSD Network Test Cluster
+ <dt><a href="http://www.freebsdfoundation.org/" >The FreeBSD Foundation </a>
+ <dd>Providing testing resources for the PTPd Project
+ </dl>
+</td></tr></table>
+<!-- end body -->
+
+</td>
+
+</tr></table>
+
+</body>
+</html>
+
diff --git a/third_party/ptpd-1.1.0/doc/organization.svg b/third_party/ptpd-1.1.0/doc/organization.svg new file mode 100644 index 0000000..7207b46 --- /dev/null +++ b/third_party/ptpd-1.1.0/doc/organization.svg @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.0"
+ width="600"
+ height="300"
+ id="svg2">
+ <defs
+ id="defs3" />
+ <g
+ id="layer1">
+ <rect
+ width="537.60052"
+ height="90.038086"
+ x="32"
+ y="41"
+ style="fill:#b9f7b9;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5125" />
+ <rect
+ width="107.4166"
+ height="60.643112"
+ x="409.04169"
+ y="21.356888"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect6665" />
+ <rect
+ width="539.01831"
+ height="89.862396"
+ x="31"
+ y="190.62921"
+ style="fill:#f7bcbc;fill-opacity:1;stroke:#000000;stroke-opacity:1"
+ id="rect9023" />
+ <rect
+ width="79.138618"
+ height="100.41978"
+ x="343.86139"
+ y="110"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect8973" />
+ <rect
+ width="89.388191"
+ height="73.291954"
+ x="142.61182"
+ y="198.91443"
+ style="fill:#f7bcbc;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect9013" />
+ <rect
+ width="89.578773"
+ height="101.717"
+ x="187.90994"
+ y="109"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect8981" />
+ <rect
+ width="81.134224"
+ height="38.52906"
+ x="476.97614"
+ y="110.3124"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect8989" />
+ <rect
+ width="80.564644"
+ height="57.965923"
+ x="119.93536"
+ y="89.955513"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect8999" />
+ <rect
+ width="40.650223"
+ height="111.63338"
+ x="43.5"
+ y="96.366623"
+ style="fill:#b9f7b9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1470" />
+ <text
+ x="231.82481"
+ y="153.29747"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4581"
+ xml:space="preserve"><tspan
+ x="231.82481"
+ y="153.29747"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4583">Net</tspan><tspan
+ x="231.82481"
+ y="175.79747"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4585">Layer</tspan></text>
+ <text
+ x="159.34317"
+ y="114.12207"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4593"
+ xml:space="preserve"><tspan
+ x="159.34317"
+ y="114.12207"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4597">Msg</tspan><tspan
+ x="159.34317"
+ y="136.62207"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4599">Packer</tspan></text>
+ <text
+ x="300.39597"
+ y="90.984863"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4601"
+ xml:space="preserve"><tspan
+ x="300.39597"
+ y="90.984863"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4605">Protocol Engine</tspan></text>
+ <text
+ x="463.44873"
+ y="45.236061"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4607"
+ xml:space="preserve"><tspan
+ x="463.44873"
+ y="45.236061"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4611">BMC</tspan><tspan
+ x="463.44873"
+ y="67.736061"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan12405">Algorithm</tspan></text>
+ <text
+ x="-152.28439"
+ y="68.632729"
+ transform="matrix(0,-1,1,0,0,0)"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4613"
+ xml:space="preserve"><tspan
+ x="-152.28439"
+ y="68.632729"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4615">Start-up</tspan></text>
+ <text
+ x="187.20483"
+ y="229.08727"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4617"
+ xml:space="preserve"><tspan
+ x="187.20483"
+ y="229.08727"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4621">Time</tspan><tspan
+ x="187.20483"
+ y="251.58727"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4623">Stamp</tspan></text>
+ <text
+ x="381.80273"
+ y="155.67033"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4625"
+ xml:space="preserve"><tspan
+ x="381.80273"
+ y="155.67033"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;font-family:Bitstream Vera Sans"
+ id="tspan4629">Clock</tspan><tspan
+ x="381.80273"
+ y="178.17033"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;font-family:Bitstream Vera Sans"
+ id="tspan4631">Servo</tspan></text>
+ <text
+ x="300.46521"
+ y="242.27086"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text4633"
+ xml:space="preserve"><tspan
+ x="300.46521"
+ y="242.27086"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan4635">Kernel</tspan></text>
+ <text
+ x="518.01343"
+ y="136.28738"
+ style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ id="text5363"
+ xml:space="preserve"><tspan
+ x="518.01343"
+ y="136.28738"
+ style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Bitstream Vera Sans"
+ id="tspan5365">Timers</tspan></text>
+ </g>
+</svg>
diff --git a/third_party/ptpd-1.1.0/doc/ptpd_2005_1588_conference_paper.pdf b/third_party/ptpd-1.1.0/doc/ptpd_2005_1588_conference_paper.pdf Binary files differnew file mode 100644 index 0000000..3d4f80d --- /dev/null +++ b/third_party/ptpd-1.1.0/doc/ptpd_2005_1588_conference_paper.pdf diff --git a/third_party/ptpd-1.1.0/doc/stylesheet.css b/third_party/ptpd-1.1.0/doc/stylesheet.css new file mode 100644 index 0000000..3f86770 --- /dev/null +++ b/third_party/ptpd-1.1.0/doc/stylesheet.css @@ -0,0 +1,74 @@ +body {
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-right: 0px;
+ margin-bottom: 0px;
+ background-color: #ffffff;
+ color: #000000;
+}
+
+a:link {
+ text-decoration: none;
+}
+a:visited {
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+a:active {
+ text-decoration: none;
+}
+
+.vline {
+ background-color: #000000;
+ width: 1px;
+}
+
+.info_table {
+ background-color: #fafae0;
+}
+
+.info_text {
+ font-family: sans-serif;
+ font-size: small;
+ color: #555555;
+ margin: 0px;
+}
+
+.title_text {
+ font-family: sans-serif;
+ font-size: 60px;
+}
+
+.subtitle_text {
+ font-family: sans-serif;
+ font-size: 20px;
+}
+
+.sidebar_table {
+ background-color: #ffffff;
+ margin: 20px;
+}
+
+.sidebar_heading {
+ font-family: sans-serif;
+ color: #000000;
+ font-weight: bold;
+ margin: 3px;
+ white-space: nowrap
+}
+
+.sidebar_link {
+ font-family: sans-serif;
+ color: #000000;
+ margin: 3px;
+ margin-left: 6px;
+ white-space: nowrap
+}
+
+.content_table {
+ background-color: #ffffff;
+ margin: 40px;
+}
+
diff --git a/third_party/ptpd-1.1.0/src/Doxyfile b/third_party/ptpd-1.1.0/src/Doxyfile new file mode 100644 index 0000000..6a2d4c4 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/Doxyfile @@ -0,0 +1,1511 @@ +# Doxyfile 1.5.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = PTPD
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = Doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene,
+# Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature. Other possible values
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW = NONE
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Options related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = YES
+
diff --git a/third_party/ptpd-1.1.0/src/Makefile b/third_party/ptpd-1.1.0/src/Makefile new file mode 100644 index 0000000..589981b --- /dev/null +++ b/third_party/ptpd-1.1.0/src/Makefile @@ -0,0 +1,35 @@ +# Makefile for ptpd
+
+RM = rm -f
+CFLAGS+= -Wall #-DBSD_INTERFACE_FUNCTIONS
+#CPPFLAGS = -DPTPD_DBG -DPTPD_NO_DAEMON
+
+PROG = ptpd
+SRCS = ptpd.c arith.c bmc.c probe.c protocol.c \
+ dep/msg.c dep/net.c dep/servo.c dep/startup.c dep/sys.c dep/timer.c
+OBJS = $(SRCS:.c=.o)
+
+HDRS = ptpd.h constants.h datatypes.h \
+ dep/ptpd_dep.h dep/constants_dep.h dep/datatypes_dep.h
+
+CSCOPE = cscope
+GTAGS = gtags
+DOXYGEN = doxygen
+
+TAGFILES = GPATH GRTAGS GSYMS GTAGS cscope.in.out cscope.out cscope.po.out
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS)
+
+tags:
+ $(CSCOPE) -R -q -b
+ $(GTAGS)
+ $(DOXYGEN) Doxyfile
+
+clean:
+ $(RM) $(PROG) $(OBJS) $(TAGFILES) make.out
diff --git a/third_party/ptpd-1.1.0/src/arith.c b/third_party/ptpd-1.1.0/src/arith.c new file mode 100644 index 0000000..a258a9e --- /dev/null +++ b/third_party/ptpd-1.1.0/src/arith.c @@ -0,0 +1,113 @@ +/**
+ * @file arith.c
+ * @date Tue Jul 20 16:12:51 2010
+ *
+ * @brief Time format conversion routines and additional math functions.
+ *
+ *
+ */
+
+#include "ptpd.h"
+
+/* from annex C of the spec */
+UInteger32
+crc_algorithm(Octet * buf, Integer16 length)
+{
+ Integer16 i;
+ UInteger8 data;
+ UInteger32 polynomial = 0xedb88320, crc = 0xffffffff;
+
+ while (length-- > 0) {
+ data = *(UInteger8 *) (buf++);
+
+ for (i = 0; i < 8; i++) {
+ if ((crc ^ data) & 1) {
+ crc = (crc >> 1);
+ crc ^= polynomial;
+ } else {
+ crc = (crc >> 1);
+ }
+ data >>= 1;
+ }
+ }
+
+ return crc ^ 0xffffffff;
+}
+
+UInteger32
+sum(Octet * buf, Integer16 length)
+{
+ UInteger32 sum = 0;
+
+ while (length-- > 0)
+ sum += *(UInteger8 *) (buf++);
+
+ return sum;
+}
+
+void
+fromInternalTime(TimeInternal * internal, TimeRepresentation * external, Boolean halfEpoch)
+{
+ external->seconds = labs(internal->seconds) + halfEpoch * INT_MAX;
+
+ if (internal->seconds < 0 || internal->nanoseconds < 0) {
+ external->nanoseconds = labs(internal->nanoseconds) | ~INT_MAX;
+ } else {
+ external->nanoseconds = labs(internal->nanoseconds);
+ }
+
+ DBGV("fromInternalTime: %10ds %11dns -> %10us %11dns\n",
+ internal->seconds, internal->nanoseconds,
+ external->seconds, external->nanoseconds);
+}
+
+void
+toInternalTime(TimeInternal * internal, TimeRepresentation * external, Boolean * halfEpoch)
+{
+ *halfEpoch = external->seconds / INT_MAX;
+
+ if (external->nanoseconds & ~INT_MAX) {
+ internal->seconds = -(external->seconds % INT_MAX);
+ internal->nanoseconds = -(external->nanoseconds & INT_MAX);
+ } else {
+ internal->seconds = external->seconds % INT_MAX;
+ internal->nanoseconds = external->nanoseconds;
+ }
+
+ DBGV("toInternalTime: %10ds %11dns <- %10us %11dns\n",
+ internal->seconds, internal->nanoseconds,
+ external->seconds, external->nanoseconds);
+}
+
+void
+normalizeTime(TimeInternal * r)
+{
+ r->seconds += r->nanoseconds / 1000000000;
+ r->nanoseconds -= r->nanoseconds / 1000000000 * 1000000000;
+
+ if (r->seconds > 0 && r->nanoseconds < 0) {
+ r->seconds -= 1;
+ r->nanoseconds += 1000000000;
+ } else if (r->seconds < 0 && r->nanoseconds > 0) {
+ r->seconds += 1;
+ r->nanoseconds -= 1000000000;
+ }
+}
+
+void
+addTime(TimeInternal * r, TimeInternal * x, TimeInternal * y)
+{
+ r->seconds = x->seconds + y->seconds;
+ r->nanoseconds = x->nanoseconds + y->nanoseconds;
+
+ normalizeTime(r);
+}
+
+void
+subTime(TimeInternal * r, TimeInternal * x, TimeInternal * y)
+{
+ r->seconds = x->seconds - y->seconds;
+ r->nanoseconds = x->nanoseconds - y->nanoseconds;
+
+ normalizeTime(r);
+}
diff --git a/third_party/ptpd-1.1.0/src/bmc.c b/third_party/ptpd-1.1.0/src/bmc.c new file mode 100644 index 0000000..0b3ce74 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/bmc.c @@ -0,0 +1,330 @@ +/**
+ * @file bmc.c
+ * @date Wed Jun 23 09:36:09 2010
+ *
+ * @brief Best master clock selection code.
+ *
+ * The functions in this file are used by the daemon to select the
+ * best master clock from any number of possibilities.
+ */
+
+#include "ptpd.h"
+
+void
+initData(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ DBG("initData\n");
+
+ if (rtOpts->slaveOnly)
+ rtOpts->clockStratum = 255;
+
+ /* Port configuration data set */
+ ptpClock->last_sync_event_sequence_number = 0;
+ ptpClock->last_general_event_sequence_number = 0;
+ ptpClock->port_id_field = 1;
+ ptpClock->burst_enabled = BURST_ENABLED;
+
+ /* Default data set */
+ ptpClock->clock_communication_technology = ptpClock->port_communication_technology;
+ memcpy(ptpClock->clock_uuid_field, ptpClock->port_uuid_field, PTP_UUID_LENGTH);
+ ptpClock->clock_port_id_field = 0;
+ ptpClock->clock_stratum = rtOpts->clockStratum;
+ memcpy(ptpClock->clock_identifier, rtOpts->clockIdentifier, PTP_CODE_STRING_LENGTH);
+ ptpClock->sync_interval = rtOpts->syncInterval;
+
+ ptpClock->clock_variance = rtOpts->clockVariance; /* see spec 7.7 */
+ ptpClock->clock_followup_capable = CLOCK_FOLLOWUP;
+ ptpClock->preferred = rtOpts->clockPreferred;
+ ptpClock->initializable = INITIALIZABLE;
+ ptpClock->external_timing = EXTERNAL_TIMING;
+ ptpClock->is_boundary_clock = BOUNDARY_CLOCK;
+ memcpy(ptpClock->subdomain_name, rtOpts->subdomainName, PTP_SUBDOMAIN_NAME_LENGTH);
+ ptpClock->number_ports = NUMBER_PORTS;
+ ptpClock->number_foreign_records = 0;
+ ptpClock->max_foreign_records = rtOpts->max_foreign_records;
+
+ /* Global time properties data set */
+ ptpClock->current_utc_offset = rtOpts->currentUtcOffset;
+ ptpClock->epoch_number = rtOpts->epochNumber;
+
+ /* other stuff */
+ ptpClock->random_seed = ptpClock->port_uuid_field[PTP_UUID_LENGTH - 1];
+}
+
+/* see spec table 18 */
+void
+m1(PtpClock * ptpClock)
+{
+ /* Default data set */
+ ptpClock->steps_removed = 0;
+ ptpClock->offset_from_master.seconds = 0;
+ ptpClock->offset_from_master.nanoseconds = 0;
+ ptpClock->one_way_delay.seconds = 0;
+ ptpClock->one_way_delay.nanoseconds = 0;
+
+ /* Parent data set */
+ ptpClock->parent_communication_technology = ptpClock->clock_communication_technology;
+ memcpy(ptpClock->parent_uuid, ptpClock->clock_uuid_field, PTP_UUID_LENGTH);
+ ptpClock->parent_port_id = ptpClock->clock_port_id_field;
+ ptpClock->parent_last_sync_sequence_number = 0;
+ ptpClock->parent_followup_capable = ptpClock->clock_followup_capable;
+ ptpClock->parent_external_timing = ptpClock->external_timing;
+ ptpClock->parent_variance = ptpClock->clock_variance;
+ ptpClock->grandmaster_communication_technology = ptpClock->clock_communication_technology;
+ memcpy(ptpClock->grandmaster_uuid_field, ptpClock->clock_uuid_field, PTP_UUID_LENGTH);
+ ptpClock->grandmaster_port_id_field = ptpClock->clock_port_id_field;
+ ptpClock->grandmaster_stratum = ptpClock->clock_stratum;
+ memcpy(ptpClock->grandmaster_identifier, ptpClock->clock_identifier, PTP_CODE_STRING_LENGTH);
+ ptpClock->grandmaster_variance = ptpClock->clock_variance;
+ ptpClock->grandmaster_preferred = ptpClock->preferred;
+ ptpClock->grandmaster_is_boundary_clock = ptpClock->is_boundary_clock;
+ ptpClock->grandmaster_sequence_number = ptpClock->last_sync_event_sequence_number;
+}
+
+/* see spec table 21 */
+void
+s1(MsgHeader * header, MsgSync * sync, PtpClock * ptpClock)
+{
+ /* Current data set */
+ ptpClock->steps_removed = sync->localStepsRemoved + 1;
+
+ /* Parent data set */
+ ptpClock->parent_communication_technology = header->sourceCommunicationTechnology;
+ memcpy(ptpClock->parent_uuid, header->sourceUuid, PTP_UUID_LENGTH);
+ ptpClock->parent_port_id = header->sourcePortId;
+ ptpClock->parent_last_sync_sequence_number = header->sequenceId;
+ ptpClock->parent_followup_capable = getFlag(header->flags, PTP_ASSIST);
+ ptpClock->parent_external_timing = getFlag(header->flags, PTP_EXT_SYNC);
+ ptpClock->parent_variance = sync->localClockVariance;
+ ptpClock->grandmaster_communication_technology = sync->grandmasterCommunicationTechnology;
+ memcpy(ptpClock->grandmaster_uuid_field, sync->grandmasterClockUuid, PTP_UUID_LENGTH);
+ ptpClock->grandmaster_port_id_field = sync->grandmasterPortId;
+ ptpClock->grandmaster_stratum = sync->grandmasterClockStratum;
+ memcpy(ptpClock->grandmaster_identifier, sync->grandmasterClockIdentifier, PTP_CODE_STRING_LENGTH);
+ ptpClock->grandmaster_variance = sync->grandmasterClockVariance;
+ ptpClock->grandmaster_preferred = sync->grandmasterPreferred;
+ ptpClock->grandmaster_is_boundary_clock = sync->grandmasterIsBoundaryClock;
+ ptpClock->grandmaster_sequence_number = sync->grandmasterSequenceId;
+
+ /* Global time properties data set */
+ ptpClock->current_utc_offset = sync->currentUTCOffset;
+ ptpClock->leap_59 = getFlag(header->flags, PTP_LI_59);
+ ptpClock->leap_61 = getFlag(header->flags, PTP_LI_61);
+ ptpClock->epoch_number = sync->epochNumber;
+}
+
+void
+copyD0(MsgHeader * header, MsgSync * sync, PtpClock * ptpClock)
+{
+ sync->grandmasterCommunicationTechnology = ptpClock->clock_communication_technology;
+ memcpy(sync->grandmasterClockUuid, ptpClock->port_uuid_field, PTP_UUID_LENGTH);
+ sync->grandmasterPortId = ptpClock->port_id_field;
+ sync->grandmasterClockStratum = ptpClock->clock_stratum;
+ memcpy(sync->grandmasterClockIdentifier, ptpClock->clock_identifier, PTP_CODE_STRING_LENGTH);
+ sync->grandmasterClockVariance = ptpClock->clock_variance;
+ sync->grandmasterIsBoundaryClock = ptpClock->is_boundary_clock;
+ sync->grandmasterPreferred = ptpClock->preferred;
+ sync->localStepsRemoved = ptpClock->steps_removed;
+ header->sourceCommunicationTechnology = ptpClock->clock_communication_technology;
+ memcpy(header->sourceUuid, ptpClock->port_uuid_field, PTP_UUID_LENGTH);
+ header->sourcePortId = ptpClock->port_id_field;
+ sync->grandmasterSequenceId = ptpClock->grandmaster_sequence_number;
+ header->sequenceId = ptpClock->grandmaster_sequence_number;
+}
+
+int
+getIdentifierOrder(Octet identifier[PTP_CODE_STRING_LENGTH])
+{
+ if (!memcmp(identifier, IDENTIFIER_ATOM, PTP_CODE_STRING_LENGTH))
+ return 1;
+ else if (!memcmp(identifier, IDENTIFIER_GPS, PTP_CODE_STRING_LENGTH))
+ return 1;
+ else if (!memcmp(identifier, IDENTIFIER_NTP, PTP_CODE_STRING_LENGTH))
+ return 2;
+ else if (!memcmp(identifier, IDENTIFIER_HAND, PTP_CODE_STRING_LENGTH))
+ return 3;
+ else if (!memcmp(identifier, IDENTIFIER_INIT, PTP_CODE_STRING_LENGTH))
+ return 4;
+ else if (!memcmp(identifier, IDENTIFIER_DFLT, PTP_CODE_STRING_LENGTH))
+ return 5;
+
+ return 6;
+}
+
+/* return similar to memcmp()s
+ note: communicationTechnology can be ignored because
+ if they differed they would not have made it here */
+Integer8
+bmcDataSetComparison(MsgHeader * headerA, MsgSync * syncA,
+ MsgHeader * headerB, MsgSync * syncB, PtpClock * ptpClock)
+{
+ DBGV("bmcDataSetComparison: start\n");
+ if (!(syncA->grandmasterPortId == syncB->grandmasterPortId
+ && !memcmp(syncA->grandmasterClockUuid, syncB->grandmasterClockUuid, PTP_UUID_LENGTH))) {
+ if (syncA->grandmasterClockStratum < syncB->grandmasterClockStratum)
+ goto A;
+ else if (syncA->grandmasterClockStratum > syncB->grandmasterClockStratum)
+ goto B;
+
+ /* grandmasterClockStratums same */
+ if (getIdentifierOrder(syncA->grandmasterClockIdentifier) < getIdentifierOrder(syncB->grandmasterClockIdentifier))
+ goto A;
+ if (getIdentifierOrder(syncA->grandmasterClockIdentifier) > getIdentifierOrder(syncB->grandmasterClockIdentifier))
+ goto B;
+
+ /* grandmasterClockIdentifiers same */
+ if (syncA->grandmasterClockStratum > 2) {
+ if (syncA->grandmasterClockVariance > syncB->grandmasterClockVariance + PTP_LOG_VARIANCE_THRESHOLD
+ || syncA->grandmasterClockVariance < syncB->grandmasterClockVariance - PTP_LOG_VARIANCE_THRESHOLD) {
+ /* grandmasterClockVariances are not similar */
+ if (syncA->grandmasterClockVariance < syncB->grandmasterClockVariance)
+ goto A;
+ else
+ goto B;
+ }
+ /* grandmasterClockVariances are similar */
+ if (!syncA->grandmasterIsBoundaryClock != !syncB->grandmasterIsBoundaryClock) { /* XOR */
+ if (syncA->grandmasterIsBoundaryClock)
+ goto A;
+ else
+ goto B;
+ }
+ /* neither is grandmasterIsBoundaryClock */
+ if (memcmp(syncA->grandmasterClockUuid, syncB->grandmasterClockUuid, PTP_UUID_LENGTH) < 0)
+ goto A;
+ else
+ goto B;
+ }
+ /* syncA->grandmasterClockStratum <= 2 */
+ if (!syncA->grandmasterPreferred != !syncB->grandmasterPreferred) { /* XOR */
+ if (syncA->grandmasterPreferred)
+ return 1; /* A1 */
+ else
+ return -1; /* B1 */
+ }
+ /* neither or both grandmasterPreferred */
+ }
+ DBGV("bmcDataSetComparison: X\n");
+ if (syncA->localStepsRemoved > syncB->localStepsRemoved + 1
+ || syncA->localStepsRemoved < syncB->localStepsRemoved - 1) {
+ /* localStepsRemoved not within 1 */
+ if (syncA->localStepsRemoved < syncB->localStepsRemoved)
+ return 1; /* A1 */
+ else
+ return -1; /* B1 */
+ }
+ /* localStepsRemoved within 1 */
+ if (syncA->localStepsRemoved < syncB->localStepsRemoved) {
+ DBGV("bmcDataSetComparison: A3\n");
+ if (memcmp(ptpClock->port_uuid_field, headerB->sourceUuid, PTP_UUID_LENGTH) < 0)
+ return 1; /* A1 */
+ else if (memcmp(ptpClock->port_uuid_field, headerB->sourceUuid, PTP_UUID_LENGTH) > 0)
+ return 2; /* A2 */
+
+ /* this port_uuid_field same as headerB->sourceUuid */
+ if (ptpClock->port_id_field < headerB->sourcePortId)
+ return 1; /* A1 */
+ else if (ptpClock->port_id_field > headerB->sourcePortId)
+ return 2; /* A2 */
+
+ /* this port_id_field same as headerB->sourcePortId */
+ return 0; /* same */
+ }
+ if (syncA->localStepsRemoved > syncB->localStepsRemoved) {
+ DBGV("bmcDataSetComparison: B3\n");
+ if (memcmp(ptpClock->port_uuid_field, headerA->sourceUuid, PTP_UUID_LENGTH) < 0)
+ return -1; /* B1 */
+ else if (memcmp(ptpClock->port_uuid_field, headerB->sourceUuid, PTP_UUID_LENGTH) > 0)
+ return -2; /* B2 */
+
+ /* this port_uuid_field same as headerA->sourceUuid */
+ if (ptpClock->port_id_field < headerA->sourcePortId)
+ return -1; /* B1 */
+ else if (ptpClock->port_id_field > headerA->sourcePortId)
+ return -2; /* B2 */
+
+ /* this port_id_field same as headerA->sourcePortId */
+ return 0; /* same */
+ }
+ /* localStepsRemoved same */
+ if (memcmp(headerA->sourceUuid, headerB->sourceUuid, PTP_UUID_LENGTH) < 0)
+ return 2; /* A2 */
+ else if (memcmp(headerA->sourceUuid, headerB->sourceUuid, PTP_UUID_LENGTH) > 0)
+ return -2; /* B2 */
+
+ /* sourceUuid same */
+ DBGV("bmcDataSetComparison: Z\n");
+ if (syncA->grandmasterSequenceId > syncB->grandmasterSequenceId)
+ return 3;
+ else if (syncA->grandmasterSequenceId < syncB->grandmasterSequenceId)
+ return -3;
+
+ /* grandmasterSequenceId same */
+ if (headerA->sequenceId > headerB->sequenceId)
+ return 3;
+ else if (headerA->sequenceId < headerB->sequenceId)
+ return -3;
+
+ /* sequenceId same */
+ return 0; /* same */
+
+ /* oh no, a goto label! the horror! */
+A:
+ if (!syncA->grandmasterPreferred && syncB->grandmasterPreferred)
+ return -1; /* B1 */
+ else
+ return 1; /* A1 */
+B:
+ if (syncA->grandmasterPreferred && !syncB->grandmasterPreferred)
+ return 1; /* A1 */
+ else
+ return -1; /* B1 */
+}
+
+UInteger8
+bmcStateDecision(MsgHeader * header, MsgSync * sync, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ if (rtOpts->slaveOnly) {
+ s1(header, sync, ptpClock);
+ return PTP_SLAVE;
+ }
+ copyD0(&ptpClock->msgTmpHeader, &ptpClock->msgTmp.sync, ptpClock);
+
+ if (ptpClock->msgTmp.sync.grandmasterClockStratum < 3) {
+ if (bmcDataSetComparison(&ptpClock->msgTmpHeader, &ptpClock->msgTmp.sync, header, sync, ptpClock) > 0) {
+ m1(ptpClock);
+ return PTP_MASTER;
+ }
+ s1(header, sync, ptpClock);
+ return PTP_PASSIVE;
+ } else if (bmcDataSetComparison(&ptpClock->msgTmpHeader, &ptpClock->msgTmp.sync, header, sync, ptpClock) > 0
+ && ptpClock->msgTmp.sync.grandmasterClockStratum != 255) {
+ m1(ptpClock);
+ return PTP_MASTER;
+ } else {
+ s1(header, sync, ptpClock);
+ return PTP_SLAVE;
+ }
+}
+
+UInteger8
+bmc(ForeignMasterRecord * foreign, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ Integer16 i, best;
+
+ if (!ptpClock->number_foreign_records) {
+ if (ptpClock->port_state == PTP_MASTER)
+ m1(ptpClock);
+ return ptpClock->port_state; /* no change */
+ }
+ for (i = 1, best = 0; i < ptpClock->number_foreign_records; ++i) {
+ if (bmcDataSetComparison(&foreign[i].header, &foreign[i].sync,
+ &foreign[best].header, &foreign[best].sync, ptpClock) > 0)
+ best = i;
+ }
+
+ DBGV("bmc: best record %d\n", best);
+ ptpClock->foreign_record_best = best;
+
+ return bmcStateDecision(&foreign[best].header, &foreign[best].sync, rtOpts, ptpClock);
+}
diff --git a/third_party/ptpd-1.1.0/src/constants.h b/third_party/ptpd-1.1.0/src/constants.h new file mode 100644 index 0000000..503aee8 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/constants.h @@ -0,0 +1,120 @@ +/**
+ * @file constants.h
+ * @date Wed Jun 23 10:02:39 2010
+ *
+ * @brief All of the defined constants for the daemon.
+ *
+ *
+ */
+
+#ifndef CONSTANTS_H
+#define CONSTANTS_H
+
+/* implementation specific constants */
+#define MANUFACTURER_ID \
+ "PTPD;1.2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+
+#define DEFAULT_SYNC_INTERVAL 1
+#define DEFAULT_UTC_OFFSET 0
+#define DEFAULT_CLOCK_VARIANCE (-4000)
+#define DEFAULT_CLOCK_STRATUM 4
+#define DEFAULT_INBOUND_LATENCY 0 /* in nsec */
+#define DEFAULT_OUTBOUND_LATENCY 0 /* in nsec */
+#define DEFAULT_NO_RESET_CLOCK FALSE
+#define DEFAULT_AP 10
+#define DEFAULT_AI 1000
+#define DEFAULT_DELAY_S 6
+#define DEFAULT_MAX_FOREIGN_RECORDS 5
+
+/* features, only change to refelect changes in implementation */
+#define CLOCK_FOLLOWUP TRUE
+#define INITIALIZABLE TRUE
+#define BURST_ENABLED FALSE
+#define EXTERNAL_TIMING FALSE
+#define BOUNDARY_CLOCK FALSE
+#define NUMBER_PORTS 1
+#define VERSION_PTP 1
+#define VERSION_NETWORK 1
+
+/* spec defined constants */
+#define DEFAULT_PTP_DOMAIN_NAME "_DFLT\0\0\0\0\0\0\0\0\0\0\0"
+#define ALTERNATE_PTP_DOMAIN1_NAME "_ALT1\0\0\0\0\0\0\0\0\0\0\0"
+#define ALTERNATE_PTP_DOMAIN2_NAME "_ALT2\0\0\0\0\0\0\0\0\0\0\0"
+#define ALTERNATE_PTP_DOMAIN3_NAME "_ALT3\0\0\0\0\0\0\0\0\0\0\0"
+
+#define IDENTIFIER_ATOM "ATOM"
+#define IDENTIFIER_GPS "GPS\0"
+#define IDENTIFIER_NTP "NTP\0"
+#define IDENTIFIER_HAND "HAND"
+#define IDENTIFIER_INIT "INIT"
+#define IDENTIFIER_DFLT "DFLT"
+
+/* ptp constants */
+#define PTP_UUID_LENGTH 6
+#define PTP_CODE_STRING_LENGTH 4
+#define PTP_SUBDOMAIN_NAME_LENGTH 16
+#define PTP_MAX_MANAGEMENT_PAYLOAD_SIZE 90
+/* no support for intervals less than one */
+#define PTP_SYNC_INTERVAL_TIMEOUT(x) (1<<((x)<0?1:(x)))
+#define PTP_SYNC_RECEIPT_TIMEOUT(x) (10*(1<<((x)<0?0:(x))))
+#define PTP_DELAY_REQ_INTERVAL 30
+#define PTP_FOREIGN_MASTER_THRESHOLD 2
+#define PTP_FOREIGN_MASTER_TIME_WINDOW(x) (4*(1<<((x)<0?0:(x))))
+#define PTP_RANDOMIZING_SLOTS 18
+#define PTP_LOG_VARIANCE_THRESHOLD 256
+#define PTP_LOG_VARIANCE_HYSTERESIS 128
+/* used in spec but not named */
+#define MANUFACTURER_ID_LENGTH 48
+
+/* ptp data enums */
+enum {
+ PTP_CLOSED = 0, PTP_ETHER, PTP_FFBUS = 4,
+ PTP_PROFIBUS, PTP_LON, PTP_DNET,
+ PTP_SDS, PTP_CONTROLNET, PTP_CANOPEN,
+ PTP_IEEE1394 = 243, PTP_IEEE802_11A, PTP_IEEE_WIRELESS,
+ PTP_INFINIBAND, PTP_BLUETOOTH, PTP_IEEE802_15_1,
+ PTP_IEEE1451_2, PTP_IEEE1451_5, PTP_USB,
+ PTP_ISA, PTP_PCI, PTP_VXI, PTP_DEFAULT
+};
+
+enum {
+ PTP_INITIALIZING = 0, PTP_FAULTY, PTP_DISABLED,
+ PTP_LISTENING, PTP_PRE_MASTER, PTP_MASTER,
+ PTP_PASSIVE, PTP_UNCALIBRATED, PTP_SLAVE
+};
+
+enum {
+ PTP_SYNC_MESSAGE = 0, PTP_DELAY_REQ_MESSAGE, PTP_FOLLOWUP_MESSAGE,
+ PTP_DELAY_RESP_MESSAGE, PTP_MANAGEMENT_MESSAGE,
+ PTP_SYNC_MESSAGE_BURST, PTP_DELAY_REQ_MESSAGE_BURST
+};
+
+enum {
+ PTP_LI_61 = 0, PTP_LI_59, PTP_BOUNDARY_CLOCK,
+ PTP_ASSIST, PTP_EXT_SYNC, PARENT_STATS, PTP_SYNC_BURST
+};
+
+enum {
+ PTP_MM_NULL = 0, PTP_MM_OBTAIN_IDENTITY, PTP_MM_CLOCK_IDENTITY,
+ PTP_MM_INITIALIZE_CLOCK, PTP_MM_SET_SUBDOMAIN,
+ PTP_MM_CLEAR_DESIGNATED_PREFERRED_MASTER,
+ PTP_MM_SET_DESIGNATED_PREFERRED_MASTER,
+ PTP_MM_GET_DEFAULT_DATA_SET, PTP_MM_DEFAULT_DATA_SET,
+ PTP_MM_UPDATE_DEFAULT_DATA_SET, PTP_MM_GET_CURRENT_DATA_SET,
+ PTP_MM_CURRENT_DATA_SET, PTP_MM_GET_PARENT_DATA_SET,
+ PTP_MM_PARENT_DATA_SET, PTP_MM_GET_PORT_DATA_SET,
+ PTP_MM_PORT_DATA_SET, PTP_MM_GET_GLOBAL_TIME_DATA_SET,
+ PTP_MM_GLOBAL_TIME_DATA_SET, PTP_MM_UPDATE_GLOBAL_TIME_PROPERTIES,
+ PTP_MM_GOTO_FAULTY_STATE, PTP_MM_GET_FOREIGN_DATA_SET,
+ PTP_MM_FOREIGN_DATA_SET, PTP_MM_SET_SYNC_INTERVAL,
+ PTP_MM_DISABLE_PORT, PTP_MM_ENABLE_PORT,
+ PTP_MM_DISABLE_BURST, PTP_MM_ENABLE_BURST, PTP_MM_SET_TIME
+};
+
+/* enum used by this implementation */
+enum {
+ SYNC_RECEIPT_TIMER = 0, SYNC_INTERVAL_TIMER, QUALIFICATION_TIMER,
+ TIMER_ARRAY_SIZE /* these two are non-spec */
+};
+
+#endif
diff --git a/third_party/ptpd-1.1.0/src/datatypes.h b/third_party/ptpd-1.1.0/src/datatypes.h new file mode 100644 index 0000000..1f0e21e --- /dev/null +++ b/third_party/ptpd-1.1.0/src/datatypes.h @@ -0,0 +1,362 @@ +/**
+ * @file datatypes.h
+ * @date Wed Jun 23 09:37:14 2010
+ *
+ * @brief All of the datatypes used by the daemon.
+ *
+ *
+ */
+
+
+#ifndef DATATYPES_H
+#define DATATYPES_H
+
+#include <stdio.h>
+
+typedef struct {
+ UInteger32 seconds;
+ Integer32 nanoseconds;
+} TimeRepresentation;
+
+typedef struct {
+ Integer32 seconds;
+ Integer32 nanoseconds;
+} TimeInternal;
+
+typedef struct {
+ Integer32 interval;
+ Integer32 left;
+ Boolean expire;
+} IntervalTimer;
+
+/* Message header */
+typedef struct {
+ UInteger16 versionPTP;
+ UInteger16 versionNetwork;
+ Octet subdomain[PTP_SUBDOMAIN_NAME_LENGTH];
+ UInteger8 messageType;
+ UInteger8 sourceCommunicationTechnology;
+ Octet sourceUuid[PTP_UUID_LENGTH];
+ UInteger16 sourcePortId;
+ UInteger16 sequenceId;
+ UInteger8 control;
+ Octet flags[2];
+
+} MsgHeader;
+
+/* Sync or Delay_Req message */
+typedef struct {
+ TimeRepresentation originTimestamp;
+ UInteger16 epochNumber;
+ Integer16 currentUTCOffset;
+ UInteger8 grandmasterCommunicationTechnology;
+ Octet grandmasterClockUuid[PTP_UUID_LENGTH];
+ UInteger16 grandmasterPortId;
+ UInteger16 grandmasterSequenceId;
+ UInteger8 grandmasterClockStratum;
+ Octet grandmasterClockIdentifier[PTP_CODE_STRING_LENGTH];
+ Integer16 grandmasterClockVariance;
+ Boolean grandmasterPreferred;
+ Boolean grandmasterIsBoundaryClock;
+ Integer8 syncInterval;
+ Integer16 localClockVariance;
+ UInteger16 localStepsRemoved;
+ UInteger8 localClockStratum;
+ Octet localClockIdentifer[PTP_CODE_STRING_LENGTH];
+ UInteger8 parentCommunicationTechnology;
+ Octet parentUuid[PTP_UUID_LENGTH];
+ UInteger16 parentPortField;
+ Integer16 estimatedMasterVariance;
+ Integer32 estimatedMasterDrift;
+ Boolean utcReasonable;
+
+} MsgSync;
+
+typedef MsgSync MsgDelayReq;
+
+/* Follow_Up message */
+typedef struct {
+ UInteger16 associatedSequenceId;
+ TimeRepresentation preciseOriginTimestamp;
+
+} MsgFollowUp;
+
+/* Delay_Resp message */
+typedef struct {
+ TimeRepresentation delayReceiptTimestamp;
+ UInteger8 requestingSourceCommunicationTechnology;
+ Octet requestingSourceUuid[PTP_UUID_LENGTH];
+ UInteger16 requestingSourcePortId;
+ UInteger16 requestingSourceSequenceId;
+
+} MsgDelayResp;
+
+/* Management message */
+typedef union {
+ struct ClockIdentity {
+ UInteger8 clockCommunicationTechnology;
+ Octet clockUuidField[PTP_UUID_LENGTH];
+ UInteger16 clockPortField;
+ Octet manufacturerIdentity[MANUFACTURER_ID_LENGTH];
+ } clockIdentity;
+
+ struct DefaultData {
+ UInteger8 clockCommunicationTechnology;
+ Octet clockUuidField[PTP_UUID_LENGTH];
+ UInteger16 clockPortField;
+ UInteger8 clockStratum;
+ Octet clockIdentifier[PTP_CODE_STRING_LENGTH];
+ Integer16 clockVariance;
+ Boolean clockFollowupCapable;
+ Boolean preferred;
+ Boolean initializable;
+ Boolean externalTiming;
+ Boolean isBoundaryClock;
+ Integer8 syncInterval;
+ Octet subdomainName[PTP_SUBDOMAIN_NAME_LENGTH];
+ UInteger16 numberPorts;
+ UInteger16 numberForeignRecords;
+ } defaultData;
+
+ struct Current {
+ UInteger16 stepsRemoved;
+ TimeRepresentation offsetFromMaster;
+ TimeRepresentation oneWayDelay;
+ } current;
+
+ struct Parent {
+ UInteger8 parentCommunicationTechnology;
+ Octet parentUuid[PTP_UUID_LENGTH];
+ UInteger16 parentPortId;
+ UInteger16 parentLastSyncSequenceNumber;
+ Boolean parentFollowupCapable;
+ Boolean parentExternalTiming;
+ Integer16 parentVariance;
+ Boolean parentStats;
+ Integer16 observedVariance;
+ Integer32 observedDrift;
+ Boolean utcReasonable;
+ UInteger8 grandmasterCommunicationTechnology;
+ Octet grandmasterUuidField[PTP_UUID_LENGTH];
+ UInteger16 grandmasterPortIdField;
+ UInteger8 grandmasterStratum;
+ Octet grandmasterIdentifier[PTP_CODE_STRING_LENGTH];
+ Integer16 grandmasterVariance;
+ Boolean grandmasterPreferred;
+ Boolean grandmasterIsBoundaryClock;
+ UInteger16 grandmasterSequenceNumber;
+ } parent;
+
+ struct Port {
+ UInteger16 returnedPortNumber;
+ UInteger8 portState;
+ UInteger16 lastSyncEventSequenceNumber;
+ UInteger16 lastGeneralEventSequenceNumber;
+ UInteger8 portCommunicationTechnology;
+ Octet portUuidField[PTP_UUID_LENGTH];
+ UInteger16 portIdField;
+ Boolean burstEnabled;
+ UInteger8 subdomainAddressOctets;
+ UInteger8 eventPortAddressOctets;
+ UInteger8 generalPortAddressOctets;
+ Octet subdomainAddress[SUBDOMAIN_ADDRESS_LENGTH];
+ Octet eventPortAddress[PORT_ADDRESS_LENGTH];
+ Octet generalPortAddress[PORT_ADDRESS_LENGTH];
+ } port;
+
+ struct GlobalTime {
+ TimeRepresentation localTime;
+ Integer16 currentUtcOffset;
+ Boolean leap59;
+ Boolean leap61;
+ UInteger16 epochNumber;
+ } globalTime;
+
+ struct Foreign {
+ UInteger16 returnedPortNumber;
+ UInteger16 returnedRecordNumber;
+ UInteger8 foreignMasterCommunicationTechnology;
+ Octet foreignMasterUuid[PTP_UUID_LENGTH];
+ UInteger16 foreignMasterPortId;
+ UInteger16 foreignMasterSyncs;
+ } foreign;
+
+} MsgManagementPayload;
+
+typedef struct {
+ UInteger8 targetCommunicationTechnology;
+ Octet targetUuid[PTP_UUID_LENGTH];
+ UInteger16 targetPortId;
+ Integer16 startingBoundaryHops;
+ Integer16 boundaryHops;
+ UInteger8 managementMessageKey;
+ UInteger16 parameterLength;
+ UInteger16 recordKey;
+
+ MsgManagementPayload payload;
+} MsgManagement;
+
+typedef struct {
+ UInteger8 foreign_master_communication_technology;
+ Octet foreign_master_uuid[PTP_UUID_LENGTH];
+ UInteger16 foreign_master_port_id;
+ UInteger16 foreign_master_syncs;
+
+ MsgHeader header;
+ MsgSync sync;
+} ForeignMasterRecord;
+
+/* main program data structure */
+typedef struct {
+ /* Default data set */
+ UInteger8 clock_communication_technology;
+ Octet clock_uuid_field[PTP_UUID_LENGTH];
+ UInteger16 clock_port_id_field;
+ UInteger8 clock_stratum;
+ Octet clock_identifier[PTP_CODE_STRING_LENGTH];
+ Integer16 clock_variance;
+ Boolean clock_followup_capable;
+ Boolean preferred;
+ Boolean initializable;
+ Boolean external_timing;
+ Boolean is_boundary_clock;
+ Integer8 sync_interval;
+ Octet subdomain_name[PTP_SUBDOMAIN_NAME_LENGTH];
+ UInteger16 number_ports;
+ UInteger16 number_foreign_records;
+
+ /* Current data set */
+ UInteger16 steps_removed;
+ TimeInternal offset_from_master;
+ TimeInternal one_way_delay;
+
+ /* Parent data set */
+ UInteger8 parent_communication_technology;
+ Octet parent_uuid[PTP_UUID_LENGTH];
+ UInteger16 parent_port_id;
+ UInteger16 parent_last_sync_sequence_number;
+ Boolean parent_followup_capable;
+ Boolean parent_external_timing;
+ Integer16 parent_variance;
+ Boolean parent_stats;
+ Integer16 observed_variance;
+ Integer32 observed_drift;
+ Boolean utc_reasonable;
+ UInteger8 grandmaster_communication_technology;
+ Octet grandmaster_uuid_field[PTP_UUID_LENGTH];
+ UInteger16 grandmaster_port_id_field;
+ UInteger8 grandmaster_stratum;
+ Octet grandmaster_identifier[PTP_CODE_STRING_LENGTH];
+ Integer16 grandmaster_variance;
+ Boolean grandmaster_preferred;
+ Boolean grandmaster_is_boundary_clock;
+ UInteger16 grandmaster_sequence_number;
+
+ /* Global time properties data set */
+ Integer16 current_utc_offset;
+ Boolean leap_59;
+ Boolean leap_61;
+ UInteger16 epoch_number;
+
+ /* Port configuration data set */
+ UInteger8 port_state;
+ UInteger16 last_sync_event_sequence_number;
+ UInteger16 last_general_event_sequence_number;
+ Octet subdomain_address[SUBDOMAIN_ADDRESS_LENGTH];
+ Octet event_port_address[PORT_ADDRESS_LENGTH];
+ Octet general_port_address[PORT_ADDRESS_LENGTH];
+ UInteger8 port_communication_technology;
+ Octet port_uuid_field[PTP_UUID_LENGTH];
+ UInteger16 port_id_field;
+ Boolean burst_enabled;
+
+ /* Foreign master data set */
+ ForeignMasterRecord *foreign;
+
+ /* Other things we need for the protocol */
+ Boolean halfEpoch;
+
+ Integer16 max_foreign_records;
+ Integer16 foreign_record_i;
+ Integer16 foreign_record_best;
+ Boolean record_update;
+ UInteger32 random_seed;
+
+ MsgHeader msgTmpHeader;
+
+ union {
+ MsgSync sync;
+ MsgFollowUp follow;
+ MsgDelayReq req;
+ MsgDelayResp resp;
+ MsgManagement manage;
+ } msgTmp;
+
+ Octet msgObuf[PACKET_SIZE];
+ Octet msgIbuf[PACKET_SIZE];
+
+ TimeInternal master_to_slave_delay;
+ TimeInternal slave_to_master_delay;
+
+ TimeInternal delay_req_receive_time;
+ TimeInternal delay_req_send_time;
+ TimeInternal sync_receive_time;
+
+ UInteger16 Q;
+ UInteger16 R;
+
+ Boolean sentDelayReq;
+ UInteger16 sentDelayReqSequenceId;
+ Boolean waitingForFollow;
+
+ offset_from_master_filter ofm_filt;
+ one_way_delay_filter owd_filt;
+
+ Boolean message_activity;
+
+ IntervalTimer itimer[TIMER_ARRAY_SIZE];
+
+ NetPath netPath;
+
+} PtpClock;
+
+/* program options set at run-time */
+typedef struct {
+ Integer8 syncInterval;
+ Octet subdomainName[PTP_SUBDOMAIN_NAME_LENGTH];
+ Octet clockIdentifier[PTP_CODE_STRING_LENGTH];
+ UInteger32 clockVariance;
+ UInteger8 clockStratum;
+ Boolean clockPreferred;
+ Integer16 currentUtcOffset;
+ UInteger16 epochNumber;
+ Octet ifaceName[IFACE_NAME_LENGTH];
+ Boolean noResetClock;
+ Integer32 maxReset; /* Maximum number of nanoseconds to reset */
+ Integer32 maxDelay; /* Maximum number of nanoseconds of delay */
+ Boolean noAdjust;
+ Boolean displayStats;
+ Boolean csvStats;
+ Octet unicastAddress[NET_ADDRESS_LENGTH];
+ Integer16 ap, ai;
+ Integer16 s;
+ TimeInternal inboundLatency, outboundLatency;
+ Integer16 max_foreign_records;
+ Boolean slaveOnly;
+ Boolean probe;
+ UInteger8 probe_management_key;
+ UInteger16 probe_record_key;
+ Boolean halfEpoch;
+#ifndef NO_FILE_SYSTEM
+ char file[PATH_MAX];
+#endif
+ int logFd;
+ Boolean useSysLog;
+ int ttl;
+#ifndef NO_FILE_SYSTEM
+ char recordFile[PATH_MAX];
+ FILE *recordFP;
+#endif
+} RunTimeOpts;
+
+#endif
diff --git a/third_party/ptpd-1.1.0/src/dep-tiva/constants_dep.h b/third_party/ptpd-1.1.0/src/dep-tiva/constants_dep.h new file mode 100644 index 0000000..952bddd --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep-tiva/constants_dep.h @@ -0,0 +1,87 @@ +/* constants_dep.h */
+
+#ifndef CONSTANTS_DEP_H
+#define CONSTANTS_DEP_H
+
+/* platform dependent */
+
+#ifdef IF_NAMESIZE
+ #define IFACE_NAME_LENGTH IF_NAMESIZE
+#else
+ #define IFACE_NAME_LENGTH 16
+#endif
+
+#ifdef INET_ADDRSTRLEN
+ #define NET_ADDRESS_LENGTH INET_ADDRSTRLEN
+#else
+ #define NET_ADDRESS_LENGTH 16
+#endif
+
+#define IFCONF_LENGTH 10
+
+#define PTPD_LSBF
+
+#define ADJ_MAX 10000000
+
+/* UDP/IPv4 dependent */
+
+#define SUBDOMAIN_ADDRESS_LENGTH 4
+#define PORT_ADDRESS_LENGTH 2
+
+#define PACKET_SIZE 300
+
+#define PTP_EVENT_PORT 319
+#define PTP_GENERAL_PORT 320
+
+#define DEFAULT_PTP_DOMAIN_ADDRESS "224.0.1.129"
+#define ALTERNATE_PTP_DOMAIN1_ADDRESS "224.0.1.130"
+#define ALTERNATE_PTP_DOMAIN2_ADDRESS "224.0.1.131"
+#define ALTERNATE_PTP_DOMAIN3_ADDRESS "224.0.1.132"
+
+#define HEADER_LENGTH 40
+#define SYNC_PACKET_LENGTH 124
+#define DELAY_REQ_PACKET_LENGTH 124
+#define FOLLOW_UP_PACKET_LENGTH 52
+#define DELAY_RESP_PACKET_LENGTH 60
+#define MANAGEMENT_PACKET_LENGTH 136
+
+#define MM_STARTING_BOUNDARY_HOPS 0x7fff
+
+/* others */
+
+#define SCREEN_BUFSZ 128
+#define SCREEN_MAXSZ 80
+
+#define PBUF_QUEUE_SIZE 16
+
+/* override default values */
+#ifdef DEFAULT_AP
+# undef DEFAULT_AP
+# define DEFAULT_AP 2
+#endif
+
+#ifdef DEFAULT_AI
+# undef DEFAULT_AI
+# define DEFAULT_AI 200
+#endif
+
+#define MAX_AP 10
+#define MAX_AI 1000
+
+#ifdef DEFAULT_INBOUND_LATENCY
+# undef DEFAULT_INBOUND_LATENCY
+# define DEFAULT_INBOUND_LATENCY 16500
+#endif
+
+#ifdef DEFAULT_OUTBOUND_LATENCY
+# undef DEFAULT_OUTBOUND_LATENCY
+# define DEFAULT_OUTBOUND_LATENCY 16500
+#endif
+
+#ifdef CLOCK_FOLLOWUP
+# undef CLOCK_FOLLOWUP
+# define CLOCK_FOLLOWUP FALSE
+#endif
+
+#endif /* #ifndef CONSTANTS_DEP_H */
+
diff --git a/third_party/ptpd-1.1.0/src/dep-tiva/datatypes_dep.h b/third_party/ptpd-1.1.0/src/dep-tiva/datatypes_dep.h new file mode 100644 index 0000000..af9f67d --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep-tiva/datatypes_dep.h @@ -0,0 +1,42 @@ +/* datatypes_dep.h */
+
+#ifndef DATATYPES_DEP_H
+#define DATATYPES_DEP_H
+
+typedef enum {FALSE=0, TRUE} Boolean;
+typedef char Octet;
+typedef signed char Integer8;
+typedef signed short Integer16;
+typedef signed int Integer32;
+typedef unsigned char UInteger8;
+typedef unsigned short UInteger16;
+typedef unsigned int UInteger32;
+
+typedef struct {
+ Integer32 nsec_prev, y;
+} offset_from_master_filter;
+
+typedef struct {
+ Integer32 nsec_prev, y;
+ Integer32 s_exp;
+} one_way_delay_filter;
+
+typedef struct {
+ void *pbuf[PBUF_QUEUE_SIZE];
+ Integer32 get;
+ Integer32 put;
+ Integer32 count;
+} BufQueue;
+
+typedef struct {
+ Integer32 multicastAddr;
+ Integer32 unicastAddr;
+ void *eventPcb;
+ void *generalPcb;
+ BufQueue eventQ;
+ BufQueue generalQ;
+ void *eventTxBuf;
+ void *generalTxBuf;
+} NetPath;
+
+#endif
diff --git a/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_dep.h b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_dep.h new file mode 100644 index 0000000..10b297e --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_dep.h @@ -0,0 +1,138 @@ +/* ptpd_dep.h */
+
+#ifndef PTPD_DEP_H
+#define PTPD_DEP_H
+
+#include <string.h>
+
+/*
+ * Remove the following #if 0 and its matching #endif to enable PTPd debug
+ * output on UART0. This is disabled by default even in debug builds due to
+ * the volume of information transmitted.
+ */
+#if 0
+#ifdef DEBUG
+#include "utils/uartstdio.h"
+#define PTPD_DBG
+/*
+ * Define the following to enable verbose debug.
+ */
+#undef PTPD_DBGV
+#endif
+#endif
+
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+#ifndef size_t
+#define size_t long
+#endif
+#ifndef ssize_t
+#define ssize_t long
+#endif
+
+/* system messages */
+#ifndef PTPD_DBG
+#define ERROR(...)
+#define PERROR(...)
+#define NOTIFY(...)
+#else
+#define ERROR(x, ...) UARTprintf("(ptpd error) " x, ##__VA_ARGS__)
+#define PERROR(x, ...) UARTprintf("(ptpd error) " x ": %m\n", ##__VA_ARGS__)
+#define NOTIFY(x, ...) UARTprintf("(ptpd notice) " x, ##__VA_ARGS__)
+#endif
+
+/* debug messages */
+#ifdef PTPD_DBGV
+#define PTPD_DBG
+#define DBGV(x, ...) UARTprintf("(ptpd debug) " x, ##__VA_ARGS__)
+#else
+#define DBGV(...)
+#endif
+
+#ifdef PTPD_DBG
+#define DBG(x, ...) UARTprintf("(ptpd debug) " x, ##__VA_ARGS__)
+#else
+#define DBG(...)
+#endif
+
+/* endian corrections */
+#if defined(PTPD_MSBF)
+#define shift8(x,y) ( (x) << ((3-y)<<3) )
+#define shift16(x,y) ( (x) << ((1-y)<<4) )
+#define flip16(x) (x)
+#define flip32(x) (x)
+
+#elif defined(PTPD_LSBF)
+#define shift8(x,y) ( (x) << ((y)<<3) )
+#define shift16(x,y) ( (x) << ((y)<<4) )
+#define flip16(x) ((((x) >> 8) & 0x00ff) | (((x) << 8) & 0xff00))
+#define flip32(x) ((((x) >> 24) & 0x000000ff) | \
+ (((x) >> 8 ) & 0x0000ff00) | \
+ (((x) << 8 ) & 0x00ff0000) | \
+ (((x) << 24) & 0xff000000))
+#endif
+
+
+/* bit array manipulation */
+#define getFlag(x,y) !!( *(UInteger8*)((x)+((y)<8?1:0)) & (1<<((y)<8?(y):(y)-8)) )
+#define setFlag(x,y) ( *(UInteger8*)((x)+((y)<8?1:0)) |= 1<<((y)<8?(y):(y)-8) )
+#define clearFlag(x,y) ( *(UInteger8*)((x)+((y)<8?1:0)) &= ~(1<<((y)<8?(y):(y)-8)) )
+
+
+#define labs(x) (((x) >= 0) ? (x) : -(x))
+
+/* msg.c */
+Boolean msgPeek(char*,size_t);
+void msgUnpackHeader(char*,MsgHeader*);
+void msgUnpackSync(char*,MsgSync*);
+void msgUnpackDelayReq(char*,MsgDelayReq*);
+void msgUnpackFollowUp(char*,MsgFollowUp*);
+void msgUnpackDelayResp(char*,MsgDelayResp*);
+void msgUnpackManagement(char*,MsgManagement*);
+UInteger8 msgUnloadManagement(char*,MsgManagement*,PtpClock*,RunTimeOpts*);
+void msgUnpackManagementPayload(char *buf, MsgManagement *manage);
+void msgPackHeader(char*,PtpClock*);
+void msgPackSync(char*,Boolean,TimeRepresentation*,PtpClock*);
+void msgPackDelayReq(char*,Boolean,TimeRepresentation*,PtpClock*);
+void msgPackFollowUp(char*,UInteger16,TimeRepresentation*,PtpClock*);
+void msgPackDelayResp(char*,MsgHeader*,TimeRepresentation*,PtpClock*);
+UInteger16 msgPackManagement(char*,MsgManagement*,PtpClock*);
+UInteger16 msgPackManagementResponse(char*,MsgHeader*,MsgManagement*,PtpClock*);
+
+/* net.c */
+Boolean netInit(NetPath*,RunTimeOpts*,PtpClock*);
+Boolean netShutdown(NetPath*);
+int netSelect(TimeInternal*,NetPath*);
+size_t netRecvEvent(Octet*,TimeInternal*,NetPath*);
+size_t netRecvGeneral(Octet*,NetPath*);
+size_t netSendEvent(Octet*,UInteger16,NetPath*);
+size_t netSendGeneral(Octet*,UInteger16,NetPath*);
+
+/* servo.c */
+void initClock(RunTimeOpts*,PtpClock*);
+void updateDelay(TimeInternal*,TimeInternal*,
+ one_way_delay_filter*,RunTimeOpts*,PtpClock*);
+void updateOffset(TimeInternal*,TimeInternal*,
+ offset_from_master_filter*,RunTimeOpts*,PtpClock*);
+void updateClock(RunTimeOpts*,PtpClock*);
+
+/* sys.c */
+void displayStats(RunTimeOpts*,PtpClock*);
+Boolean nanoSleep(TimeInternal*);
+void getTime(TimeInternal*);
+void setTime(TimeInternal*);
+UInteger16 getRand(UInteger32*);
+Boolean adjFreq(Integer32);
+
+/* timer.c */
+void initTimer(void);
+void timerTick(int);
+void timerUpdate(IntervalTimer*);
+void timerStop(UInteger16,IntervalTimer*);
+void timerStart(UInteger16,UInteger16,IntervalTimer*);
+Boolean timerExpired(UInteger16,IntervalTimer*);
+
+
+#endif
+
diff --git a/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_msg.c b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_msg.c new file mode 100644 index 0000000..6827ec0 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_msg.c @@ -0,0 +1,655 @@ +/* ptpd_msg.c */
+/* see spec annex d */
+
+#include "../ptpd.h"
+
+Boolean msgPeek(char *buf, size_t length)
+{
+ /* not imlpemented yet */
+ return TRUE;
+}
+
+void msgUnpackHeader(char *buf, MsgHeader *header)
+{
+ header->versionPTP = flip16(*(UInteger16*)(buf + 0));
+ header->versionNetwork = flip16(*(UInteger16*)(buf + 2));
+ DBGV("msgUnpackHeader: versionPTP %d\n", header->versionPTP);
+ DBGV("msgUnpackHeader: versionNetwork %d\n", header->versionNetwork);
+
+ memcpy(header->subdomain, (buf + 4), 16);
+ DBGV("msgUnpackHeader: subdomain %s\n", header->subdomain);
+
+ header->messageType = *(UInteger8*)(buf + 20);
+ header->sourceCommunicationTechnology = *(UInteger8*)(buf + 21);
+ DBGV("msgUnpackHeader: messageType %d\n", header->messageType);
+ DBGV("msgUnpackHeader: sourceCommunicationTechnology %d\n", header->sourceCommunicationTechnology);
+
+ memcpy(header->sourceUuid, (buf + 22), 6);
+ DBGV("msgUnpackHeader: sourceUuid %02x:%02x:%02x:%02x:%02x:%02x\n",
+ header->sourceUuid[0], header->sourceUuid[1], header->sourceUuid[2],
+ header->sourceUuid[3], header->sourceUuid[4], header->sourceUuid[5]);
+
+ header->sourcePortId = flip16(*(UInteger16*)(buf + 28));
+ header->sequenceId = flip16(*(UInteger16*)(buf + 30));
+ DBGV("msgUnpackHeader: sourcePortId %d\n", header->sourcePortId);
+ DBGV("msgUnpackHeader: sequenceId %d\n", header->sequenceId);
+
+ header->control = *(UInteger8*)(buf + 32);
+ DBGV("msgUnpackHeader: control %d\n", header->control);
+
+ memcpy(header->flags, (buf + 34), 2);
+ DBGV("msgUnpackHeader: flags %02x %02x\n", header->flags[0], header->flags[1]);
+}
+
+void msgUnpackSync(char *buf, MsgSync *sync)
+{
+ sync->originTimestamp.seconds = flip32(*(UInteger32*)(buf + 40));
+ DBG("msgUnpackSync: originTimestamp.seconds %u\n", sync->originTimestamp.seconds);
+ sync->originTimestamp.nanoseconds = flip32(*(Integer32*)(buf + 44));
+ DBG("msgUnpackSync: originTimestamp.nanoseconds %d\n", sync->originTimestamp.nanoseconds);
+ sync->epochNumber = flip16(*(UInteger16*)(buf + 48));
+ DBGV("msgUnpackSync: epochNumber %d\n", sync->epochNumber);
+ sync->currentUTCOffset = flip16(*(Integer16*)(buf + 50));
+ DBGV("msgUnpackSync: currentUTCOffset %d\n", sync->currentUTCOffset);
+ sync->grandmasterCommunicationTechnology = *(UInteger8*)(buf + 53);
+ DBGV("msgUnpackSync: grandmasterCommunicationTechnology %d\n", sync->grandmasterCommunicationTechnology);
+ memcpy(sync->grandmasterClockUuid, (buf + 54), 6);
+ DBGV("msgUnpackSync: grandmasterClockUuid %02x:%02x:%02x:%02x:%02x:%02x\n",
+ sync->grandmasterClockUuid[0], sync->grandmasterClockUuid[1], sync->grandmasterClockUuid[2],
+ sync->grandmasterClockUuid[3], sync->grandmasterClockUuid[4], sync->grandmasterClockUuid[5]);
+ sync->grandmasterPortId = flip16(*(UInteger16*)(buf + 60));
+ DBGV("msgUnpackSync: grandmasterPortId %d\n", sync->grandmasterPortId);
+ sync->grandmasterSequenceId = flip16(*(UInteger16*)(buf + 62));
+ DBGV("msgUnpackSync: grandmasterSequenceId %d\n", sync->grandmasterSequenceId);
+ sync->grandmasterClockStratum = *(UInteger8*)(buf + 67);
+ DBGV("msgUnpackSync: grandmasterClockStratum %d\n", sync->grandmasterClockStratum);
+ memcpy(sync->grandmasterClockIdentifier, (buf + 68), 4);
+ DBGV("msgUnpackSync: grandmasterClockIdentifier %c%c%c%c\n",
+ sync->grandmasterClockIdentifier[0], sync->grandmasterClockIdentifier[1],
+ sync->grandmasterClockIdentifier[2], sync->grandmasterClockIdentifier[3]);
+ sync->grandmasterClockVariance = flip16(*(Integer16*)(buf + 74));
+ DBGV("msgUnpackSync: grandmasterClockVariance %d\n", sync->grandmasterClockVariance);
+ sync->grandmasterPreferred = *(UInteger8*)(buf + 77);
+ DBGV("msgUnpackSync: grandmasterPreferred %d\n", sync->grandmasterPreferred);
+ sync->grandmasterIsBoundaryClock = *(UInteger8*)(buf + 79);
+ DBGV("msgUnpackSync: grandmasterIsBoundaryClock %d\n", sync->grandmasterIsBoundaryClock);
+ sync->syncInterval = *(Integer8*)(buf + 83);
+ DBGV("msgUnpackSync: syncInterval %d\n", sync->syncInterval);
+ sync->localClockVariance = flip16(*(Integer16*)(buf + 86));
+ DBGV("msgUnpackSync: localClockVariance %d\n", sync->localClockVariance);
+ sync->localStepsRemoved = flip16(*(UInteger16*)(buf + 90));
+ DBGV("msgUnpackSync: localStepsRemoved %d\n", sync->localStepsRemoved);
+ sync->localClockStratum = *(UInteger8*)(buf + 95);
+ DBGV("msgUnpackSync: localClockStratum %d\n", sync->localClockStratum);
+ memcpy(sync->localClockIdentifer, (buf + 96), PTP_CODE_STRING_LENGTH);
+ DBGV("msgUnpackSync: localClockIdentifer %c%c%c%c\n",
+ sync->localClockIdentifer[0], sync->localClockIdentifer[1],
+ sync->localClockIdentifer[2], sync->localClockIdentifer[3]);
+ sync->parentCommunicationTechnology = *(UInteger8*)(buf + 101);
+ DBGV("msgUnpackSync: parentCommunicationTechnology %d\n", sync->parentCommunicationTechnology);
+ memcpy(sync->parentUuid, (buf + 102), PTP_UUID_LENGTH);
+ DBGV("msgUnpackSync: parentUuid %02x:%02x:%02x:%02x:%02x:%02x\n",
+ sync->parentUuid[0], sync->parentUuid[1], sync->parentUuid[2],
+ sync->parentUuid[3], sync->parentUuid[4], sync->parentUuid[5]);
+ sync->parentPortField = flip16(*(UInteger16*)(buf + 110));
+ DBGV("msgUnpackSync: parentPortField %d\n", sync->parentPortField);
+ sync->estimatedMasterVariance = flip16(*(Integer16*)(buf + 114));
+ DBGV("msgUnpackSync: estimatedMasterVariance %d\n", sync->estimatedMasterVariance);
+ sync->estimatedMasterDrift = flip32(*(Integer32*)(buf + 116));
+ DBGV("msgUnpackSync: estimatedMasterDrift %d\n", sync->estimatedMasterDrift);
+ sync->utcReasonable = *(UInteger8*)(buf + 123);
+ DBGV("msgUnpackSync: utcReasonable %d\n", sync->utcReasonable);
+}
+
+void msgUnpackDelayReq(char *buf, MsgDelayReq *req) {}
+
+void msgUnpackFollowUp(char *buf, MsgFollowUp *follow)
+{
+ follow->associatedSequenceId = flip16(*(UInteger16*)(buf + 42));
+ DBGV("msgUnpackFollowUp: associatedSequenceId %u\n", follow->associatedSequenceId);
+ follow->preciseOriginTimestamp.seconds = flip32(*(UInteger32*)(buf + 44));
+ DBG("msgUnpackFollowUp: preciseOriginTimestamp.seconds %u\n", follow->preciseOriginTimestamp.seconds);
+ follow->preciseOriginTimestamp.nanoseconds = flip32(*(Integer32*)(buf + 48));
+ DBG("msgUnpackFollowUp: preciseOriginTimestamp.nanoseconds %d\n", follow->preciseOriginTimestamp.nanoseconds);
+}
+
+void msgUnpackDelayResp(char *buf, MsgDelayResp *resp)
+{
+ resp->delayReceiptTimestamp.seconds = flip32(*(UInteger32*)(buf + 40));
+ DBGV("msgUnpackDelayResp: delayReceiptTimestamp.seconds %u\n", resp->delayReceiptTimestamp.seconds);
+ resp->delayReceiptTimestamp.nanoseconds = flip32(*(Integer32*)(buf + 44));
+ DBGV("msgUnpackDelayResp: delayReceiptTimestamp.nanoseconds %d\n", resp->delayReceiptTimestamp.nanoseconds);
+ resp->requestingSourceCommunicationTechnology = *(UInteger8*)(buf + 49);
+ DBGV("msgUnpackDelayResp: requestingSourceCommunicationTechnology %d\n", resp->requestingSourceCommunicationTechnology);
+ memcpy(resp->requestingSourceUuid, (buf + 50), 6);
+ DBGV("msgUnpackDelayResp: requestingSourceUuid %02x:%02x:%02x:%02x:%02x:%02x\n",
+ resp->requestingSourceUuid[0], resp->requestingSourceUuid[1], resp->requestingSourceUuid[2],
+ resp->requestingSourceUuid[3], resp->requestingSourceUuid[4], resp->requestingSourceUuid[5]);
+ resp->requestingSourcePortId = flip16(*(UInteger16*)(buf + 56));
+ DBGV("msgUnpackDelayResp: requestingSourcePortId %d\n", resp->requestingSourcePortId);
+ resp->requestingSourceSequenceId = flip16(*(UInteger16*)(buf + 58));
+ DBGV("msgUnpackDelayResp: requestingSourceSequenceId %d\n", resp->requestingSourceSequenceId);
+}
+
+void msgUnpackManagement(char *buf, MsgManagement *manage)
+{
+ manage->targetCommunicationTechnology = *(UInteger8*)(buf + 41);
+ DBGV("msgUnpackManagement: targetCommunicationTechnology %d\n", manage->targetCommunicationTechnology);
+ memcpy(manage->targetUuid, (buf + 42), 6);
+ DBGV("msgUnpackManagement: targetUuid %02x:%02x:%02x:%02x:%02x:%02x\n",
+ manage->targetUuid[0], manage->targetUuid[1], manage->targetUuid[2],
+ manage->targetUuid[3], manage->targetUuid[4], manage->targetUuid[5]);
+ manage->targetPortId = flip16(*(UInteger16*)(buf + 48));
+ DBGV("msgUnpackManagement: targetPortId %d\n", manage->targetPortId);
+ manage->startingBoundaryHops = flip16(*(Integer16*)(buf + 50));
+ DBGV("msgUnpackManagement: startingBoundaryHops %d\n", manage->startingBoundaryHops);
+ manage->boundaryHops = flip16(*(Integer16*)(buf + 52));
+ DBGV("msgUnpackManagement: boundaryHops %d\n", manage->boundaryHops);
+ manage->managementMessageKey = *(UInteger8*)(buf + 55);
+ DBGV("msgUnpackManagement: managementMessageKey %d\n", manage->managementMessageKey);
+ manage->parameterLength = flip16(*(UInteger16*)(buf + 58));
+ DBGV("msgUnpackManagement: parameterLength %d\n", manage->parameterLength);
+
+ if(manage->managementMessageKey == PTP_MM_GET_FOREIGN_DATA_SET)
+ manage->recordKey = flip16(*(UInteger16*)(buf + 62));
+}
+
+UInteger8 msgUnloadManagement(char *buf, MsgManagement *manage,
+ PtpClock *ptpClock, RunTimeOpts *rtOpts)
+{
+ TimeInternal internalTime;
+ TimeRepresentation externalTime;
+
+ switch(manage->managementMessageKey)
+ {
+ case PTP_MM_INITIALIZE_CLOCK:
+ if(ptpClock->initializable)
+ return PTP_INITIALIZING;
+ break;
+
+ case PTP_MM_GOTO_FAULTY_STATE:
+ DBG("event FAULT_DETECTED (forced by management message)\n");
+ return PTP_FAULTY;
+ break;
+
+ case PTP_MM_DISABLE_PORT:
+ if(manage->targetPortId == 1)
+ {
+ DBG("event DESIGNATED_DISABLED\n");
+ return PTP_DISABLED;
+ }
+ break;
+
+ case PTP_MM_ENABLE_PORT:
+ if(manage->targetPortId == 1)
+ {
+ DBG("event DESIGNATED_ENABLED\n");
+ return PTP_INITIALIZING;
+ }
+ break;
+
+ case PTP_MM_CLEAR_DESIGNATED_PREFERRED_MASTER:
+ ptpClock->preferred = FALSE;
+ break;
+
+ case PTP_MM_SET_DESIGNATED_PREFERRED_MASTER:
+ ptpClock->preferred = TRUE;
+ break;
+
+ case PTP_MM_DISABLE_BURST:
+ break;
+
+ case PTP_MM_ENABLE_BURST:
+ break;
+
+ case PTP_MM_SET_SYNC_INTERVAL:
+ rtOpts->syncInterval = *(Integer8*)(buf + 63);
+ break;
+
+ case PTP_MM_SET_SUBDOMAIN:
+ memcpy(rtOpts->subdomainName, buf + 60, 16);
+ DBG("set subdomain to %s\n", rtOpts->subdomainName);
+ break;
+
+ case PTP_MM_SET_TIME:
+ externalTime.seconds = flip32(*(UInteger32*)(buf + 60));
+ externalTime.nanoseconds = flip32(*(Integer32*)(buf + 64));
+ toInternalTime(&internalTime, &externalTime, &ptpClock->halfEpoch);
+ setTime(&internalTime);
+ break;
+
+ case PTP_MM_UPDATE_DEFAULT_DATA_SET:
+ if(!rtOpts->slaveOnly)
+ ptpClock->clock_stratum = *(UInteger8*)(buf + 63);
+ memcpy(ptpClock->clock_identifier, buf + 64, 4);
+ ptpClock->clock_variance = flip16(*(Integer16*)(buf + 70));
+ ptpClock->preferred = *(UInteger8*)(buf + 75);
+ rtOpts->syncInterval = *(UInteger8*)(buf + 79);
+ memcpy(rtOpts->subdomainName, buf + 80, 16);
+ break;
+
+ case PTP_MM_UPDATE_GLOBAL_TIME_PROPERTIES:
+ ptpClock->current_utc_offset = flip16(*(Integer16*)(buf + 62));
+ ptpClock->leap_59 = *(UInteger8*)(buf + 67);
+ ptpClock->leap_61 = *(UInteger8*)(buf + 71);
+ ptpClock->epoch_number = flip16(*(UInteger16*)(buf + 74));
+ break;
+
+ default:
+ break;
+ }
+
+ return ptpClock->port_state;
+}
+
+void msgUnpackManagementPayload(char *buf, MsgManagement *manage)
+{
+ switch(manage->managementMessageKey)
+ {
+ case PTP_MM_CLOCK_IDENTITY:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_CLOCK_IDENTITY\n");
+ manage->payload.clockIdentity.clockCommunicationTechnology = *(UInteger8*)(buf + 63);
+ memcpy(manage->payload.clockIdentity.clockUuidField, buf + 64, PTP_UUID_LENGTH);
+ manage->payload.clockIdentity.clockPortField = flip16(*(UInteger16*)(buf + 74));
+ memcpy(manage->payload.clockIdentity.manufacturerIdentity, buf + 76, MANUFACTURER_ID_LENGTH);
+ break;
+
+ case PTP_MM_DEFAULT_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_DEFAULT_DATA_SET\n");
+ manage->payload.defaultData.clockCommunicationTechnology = *(UInteger8*)(buf + 63);
+ memcpy(manage->payload.defaultData.clockUuidField, buf + 64, PTP_UUID_LENGTH);
+ manage->payload.defaultData.clockPortField = flip16(*(UInteger16*)(buf + 74));
+ manage->payload.defaultData.clockStratum = *(UInteger16*)(buf + 79);
+ memcpy(manage->payload.defaultData.clockIdentifier, buf + 80, PTP_CODE_STRING_LENGTH);
+ manage->payload.defaultData.clockVariance = flip16(*(UInteger16*)(buf + 86));
+ manage->payload.defaultData.clockFollowupCapable = *(UInteger8*)(buf + 91);
+ manage->payload.defaultData.preferred = *(UInteger8*)(buf + 95);
+ manage->payload.defaultData.initializable = *(UInteger8*)(buf + 99);
+ manage->payload.defaultData.externalTiming = *(UInteger8*)(buf + 103);
+ manage->payload.defaultData.isBoundaryClock = *(UInteger8*)(buf + 107);
+ manage->payload.defaultData.syncInterval = *(UInteger8*)(buf + 111);
+ memcpy(manage->payload.defaultData.subdomainName, buf + 112, PTP_SUBDOMAIN_NAME_LENGTH);
+ manage->payload.defaultData.numberPorts = flip16(*(UInteger16*)(buf + 130));
+ manage->payload.defaultData.numberForeignRecords = flip16(*(UInteger16*)(buf + 134));
+ break;
+
+ case PTP_MM_CURRENT_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_CURRENT_DATA_SET\n");
+ manage->payload.current.stepsRemoved = flip16(*(UInteger16*)(buf + 62));
+ manage->payload.current.offsetFromMaster.seconds = flip32(*(UInteger32*)(buf + 64));
+ manage->payload.current.offsetFromMaster.nanoseconds = flip32(*(UInteger32*)(buf + 68));
+ manage->payload.current.oneWayDelay.seconds = flip32(*(UInteger32*)(buf + 72));
+ manage->payload.current.oneWayDelay.nanoseconds = flip32(*(Integer32*)(buf + 76));
+ break;
+
+ case PTP_MM_PARENT_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_PORT_DATA_SET\n");
+ manage->payload.parent.parentCommunicationTechnology = *(UInteger8*)(buf + 63);
+ memcpy(manage->payload.parent.parentUuid, buf + 64, PTP_UUID_LENGTH);
+ manage->payload.parent.parentPortId = flip16(*(UInteger16*)(buf + 74));
+ manage->payload.parent.parentLastSyncSequenceNumber = flip16(*(UInteger16*)(buf + 74));
+ manage->payload.parent.parentFollowupCapable = *(UInteger8*)(buf + 83);
+ manage->payload.parent.parentExternalTiming = *(UInteger8*)(buf + 87);
+ manage->payload.parent.parentVariance = flip16(*(UInteger16*)(buf + 90));
+ manage->payload.parent.parentStats = *(UInteger8*)(buf + 85);
+ manage->payload.parent.observedVariance = flip16(*(Integer16*)(buf + 98));
+ manage->payload.parent.observedDrift = flip32(*(Integer32*)(buf + 100));
+ manage->payload.parent.utcReasonable = *(UInteger8*)(buf + 107);
+ manage->payload.parent.grandmasterCommunicationTechnology = *(UInteger8*)(buf + 111);
+ memcpy(manage->payload.parent.grandmasterUuidField, buf + 112, PTP_UUID_LENGTH);
+ manage->payload.parent.grandmasterPortIdField = flip16(*(UInteger16*)(buf + 122));
+ manage->payload.parent.grandmasterStratum = *(UInteger8*)(buf + 127);
+ memcpy(manage->payload.parent.grandmasterIdentifier, buf + 128, PTP_CODE_STRING_LENGTH);
+ manage->payload.parent.grandmasterVariance = flip16(*(Integer16*)(buf + 134));
+ manage->payload.parent.grandmasterPreferred = *(UInteger8*)(buf + 139);
+ manage->payload.parent.grandmasterIsBoundaryClock = *(UInteger8*)(buf + 144);
+ manage->payload.parent.grandmasterSequenceNumber = flip16(*(UInteger16*)(buf + 146));
+ break;
+
+ case PTP_MM_PORT_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_FOREIGN_DATA_SET\n");
+ manage->payload.port.returnedPortNumber = flip16(*(UInteger16*)(buf + 62));
+ manage->payload.port.portState = *(UInteger8*)(buf + 67);
+ manage->payload.port.lastSyncEventSequenceNumber = flip16(*(UInteger16*)(buf + 70));
+ manage->payload.port.lastGeneralEventSequenceNumber = flip16(*(UInteger16*)(buf + 74));
+ manage->payload.port.portCommunicationTechnology = *(UInteger8*)(buf + 79);
+ memcpy(manage->payload.port.portUuidField, buf + 80, PTP_UUID_LENGTH);
+ manage->payload.port.portIdField = flip16(*(UInteger16*)(buf + 90));
+ manage->payload.port.burstEnabled = *(UInteger8*)(buf + 95);
+ manage->payload.port.subdomainAddressOctets = *(UInteger8*)(buf + 97);
+ manage->payload.port.eventPortAddressOctets = *(UInteger8*)(buf + 98);
+ manage->payload.port.generalPortAddressOctets = *(UInteger8*)(buf + 99);
+ memcpy(manage->payload.port.subdomainAddress, buf + 100, SUBDOMAIN_ADDRESS_LENGTH);
+ memcpy(manage->payload.port.eventPortAddress, buf + 106, PORT_ADDRESS_LENGTH);
+ memcpy(manage->payload.port.generalPortAddress, buf + 110, PORT_ADDRESS_LENGTH);
+ break;
+
+ case PTP_MM_GLOBAL_TIME_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_GLOBAL_TIME_DATA_SET\n");
+ manage->payload.globalTime.localTime.seconds = flip32(*(UInteger32*)(buf + 60));
+ manage->payload.globalTime.localTime.nanoseconds = flip32(*(Integer32*)(buf + 64));
+ manage->payload.globalTime.currentUtcOffset = flip16(*(Integer16*)(buf + 70));
+ manage->payload.globalTime.leap59 = *(UInteger8*)(buf + 75);
+ manage->payload.globalTime.leap61 = *(UInteger8*)(buf + 79);
+ manage->payload.globalTime.epochNumber = flip16(*(UInteger16*)(buf + 82));
+ break;
+
+
+ case PTP_MM_FOREIGN_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_FOREIGN_DATA_SET\n");
+ manage->payload.foreign.returnedPortNumber = flip16(*(UInteger16*)(buf + 62));
+ manage->payload.foreign.returnedRecordNumber = flip16(*(UInteger16*)(buf + 68));
+ manage->payload.foreign.foreignMasterCommunicationTechnology = *(UInteger8*)(buf + 71);
+ memcpy(manage->payload.foreign.foreignMasterUuid, buf + 72, PTP_UUID_LENGTH);
+ manage->payload.foreign.foreignMasterPortId = flip16(*(UInteger16*)(buf + 82));
+ manage->payload.foreign.foreignMasterSyncs = flip16(*(UInteger16*)(buf + 66));
+ break;
+
+ case PTP_MM_NULL:
+ DBGV("msgUnloadManagementPayload: managementMessageKey NULL\n");
+ break;
+
+ default:
+ DBGV("msgUnloadManagementPayload: managementMessageKey ?\n");
+ break;
+ }
+
+ return;
+}
+
+void msgPackHeader(char *buf, PtpClock *ptpClock)
+{
+ *(Integer32*)(buf + 0) = shift16(flip16(VERSION_PTP), 0) | shift16(flip16(VERSION_NETWORK), 1);
+ memcpy((buf + 4), ptpClock->subdomain_name, 16);
+ *(Integer32*)(buf + 20) = shift8(ptpClock->port_communication_technology, 1);
+ memcpy((buf + 22), ptpClock->port_uuid_field, 6);
+
+ if(ptpClock->external_timing)
+ setFlag((buf + 34), PTP_EXT_SYNC);
+ if(ptpClock->clock_followup_capable)
+ setFlag((buf + 34), PTP_ASSIST);
+ if(ptpClock->is_boundary_clock)
+ setFlag((buf + 34), PTP_BOUNDARY_CLOCK);
+}
+
+void msgPackSync(char *buf, Boolean burst,
+ TimeRepresentation *originTimestamp, PtpClock *ptpClock)
+{
+ *(UInteger8*)(buf +20) = 1; /* messageType */
+ *(Integer32*)(buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_sync_event_sequence_number), 1);
+ *(UInteger8*)(buf +32) = PTP_SYNC_MESSAGE; /* control */
+ if(ptpClock->burst_enabled && burst)
+ setFlag((buf + 34), PTP_SYNC_BURST);
+ else
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ if(ptpClock->parent_stats)
+ setFlag((buf + 34), PARENT_STATS);
+ else
+ clearFlag((buf + 34), PARENT_STATS);
+
+
+ *(Integer32*)(buf + 40) = flip32(originTimestamp->seconds);
+ *(Integer32*)(buf + 44) = flip32(originTimestamp->nanoseconds);
+ *(Integer32*)(buf + 48) = shift16(flip16(ptpClock->epoch_number), 0) | shift16(flip16(ptpClock->current_utc_offset), 1);
+ *(Integer32*)(buf + 52) = shift8(ptpClock->grandmaster_communication_technology, 1);
+ memcpy((buf + 54), ptpClock->grandmaster_uuid_field, 6);
+ *(Integer32*)(buf + 60) = shift16(flip16(ptpClock->grandmaster_port_id_field), 0) | shift16(flip16(ptpClock->grandmaster_sequence_number), 1);
+ *(Integer32*)(buf + 64) = shift8(ptpClock->grandmaster_stratum, 3);
+ memcpy((buf + 68), ptpClock->grandmaster_identifier, 4);
+ *(Integer32*)(buf + 72) = shift16(flip16(ptpClock->grandmaster_variance), 1);
+ *(Integer32*)(buf + 76) = shift16(flip16(ptpClock->grandmaster_preferred), 0) | shift16(flip16(ptpClock->grandmaster_is_boundary_clock), 1);
+ *(Integer32*)(buf + 80) = shift16(flip16(ptpClock->sync_interval), 1);
+ *(Integer32*)(buf + 84) = shift16(flip16(ptpClock->clock_variance), 1);
+ *(Integer32*)(buf + 88) = shift16(flip16(ptpClock->steps_removed), 1);
+ *(Integer32*)(buf + 92) = shift8(ptpClock->clock_stratum, 3);
+ memcpy((buf + 96), ptpClock->clock_identifier, 4);
+ *(Integer32*)(buf + 100) = shift8(ptpClock->parent_communication_technology, 1);
+ memcpy((buf + 102), ptpClock->parent_uuid, 6);
+ *(Integer32*)(buf + 108) = shift16(flip16(ptpClock->parent_port_id), 1);
+ *(Integer32*)(buf + 112) = shift16(flip16(ptpClock->observed_variance), 1);
+ *(Integer32*)(buf + 116) = flip32(ptpClock->observed_drift);
+ *(Integer32*)(buf + 120) = shift8(ptpClock->utc_reasonable, 3);
+}
+
+void msgPackDelayReq(char *buf, Boolean burst,
+ TimeRepresentation *originTimestamp, PtpClock *ptpClock)
+{
+ *(UInteger8*)(buf + 20) = 1; /* messageType */
+ *(Integer32*)(buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_sync_event_sequence_number), 1);
+ *(UInteger8*)(buf + 32) = PTP_DELAY_REQ_MESSAGE; /* control */
+ if(ptpClock->burst_enabled && burst)
+ setFlag((buf + 34), PTP_SYNC_BURST);
+ else
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ if(ptpClock->parent_stats)
+ setFlag((buf + 34), PARENT_STATS);
+ else
+ clearFlag((buf + 34), PARENT_STATS);
+
+ *(Integer32*)(buf + 40) = flip32(originTimestamp->seconds);
+ *(Integer32*)(buf + 44) = flip32(originTimestamp->nanoseconds);
+ *(Integer32*)(buf + 48) = shift16(flip16(ptpClock->epoch_number), 0) | shift16(flip16(ptpClock->current_utc_offset), 1);
+ *(Integer32*)(buf + 52) = shift8(ptpClock->grandmaster_communication_technology, 1);
+ memcpy((buf + 54), ptpClock->grandmaster_uuid_field, 6);
+ *(Integer32*)(buf + 60) = shift16(flip16(ptpClock->grandmaster_port_id_field), 0) | shift16(flip16(ptpClock->grandmaster_sequence_number), 1);
+ *(Integer32*)(buf + 64) = shift8(ptpClock->grandmaster_stratum, 3);
+ memcpy((buf + 68), ptpClock->grandmaster_identifier, 4);
+ *(Integer32*)(buf + 72) = shift16(flip16(ptpClock->grandmaster_variance), 1);
+ *(Integer32*)(buf + 76) = shift16(flip16(ptpClock->grandmaster_preferred), 0) | shift16(flip16(ptpClock->grandmaster_is_boundary_clock), 1);
+ *(Integer32*)(buf + 80) = shift16(flip16(ptpClock->sync_interval), 1);
+ *(Integer32*)(buf + 84) = shift16(flip16(ptpClock->clock_variance), 1);
+ *(Integer32*)(buf + 88) = shift16(flip16(ptpClock->steps_removed), 1);
+ *(Integer32*)(buf + 92) = shift8(ptpClock->clock_stratum, 3);
+ memcpy((buf + 96), ptpClock->clock_identifier, 4);
+ *(Integer32*)(buf + 100) = shift8(ptpClock->parent_communication_technology, 1);
+ memcpy((buf + 102), ptpClock->parent_uuid, 6);
+ *(Integer32*)(buf + 108) = shift16(flip16(ptpClock->parent_port_id), 1);
+ *(Integer32*)(buf + 112) = shift16(flip16(ptpClock->observed_variance), 1);
+ *(Integer32*)(buf + 116) = flip32(ptpClock->observed_drift);
+ *(Integer32*)(buf + 120) = shift8(ptpClock->utc_reasonable, 3);
+}
+
+void msgPackFollowUp(char *buf, UInteger16 associatedSequenceId,
+ TimeRepresentation *preciseOriginTimestamp, PtpClock *ptpClock)
+{
+ *(UInteger8*)(buf + 20) = 2; /* messageType */
+ *(Integer32*)(buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(UInteger8*)(buf + 32) = PTP_FOLLOWUP_MESSAGE; /* control */
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ clearFlag((buf + 34), PARENT_STATS);
+
+ *(Integer32*)(buf + 40) = shift16(flip16(associatedSequenceId), 1);
+ *(Integer32*)(buf + 44) = flip32(preciseOriginTimestamp->seconds);
+ *(Integer32*)(buf + 48) = flip32(preciseOriginTimestamp->nanoseconds);
+}
+
+void msgPackDelayResp(char *buf, MsgHeader *header,
+ TimeRepresentation *delayReceiptTimestamp, PtpClock *ptpClock)
+{
+ *(UInteger8*)(buf + 20) = 2; /* messageType */
+ *(Integer32*)(buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(UInteger8*)(buf + 32) = PTP_DELAY_RESP_MESSAGE; /* control */
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ clearFlag((buf + 34), PARENT_STATS);
+
+ *(Integer32*)(buf + 40) = flip32(delayReceiptTimestamp->seconds);
+ *(Integer32*)(buf + 44) = flip32(delayReceiptTimestamp->nanoseconds);
+ *(Integer32*)(buf + 48) = shift8(header->sourceCommunicationTechnology, 1);
+ memcpy(buf + 50, header->sourceUuid, 6);
+ *(Integer32*)(buf + 56) = shift16(flip16(header->sourcePortId), 0) | shift16(flip16(header->sequenceId), 1);
+}
+
+UInteger16 msgPackManagement(char *buf, MsgManagement *manage, PtpClock *ptpClock)
+{
+ *(UInteger8*)(buf + 20) = 2; /* messageType */
+ *(Integer32*)(buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(UInteger8*)(buf + 32) = PTP_MANAGEMENT_MESSAGE; /* control */
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ clearFlag((buf + 34), PARENT_STATS);
+ *(Integer32*)(buf + 40) = shift8(manage->targetCommunicationTechnology, 1);
+ memcpy(buf + 42, manage->targetUuid, 6);
+ *(Integer32*)(buf + 48) = shift16(flip16(manage->targetPortId), 0) | shift16(flip16(MM_STARTING_BOUNDARY_HOPS), 1);
+ *(Integer32*)(buf + 52) = shift16(flip16(MM_STARTING_BOUNDARY_HOPS), 0);
+
+ *(UInteger8*)(buf + 55) = manage->managementMessageKey;
+
+ switch(manage->managementMessageKey)
+ {
+ case PTP_MM_GET_FOREIGN_DATA_SET:
+ *(UInteger16*)(buf + 62) = manage->recordKey;
+ *(Integer32*)(buf + 56) = shift16(flip16(4), 1);
+ return 64;
+
+ default:
+ *(Integer32*)(buf + 56) = shift16(flip16(0), 1);
+ return 60;
+ }
+}
+
+UInteger16 msgPackManagementResponse(char *buf, MsgHeader *header, MsgManagement *manage, PtpClock *ptpClock)
+{
+ TimeInternal internalTime;
+ TimeRepresentation externalTime;
+
+ *(UInteger8*)(buf + 20) = 2; /* messageType */
+ *(Integer32*)(buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(UInteger8*)(buf + 32) = PTP_MANAGEMENT_MESSAGE; /* control */
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ clearFlag((buf + 34), PARENT_STATS);
+ *(Integer32*)(buf + 40) = shift8(header->sourceCommunicationTechnology, 1);
+ memcpy(buf + 42, header->sourceUuid, 6);
+ *(Integer32*)(buf + 48) = shift16(flip16(header->sourcePortId), 0) | shift16(flip16(MM_STARTING_BOUNDARY_HOPS), 1);
+ *(Integer32*)(buf + 52) = shift16(flip16(manage->startingBoundaryHops - manage->boundaryHops + 1), 0);
+
+ switch(manage->managementMessageKey)
+ {
+ case PTP_MM_OBTAIN_IDENTITY:
+ *(UInteger8*)(buf + 55) = PTP_MM_CLOCK_IDENTITY;
+ *(Integer32*)(buf + 56) = shift16(flip16(64), 1);
+ *(Integer32*)(buf + 60) = shift8(ptpClock->clock_communication_technology, 3);
+ memcpy(buf + 64, ptpClock->clock_uuid_field, 6);
+ *(Integer32*)(buf + 72) = shift16(flip16(ptpClock->clock_port_id_field), 1);
+ memcpy((buf + 76), MANUFACTURER_ID, 48);
+ return 124;
+
+ case PTP_MM_GET_DEFAULT_DATA_SET:
+ *(UInteger8*)(buf + 55) = PTP_MM_DEFAULT_DATA_SET;
+ *(Integer32*)(buf + 56) = shift16(flip16(76), 1);
+ *(Integer32*)(buf + 60) = shift8(ptpClock->clock_communication_technology, 3);
+ memcpy(buf + 64, ptpClock->clock_uuid_field, 6);
+ *(Integer32*)(buf + 72) = shift16(flip16(ptpClock->clock_port_id_field), 1);
+ *(Integer32*)(buf + 76) = shift8(ptpClock->clock_stratum, 3);
+ memcpy(buf + 80, ptpClock->clock_identifier, 4);
+ *(Integer32*)(buf + 84) = shift16(flip16(ptpClock->clock_variance), 1);
+ *(Integer32*)(buf + 88) = shift8(ptpClock->clock_followup_capable, 3);
+ *(Integer32*)(buf + 92) = shift8(ptpClock->preferred, 3);
+ *(Integer32*)(buf + 96) = shift8(ptpClock->initializable, 3);
+ *(Integer32*)(buf + 100) = shift8(ptpClock->external_timing, 3);
+ *(Integer32*)(buf + 104) = shift8(ptpClock->is_boundary_clock, 3);
+ *(Integer32*)(buf + 108) = shift8(ptpClock->sync_interval, 3);
+ memcpy(buf + 112, ptpClock->subdomain_name, 16);
+ *(Integer32*)(buf + 128) = shift16(flip16(ptpClock->number_ports), 1);
+ *(Integer32*)(buf + 132) = shift16(flip16(ptpClock->number_foreign_records), 1);
+ return 136;
+
+ case PTP_MM_GET_CURRENT_DATA_SET:
+ *(UInteger8*)(buf + 55) = PTP_MM_CURRENT_DATA_SET;
+ *(Integer32*)(buf + 56) = shift16(flip16(20), 1);
+ *(Integer32*)(buf + 60) = shift16(flip16(ptpClock->steps_removed), 1);
+
+ fromInternalTime(&ptpClock->offset_from_master, &externalTime, 0);
+ *(Integer32*)(buf + 64) = flip32(externalTime.seconds);
+ *(Integer32*)(buf + 68) = flip32(externalTime.nanoseconds);
+
+ fromInternalTime(&ptpClock->one_way_delay, &externalTime, 0);
+ *(Integer32*)(buf + 72) = flip32(externalTime.seconds);
+ *(Integer32*)(buf + 76) = flip32(externalTime.nanoseconds);
+ return 80;
+
+ case PTP_MM_GET_PARENT_DATA_SET:
+ *(UInteger8*)(buf + 55) = PTP_MM_PARENT_DATA_SET;
+ *(Integer32*)(buf + 56) = shift16(flip16(90), 1);
+ *(Integer32*)(buf + 60) = shift8(ptpClock->parent_communication_technology, 3);
+ memcpy(buf + 64, ptpClock->parent_uuid, 6);
+ *(Integer32*)(buf + 72) = shift16(flip16(ptpClock->parent_port_id), 1);
+ *(Integer32*)(buf + 76) = shift16(flip16(ptpClock->parent_last_sync_sequence_number), 1);
+ *(Integer32*)(buf + 80) = shift8(ptpClock->parent_followup_capable, 1);
+ *(Integer32*)(buf + 84) = shift8(ptpClock->parent_external_timing, 3);
+ *(Integer32*)(buf + 88) = shift16(flip16(ptpClock->parent_variance), 1);
+ *(Integer32*)(buf + 92) = shift8(ptpClock->parent_stats, 3);
+ *(Integer32*)(buf + 96) = shift16(flip16(ptpClock->observed_variance), 1);
+ *(Integer32*)(buf + 100) = flip32(ptpClock->observed_drift);
+ *(Integer32*)(buf + 104) = shift8(ptpClock->utc_reasonable, 3);
+ *(Integer32*)(buf + 108) = shift8(ptpClock->grandmaster_communication_technology, 3);
+ memcpy(buf + 112, ptpClock->grandmaster_uuid_field, 6);
+ *(Integer32*)(buf + 120) = shift16(flip16(ptpClock->grandmaster_port_id_field), 1);
+ *(Integer32*)(buf + 124) = shift8(ptpClock->grandmaster_stratum, 3);
+ memcpy(buf + 128, ptpClock->grandmaster_identifier, 4);
+ *(Integer32*)(buf + 132) = shift16(flip16(ptpClock->grandmaster_variance), 1);
+ *(Integer32*)(buf + 136) = shift8(ptpClock->grandmaster_preferred, 3);
+ *(Integer32*)(buf + 140) = shift8(ptpClock->grandmaster_is_boundary_clock, 3);
+ *(Integer32*)(buf + 144) = shift16(flip16(ptpClock->grandmaster_sequence_number), 1);
+ return 148;
+
+ case PTP_MM_GET_PORT_DATA_SET:
+ if(manage->targetPortId && manage->targetPortId != ptpClock->port_id_field)
+ {
+ *(UInteger8*)(buf + 55) = PTP_MM_NULL;
+ *(Integer32*)(buf + 56) = shift16(flip16(0), 1);
+ return 0;
+ }
+
+ *(UInteger8*)(buf + 55) = PTP_MM_PORT_DATA_SET;
+ *(Integer32*)(buf + 56) = shift16(flip16(52), 1);
+ *(Integer32*)(buf + 60) = shift16(flip16(ptpClock->port_id_field), 1);
+ *(Integer32*)(buf + 64) = shift8(ptpClock->port_state, 3);
+ *(Integer32*)(buf + 68) = shift16(flip16(ptpClock->last_sync_event_sequence_number), 1);
+ *(Integer32*)(buf + 72) = shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(Integer32*)(buf + 76) = shift8(ptpClock->port_communication_technology, 3);
+ memcpy(buf + 80, ptpClock->port_uuid_field, 6);
+ *(Integer32*)(buf + 88) = shift16(flip16(ptpClock->port_id_field), 1);
+ *(Integer32*)(buf + 92) = shift8(ptpClock->burst_enabled, 3);
+ *(Integer32*)(buf + 96) = shift8(4, 1) | shift8(2, 2) | shift8(2, 3);
+ memcpy(buf + 100, ptpClock->subdomain_address, 4);
+ memcpy(buf + 106, ptpClock->event_port_address, 2);
+ memcpy(buf + 110, ptpClock->general_port_address, 2);
+ return 112;
+
+ case PTP_MM_GET_GLOBAL_TIME_DATA_SET:
+ *(UInteger8*)(buf + 55) = PTP_MM_GLOBAL_TIME_DATA_SET;
+ *(Integer32*)(buf + 56) = shift16(flip16(24), 1);
+
+ getTime(&internalTime);
+ fromInternalTime(&internalTime, &externalTime, ptpClock->halfEpoch);
+ *(Integer32*)(buf + 60) = flip32(externalTime.seconds);
+ *(Integer32*)(buf + 64) = flip32(externalTime.nanoseconds);
+
+ *(Integer32*)(buf + 68) = shift16(flip16(ptpClock->current_utc_offset), 1);
+ *(Integer32*)(buf + 72) = shift8(ptpClock->leap_59, 3);
+ *(Integer32*)(buf + 76) = shift8(ptpClock->leap_61, 3);
+ *(Integer32*)(buf + 80) = shift16(flip16(ptpClock->epoch_number), 1);
+ return 84;
+
+ case PTP_MM_GET_FOREIGN_DATA_SET:
+ if((manage->targetPortId && manage->targetPortId != ptpClock->port_id_field)
+ || !manage->recordKey || manage->recordKey > ptpClock->number_foreign_records)
+ {
+ *(UInteger8*)(buf + 55) = PTP_MM_NULL;
+ *(Integer32*)(buf + 56) = shift16(flip16(0), 1);
+ return 0;
+ }
+
+ *(UInteger8*)(buf + 55) = PTP_MM_FOREIGN_DATA_SET;
+ *(Integer32*)(buf + 56) = shift16(flip16(28), 1);
+ *(Integer32*)(buf + 60) = shift16(flip16(ptpClock->port_id_field), 1);
+ *(Integer32*)(buf + 64) = shift16(flip16(manage->recordKey - 1), 1);
+ *(Integer32*)(buf + 68) = shift8(ptpClock->foreign[manage->recordKey - 1].foreign_master_communication_technology, 3);
+ memcpy(buf + 72, ptpClock->foreign[manage->recordKey - 1].foreign_master_uuid, 6);
+ *(Integer32*)(buf + 80) = shift16(flip16(ptpClock->foreign[manage->recordKey - 1].foreign_master_port_id), 1);
+ *(Integer32*)(buf + 84) = shift16(flip16(ptpClock->foreign[manage->recordKey - 1].foreign_master_syncs), 1);
+ return 88;
+
+ default:
+ return 0;
+ }
+}
diff --git a/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_net.c b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_net.c new file mode 100644 index 0000000..5826ebc --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_net.c @@ -0,0 +1,401 @@ +/* net.c */
+
+#include "utils/lwiplib.h"
+#include "utils/ptpdlib.h"
+#include "lwip/inet.h"
+
+/* Network Buffer Queue Functions. */
+static void netQInit(BufQueue *pQ)
+{
+ pQ->get = 0;
+ pQ->put = 0;
+ pQ->count = 0;
+}
+
+static Integer32 netQPut(BufQueue *pQ, void *pbuf)
+{
+ if(pQ->count >= PBUF_QUEUE_SIZE)
+ return FALSE;
+ pQ->pbuf[pQ->put] = pbuf;
+ pQ->put = (pQ->put + 1) % PBUF_QUEUE_SIZE;
+ pQ->count++;
+ return TRUE;
+}
+
+void *netQGet(BufQueue *pQ)
+{
+ void *pbuf;
+
+ if(!pQ->count)
+ return NULL;
+ pbuf = pQ->pbuf[pQ->get];
+ pQ->get = (pQ->get + 1) % PBUF_QUEUE_SIZE;
+ pQ->count--;
+ return pbuf;
+}
+
+static Integer32 netQCheck(BufQueue *pQ)
+{
+ if(!pQ->count)
+ return FALSE;
+ return TRUE;
+}
+
+/* Processing an incoming message on the Event port. */
+static void eventRecv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+ struct ip_addr *addr, u16_t port)
+{
+ NetPath *netPath = (NetPath *)arg;
+
+ /* prevent warnings about unused arguments */
+ (void)pcb; (void)addr; (void)port;
+
+ /* Place the incoming message on the Event Port QUEUE. */
+ if(!netQPut(&netPath->eventQ, p))
+ PERROR("Event Queue Full!\n");
+}
+
+/* Processing an incoming message on the Event port. */
+static void generalRecv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
+ struct ip_addr *addr, u16_t port)
+{
+ NetPath *netPath = (NetPath *)arg;
+
+ /* prevent warnings about unused arguments */
+ (void)pcb; (void)addr; (void)port;
+
+ /* Place the incoming message on the Event Port QUEUE. */
+ if(!netQPut(&netPath->generalQ, p))
+ {
+ PERROR("Event Queue Full!\n");
+ }
+}
+
+Boolean lookupSubdomainAddress(Octet *subdomainName, Octet *subdomainAddress)
+{
+ UInteger32 h;
+
+ /* set multicast group address based on subdomainName */
+ if (!memcmp(subdomainName, DEFAULT_PTP_DOMAIN_NAME, PTP_SUBDOMAIN_NAME_LENGTH))
+ memcpy(subdomainAddress, DEFAULT_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH);
+ else if(!memcmp(subdomainName, ALTERNATE_PTP_DOMAIN1_NAME, PTP_SUBDOMAIN_NAME_LENGTH))
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN1_ADDRESS, NET_ADDRESS_LENGTH);
+ else if(!memcmp(subdomainName, ALTERNATE_PTP_DOMAIN2_NAME, PTP_SUBDOMAIN_NAME_LENGTH))
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN2_ADDRESS, NET_ADDRESS_LENGTH);
+ else if(!memcmp(subdomainName, ALTERNATE_PTP_DOMAIN3_NAME, PTP_SUBDOMAIN_NAME_LENGTH))
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN3_ADDRESS, NET_ADDRESS_LENGTH);
+ else
+ {
+ h = crc_algorithm(subdomainName, PTP_SUBDOMAIN_NAME_LENGTH) % 3;
+ switch(h)
+ {
+ case 0:
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN1_ADDRESS, NET_ADDRESS_LENGTH);
+ break;
+ case 1:
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN2_ADDRESS, NET_ADDRESS_LENGTH);
+ break;
+ case 2:
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN3_ADDRESS, NET_ADDRESS_LENGTH);
+ break;
+ default:
+ ERROR("handle out of range for '%s'!\n", subdomainName);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+Boolean netInit(NetPath *netPath, RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+ int i;
+ struct in_addr netAddr;
+ char addrStr[NET_ADDRESS_LENGTH];
+
+ DBG("netInit\n");
+
+ /* Allocate tx buffer for the event port. */
+ netPath->eventTxBuf = pbuf_alloc(PBUF_TRANSPORT, PACKET_SIZE, PBUF_RAM);
+ if(netPath->eventTxBuf == NULL)
+ {
+ PERROR("Failed to allocate Event Tx Buffer\n");
+ return FALSE;
+ }
+
+ /* Allocate tx buffer for the general port. */
+ netPath->generalTxBuf = pbuf_alloc(PBUF_TRANSPORT, PACKET_SIZE, PBUF_RAM);
+ if(netPath->generalTxBuf == NULL)
+ {
+ PERROR("Failed to allocate Event Tx Buffer\n");
+ pbuf_free(netPath->eventTxBuf);
+ return FALSE;
+ }
+
+ /* Open lwIP raw udp interfaces for the event port. */
+ netPath->eventPcb = udp_new();
+ if(netPath->eventPcb == NULL)
+ {
+ PERROR("Failed to open Event UDP PCB\n");
+ pbuf_free(netPath->eventTxBuf);
+ pbuf_free(netPath->generalTxBuf);
+ return FALSE;
+ }
+
+ /* Open lwIP raw udp interfaces for the general port. */
+ netPath->generalPcb = udp_new();
+ if(netPath->generalPcb == NULL)
+ {
+ PERROR("Failed to open General UDP PCB\n");
+ udp_remove(netPath->eventPcb);
+ pbuf_free(netPath->eventTxBuf);
+ pbuf_free(netPath->generalTxBuf);
+ return FALSE;
+ }
+
+ /* Initialize the buffer queues. */
+ netQInit(&netPath->eventQ);
+ netQInit(&netPath->generalQ);
+
+ /* Configure network (broadcast/unicast) addresses. */
+ netPath->unicastAddr = 0;
+ if(!lookupSubdomainAddress(rtOpts->subdomainName, addrStr))
+ {
+ udp_disconnect(netPath->eventPcb);
+ udp_disconnect(netPath->generalPcb);
+ udp_remove(netPath->eventPcb);
+ udp_remove(netPath->generalPcb);
+ pbuf_free(netPath->eventTxBuf);
+ pbuf_free(netPath->generalTxBuf);
+ return FALSE;
+ }
+ if(!inet_aton(addrStr, &netAddr))
+ {
+ ERROR("failed to encode multi-cast address: %s\n", addrStr);
+ udp_disconnect(netPath->eventPcb);
+ udp_disconnect(netPath->generalPcb);
+ udp_remove(netPath->eventPcb);
+ udp_remove(netPath->generalPcb);
+ pbuf_free(netPath->eventTxBuf);
+ pbuf_free(netPath->generalTxBuf);
+ return FALSE;
+ }
+ netPath->multicastAddr = netAddr.s_addr;
+
+ /* Setup subdomain address string. */
+ for(i = 0; i < SUBDOMAIN_ADDRESS_LENGTH; ++i)
+ {
+ ptpClock->subdomain_address[i] = (netAddr.s_addr >> (i * 8)) & 0xff;
+ }
+
+ /* Establish the appropriate UDP bindings/connections for events. */
+
+ udp_recv(netPath->eventPcb, eventRecv, netPath);
+ udp_bind(netPath->eventPcb, IP_ADDR_ANY, PTP_EVENT_PORT);
+// udp_connect(netPath->eventPcb, IP_ADDR_ANY, PTP_EVENT_PORT);
+ *(Integer16*)ptpClock->event_port_address = PTP_EVENT_PORT;
+
+ /* Establish the appropriate UDP bindings/connections for general. */
+ udp_recv(netPath->generalPcb, generalRecv, netPath);
+ udp_bind(netPath->generalPcb, IP_ADDR_ANY, PTP_GENERAL_PORT);
+// udp_connect(netPath->generalPcb, IP_ADDR_ANY, PTP_GENERAL_PORT);
+ *(Integer16*)ptpClock->general_port_address = PTP_GENERAL_PORT;
+
+ /* Return a success code. */
+ return TRUE;
+}
+
+/* shut down the UDP stuff */
+Boolean netShutdown(NetPath *netPath)
+{
+ /* Disconnect and close the Event UDP interface */
+ if(netPath->eventPcb)
+ {
+ udp_disconnect(netPath->eventPcb);
+ udp_remove(netPath->eventPcb);
+ }
+
+ /* Disconnect and close the General UDP interface */
+ if(netPath->generalPcb)
+ {
+ udp_disconnect(netPath->generalPcb);
+ udp_remove(netPath->generalPcb);
+ }
+
+ /* Free up the Event and General Tx PBUFs. */
+ if(netPath->eventTxBuf)
+ {
+ pbuf_free(netPath->eventTxBuf);
+ }
+ if(netPath->generalTxBuf)
+ {
+ pbuf_free(netPath->generalTxBuf);
+ }
+
+ /* Clear the network addresses. */
+ netPath->multicastAddr = 0;
+ netPath->unicastAddr = 0;
+
+ /* Return a success code. */
+ return TRUE;
+}
+
+/* Wait for a packet to come in on either port. For now, there is no wait.
+ * Simply check to see if a packet is available on either port and return 1,
+ * otherwise return 0. */
+int netSelect(TimeInternal *timeout, NetPath *netPath)
+{
+ /* Check the packet queues. If there is data, return TRUE. */
+ if(netQCheck(&netPath->eventQ) || netQCheck(&netPath->generalQ))
+ return 1;
+ return 0;
+}
+
+/* Pop a message off of the event queue and copy it to the passed in buffer. */
+size_t netRecvEvent(Octet *buf, TimeInternal *time, NetPath *netPath)
+{
+ int i, j;
+ int iPacketSize;
+ struct pbuf *p, *pcopy;
+
+ /* Attempt to get a buffer from the Q. If none is available,
+ * return length of 0. */
+
+ p = netQGet(&netPath->eventQ);
+ if(p == NULL)
+ return 0;
+ pcopy = p;
+
+
+ /* Here, p points to a valid PBUF structure. Verify that we have
+ * enough space to store the contents. */
+ if(p->tot_len > PACKET_SIZE)
+ {
+ ERROR("received truncated message\n");
+ return 0;
+ }
+
+ /* Copy the PBUF payload into the buffer. */
+ j = 0;
+ iPacketSize = p->tot_len;
+ for(i = 0; i < iPacketSize; i++)
+ {
+ buf[i] = ((u8_t *)pcopy->payload)[j++];
+ if(j == pcopy->len)
+ {
+ pcopy = pcopy->next;
+ j = 0;
+ }
+ }
+
+ /* Get the timestamp information. */
+ time->seconds = p->time_s;
+ time->nanoseconds = p->time_ns;
+
+ /* Free up the pbuf (chain). */
+ pbuf_free(p);
+
+ /* Return the length of data copied. */
+ return iPacketSize;
+}
+
+/* Pop a message off of the general queue and copy to the passed in buffer. */
+size_t netRecvGeneral(Octet *buf, NetPath *netPath)
+{
+ int i, j;
+ int iPacketSize;
+ struct pbuf *p, *pcopy;
+
+
+ /* Attempt to get a buffer from the Q. If none is available,
+ * return length of 0. */
+ p = netQGet(&netPath->generalQ);
+ if(p == NULL)
+ return 0;
+ pcopy = p;
+
+ /* Here, p points to a valid PBUF structure. Verify that we have
+ * enough space to store the contents. */
+ if(p->tot_len > PACKET_SIZE)
+ {
+ ERROR("received truncated message\n");
+ return 0;
+ }
+
+ /* Copy the PBUF payload into the buffer. */
+ j = 0;
+ iPacketSize = p->tot_len;
+ for(i = 0; i < iPacketSize; i++)
+ {
+ buf[i] = ((u8_t *)pcopy->payload)[j++];
+ if(j == pcopy->len)
+ {
+ pcopy = pcopy->next;
+ j = 0;
+ }
+ }
+
+ /* Free up the pbuf (chain). */
+ pbuf_free(p);
+
+ /* Return the length of data copied. */
+ return iPacketSize;
+}
+
+/* Transmit a packet on the Event Port. */
+size_t netSendEvent(Octet *buf, UInteger16 length, NetPath *netPath)
+{
+ int i, j;
+ struct pbuf *pcopy;
+
+ /* Reallocate the tx pbuf based on the current size. */
+ pbuf_realloc(netPath->eventTxBuf, length);
+ pcopy = netPath->eventTxBuf;
+
+ /* Copy the incoming data into the pbuf payload. */
+ j = 0;
+ for(i = 0; i < length; i++)
+ {
+ ((u8_t *)pcopy->payload)[j++] = buf[i];
+ if(j == pcopy->len)
+ {
+ pcopy = pcopy->next;
+ j = 0;
+ }
+ }
+
+ /* send the buffer. */
+ udp_sendto(netPath->eventPcb, netPath->eventTxBuf,
+ (void *)&netPath->multicastAddr, PTP_EVENT_PORT);
+
+ return(length);
+}
+
+/* Transmit a packet on the General Port. */
+size_t netSendGeneral(Octet *buf, UInteger16 length, NetPath *netPath)
+{
+ int i, j;
+ struct pbuf *pcopy;
+
+ /* Reallocate the tx pbuf based on the current size. */
+ pbuf_realloc(netPath->generalTxBuf, length);
+ pcopy = netPath->generalTxBuf;
+
+ /* Copy the incoming data into the pbuf payload. */
+ j = 0;
+ for(i = 0; i < length; i++)
+ {
+ ((u8_t *)pcopy->payload)[j++] = buf[i];
+ if(j == pcopy->len)
+ {
+ pcopy = pcopy->next;
+ j = 0;
+ }
+ }
+
+ /* send the buffer. */
+ udp_sendto(netPath->eventPcb, netPath->generalTxBuf,
+ (void *)&netPath->multicastAddr, PTP_GENERAL_PORT);
+
+ return(length);
+}
diff --git a/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_servo.c b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_servo.c new file mode 100644 index 0000000..c6a3eae --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_servo.c @@ -0,0 +1,179 @@ +/* ptpd_servo.c */
+
+#include "../ptpd.h"
+
+void initClock(RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+ DBG("initClock\n");
+
+ /* clear vars */
+ ptpClock->master_to_slave_delay.seconds = ptpClock->master_to_slave_delay.nanoseconds = 0;
+ ptpClock->slave_to_master_delay.seconds = ptpClock->slave_to_master_delay.nanoseconds = 0;
+ ptpClock->observed_variance = 0;
+ ptpClock->observed_drift = 0; /* clears clock servo accumulator (the I term) */
+ ptpClock->owd_filt.s_exp = 0; /* clears one-way delay filter */
+ ptpClock->halfEpoch = ptpClock->halfEpoch || rtOpts->halfEpoch;
+ rtOpts->halfEpoch = 0;
+
+ rtOpts->ai = DEFAULT_AI;
+ rtOpts->ap = DEFAULT_AP;
+
+ /* level clock */
+ if(!rtOpts->noAdjust)
+ adjFreq(0);
+}
+
+void updateDelay(TimeInternal *send_time, TimeInternal *recv_time,
+ one_way_delay_filter *owd_filt, RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+ Integer16 s;
+
+ DBGV("updateDelay\n");
+
+ /* calc 'slave_to_master_delay' */
+ subTime(&ptpClock->slave_to_master_delay, recv_time, send_time);
+
+ /* update 'one_way_delay' */
+ addTime(&ptpClock->one_way_delay, &ptpClock->master_to_slave_delay, &ptpClock->slave_to_master_delay);
+
+ //
+ // TODO: This looks wrong. If seconds is odd, surely we need to add half
+ // a second's worth of nanoseconds to the result? I'm assuming that
+ // these two lines intend to divide the one_way_delay as a whole by 2.
+ //
+ ptpClock->one_way_delay.seconds /= 2;
+ ptpClock->one_way_delay.nanoseconds /= 2;
+
+ if(ptpClock->one_way_delay.seconds)
+ {
+ /* cannot filter with secs, clear filter */
+ owd_filt->s_exp = owd_filt->nsec_prev = 0;
+ return;
+ }
+
+ /* avoid overflowing filter */
+ s = rtOpts->s;
+ while(labs(owd_filt->y)>>(31-s))
+ --s;
+
+ /* crank down filter cutoff by increasing 's_exp' */
+ if(owd_filt->s_exp < 1)
+ owd_filt->s_exp = 1;
+ else if(owd_filt->s_exp < 1<<s)
+ ++owd_filt->s_exp;
+ else if(owd_filt->s_exp > 1<<s)
+ owd_filt->s_exp = 1<<s;
+
+ /* filter 'one_way_delay' */
+ owd_filt->y = (owd_filt->s_exp-1)*owd_filt->y/owd_filt->s_exp +
+ (ptpClock->one_way_delay.nanoseconds/2 + owd_filt->nsec_prev/2)/owd_filt->s_exp;
+
+ owd_filt->nsec_prev = ptpClock->one_way_delay.nanoseconds;
+ ptpClock->one_way_delay.nanoseconds = owd_filt->y;
+
+ DBG("delay filter %d, %d\n", owd_filt->y, owd_filt->s_exp);
+}
+
+void updateOffset(TimeInternal *send_time, TimeInternal *recv_time,
+ offset_from_master_filter *ofm_filt, RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+ DBGV("updateOffset\n");
+
+ /* calc 'master_to_slave_delay' */
+ subTime(&ptpClock->master_to_slave_delay, recv_time, send_time);
+
+ /* update 'offset_from_master' */
+ subTime(&ptpClock->offset_from_master, &ptpClock->master_to_slave_delay, &ptpClock->one_way_delay);
+
+ if(ptpClock->offset_from_master.seconds)
+ {
+ /* cannot filter with secs, clear filter */
+ ofm_filt->nsec_prev = 0;
+ return;
+ }
+
+ /* filter 'offset_from_master' */
+ ofm_filt->y = ptpClock->offset_from_master.nanoseconds/2 + ofm_filt->nsec_prev/2;
+ ofm_filt->nsec_prev = ptpClock->offset_from_master.nanoseconds;
+ ptpClock->offset_from_master.nanoseconds = ofm_filt->y;
+
+ DBGV("offset filter %d\n", ofm_filt->y);
+}
+
+void updateClock(RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+ Integer32 adj;
+ TimeInternal timeTmp;
+ static unsigned long ulCount = 0;
+
+ DBGV("updateClock\n");
+
+ if(ptpClock->offset_from_master.seconds)
+ {
+ /* if secs, reset clock or set freq adjustment to max */
+ if(!rtOpts->noAdjust)
+ {
+ if(!rtOpts->noResetClock)
+ {
+ getTime(&timeTmp);
+ subTime(&timeTmp, &timeTmp, &ptpClock->offset_from_master);
+ setTime(&timeTmp);
+ initClock(rtOpts, ptpClock);
+ }
+ else
+ {
+ adj = ptpClock->offset_from_master.nanoseconds > 0 ? ADJ_MAX : -ADJ_MAX;
+ adjFreq(-adj);
+ }
+ }
+ }
+ else
+ {
+ /* the PI controller */
+
+ /* no negative or zero attenuation */
+ if(rtOpts->ap < 1)
+ rtOpts->ap = 1;
+ if(rtOpts->ai < 1)
+ rtOpts->ai = 1;
+
+ /* adjust the filter components each time, till we reach the max */
+ ulCount++;
+ if(!ulCount % 2)
+ {
+ rtOpts->ai++;
+ if(rtOpts->ai > MAX_AI)
+ {
+ rtOpts->ai = MAX_AI;
+ }
+ rtOpts->ap = rtOpts->ai / 100;
+ if(rtOpts->ap < DEFAULT_AP)
+ {
+ rtOpts->ap = DEFAULT_AP;
+ }
+ }
+
+ /* the accumulator for the I component */
+ ptpClock->observed_drift += ptpClock->offset_from_master.nanoseconds/rtOpts->ai;
+
+ adj = ptpClock->offset_from_master.nanoseconds/rtOpts->ap + ptpClock->observed_drift;
+
+ /* apply controller output as a clock tick rate adjustment */
+ if(!rtOpts->noAdjust)
+ adjFreq(-adj);
+ }
+
+ if(rtOpts->displayStats)
+ displayStats(rtOpts, ptpClock);
+
+ DBGV("master-to-slave delay: %10ds %11dns\n",
+ ptpClock->master_to_slave_delay.seconds, ptpClock->master_to_slave_delay.nanoseconds);
+ DBGV("slave-to-master delay: %10ds %11dns\n",
+ ptpClock->slave_to_master_delay.seconds, ptpClock->slave_to_master_delay.nanoseconds);
+ DBGV("one-way delay: %10ds %11dns\n",
+ ptpClock->one_way_delay.seconds, ptpClock->one_way_delay.nanoseconds);
+ DBG("offset from master: %10ds %11dns\n",
+ ptpClock->offset_from_master.seconds, ptpClock->offset_from_master.nanoseconds);
+ DBG("observed drift: %10d\n", ptpClock->observed_drift);
+}
+
diff --git a/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_timer.c b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_timer.c new file mode 100644 index 0000000..47b0bb5 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep-tiva/ptpd_timer.c @@ -0,0 +1,75 @@ +/* ptpd_timer.c */
+
+#include "../ptpd.h"
+
+static int iElapsedMilliSeconds = 0;
+
+void initTimer(void)
+{
+ DBG("initTimer\n");
+
+ iElapsedMilliSeconds = 0;
+}
+
+void timerTick(int iTickMilliSeconds)
+{
+ iElapsedMilliSeconds += iTickMilliSeconds;
+}
+
+void timerUpdate(IntervalTimer *itimer)
+{
+ int i, delta;
+
+ delta = iElapsedMilliSeconds / 1000;
+
+ if(delta <= 0)
+ return;
+
+ iElapsedMilliSeconds %= 1000;
+
+ for(i = 0; i < TIMER_ARRAY_SIZE; ++i)
+ {
+ if(itimer[i].interval > 0 && (itimer[i].left -= delta) <= 0)
+ {
+ itimer[i].left = itimer[i].interval;
+ itimer[i].expire = TRUE;
+ DBGV("timerUpdate: timer %u expired\n", i);
+ }
+ }
+}
+
+void timerStop(UInteger16 index, IntervalTimer *itimer)
+{
+ if(index >= TIMER_ARRAY_SIZE)
+ return;
+
+ itimer[index].interval = 0;
+}
+
+void timerStart(UInteger16 index, UInteger16 interval, IntervalTimer *itimer)
+{
+ if(index >= TIMER_ARRAY_SIZE)
+ return;
+
+ itimer[index].expire = FALSE;
+ itimer[index].left = interval;
+ itimer[index].interval = itimer[index].left;
+
+ DBGV("timerStart: set timer %d to %d\n", index, interval);
+}
+
+Boolean timerExpired(UInteger16 index, IntervalTimer *itimer)
+{
+ timerUpdate(itimer);
+
+ if(index >= TIMER_ARRAY_SIZE)
+ return FALSE;
+
+ if(!itimer[index].expire)
+ return FALSE;
+
+ itimer[index].expire = FALSE;
+
+ return TRUE;
+}
+
diff --git a/third_party/ptpd-1.1.0/src/dep/constants_dep.h b/third_party/ptpd-1.1.0/src/dep/constants_dep.h new file mode 100644 index 0000000..54afaf1 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep/constants_dep.h @@ -0,0 +1,99 @@ +/**
+ * @file constants_dep.h
+ * @date Tue Jul 20 16:16:23 2010
+ *
+ * @brief Platform dependent constants
+ *
+ *
+ */
+
+#ifndef CONSTANTS_DEP_H
+#define CONSTANTS_DEP_H
+
+#include <limits.h>
+
+#if !defined(linux) && !defined(__NetBSD__) && !defined(__FreeBSD__)
+#error Not ported to this architecture, please update.
+#endif
+
+#ifdef linux
+#include<netinet/in.h>
+#include<net/if.h>
+#include<net/if_arp.h>
+#define IFACE_NAME_LENGTH IF_NAMESIZE
+#define NET_ADDRESS_LENGTH INET_ADDRSTRLEN
+
+#define IFCONF_LENGTH 10
+
+#include<endian.h>
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define PTPD_LSBF
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define PTPD_MSBF
+#endif
+#endif /* linux */
+
+
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#if defined(__FreeBSD__)
+#include <net/ethernet.h>
+#include <sys/uio.h>
+#else
+#include <net/if_ether.h>
+#endif
+#include <ifaddrs.h>
+#define IFACE_NAME_LENGTH IF_NAMESIZE
+#define NET_ADDRESS_LENGTH INET_ADDRSTRLEN
+
+#define IFCONF_LENGTH 10
+
+#define adjtimex ntp_adjtime
+
+#include <machine/endian.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define PTPD_LSBF
+#elif BYTE_ORDER == BIG_ENDIAN
+#define PTPD_MSBF
+#endif
+#endif
+
+
+#define ADJ_FREQ_MAX 512000
+
+/* UDP/IPv4 dependent */
+
+#define SUBDOMAIN_ADDRESS_LENGTH 4
+#define PORT_ADDRESS_LENGTH 2
+
+#define PACKET_SIZE 300
+
+#define PTP_EVENT_PORT 319
+#define PTP_GENERAL_PORT 320
+
+#define DEFAULT_PTP_DOMAIN_ADDRESS "224.0.1.129"
+#define ALTERNATE_PTP_DOMAIN1_ADDRESS "224.0.1.130"
+#define ALTERNATE_PTP_DOMAIN2_ADDRESS "224.0.1.131"
+#define ALTERNATE_PTP_DOMAIN3_ADDRESS "224.0.1.132"
+
+#define HEADER_LENGTH 40
+#define SYNC_PACKET_LENGTH 124
+#define DELAY_REQ_PACKET_LENGTH 124
+#define FOLLOW_UP_PACKET_LENGTH 52
+#define DELAY_RESP_PACKET_LENGTH 60
+#define MANAGEMENT_PACKET_LENGTH 136
+
+#define MM_STARTING_BOUNDARY_HOPS 0x7fff
+
+/* others */
+
+#define SCREEN_BUFSZ 128
+#define SCREEN_MAXSZ 80
+
+#define MAXTIMESTR 32
+#endif
diff --git a/third_party/ptpd-1.1.0/src/dep/datatypes_dep.h b/third_party/ptpd-1.1.0/src/dep/datatypes_dep.h new file mode 100644 index 0000000..b105130 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep/datatypes_dep.h @@ -0,0 +1,37 @@ +/**
+ * @file datatypes_dep.h
+ * @date Tue Jul 20 16:16:48 2010
+ *
+ * @brief Platform dependent datatypes.
+ *
+ *
+ */
+
+#ifndef DATATYPES_DEP_H
+#define DATATYPES_DEP_H
+
+typedef enum {
+ FALSE = 0, TRUE
+} Boolean;
+typedef char Octet;
+typedef signed char Integer8;
+typedef signed short Integer16;
+typedef signed int Integer32;
+typedef unsigned char UInteger8;
+typedef unsigned short UInteger16;
+typedef unsigned int UInteger32;
+
+typedef struct {
+ Integer32 nsec_prev, y;
+} offset_from_master_filter;
+
+typedef struct {
+ Integer32 nsec_prev, y;
+ Integer32 s_exp;
+} one_way_delay_filter;
+
+typedef struct {
+ Integer32 eventSock, generalSock, multicastAddr, unicastAddr;
+} NetPath;
+
+#endif
diff --git a/third_party/ptpd-1.1.0/src/dep/msg.c b/third_party/ptpd-1.1.0/src/dep/msg.c new file mode 100644 index 0000000..cd2dbb9 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep/msg.c @@ -0,0 +1,671 @@ +/**
+ * @file msg.c
+ * @author George Neville-Neil <gnn@neville-neil.com>
+ * @date Tue Jul 20 16:17:05 2010
+ *
+ * @brief Functions to pack and unpack messages.
+ *
+ * See spec annex d
+ */
+
+
+#include "../ptpd.h"
+
+Boolean
+msgPeek(void *buf, ssize_t length)
+{
+ /* not imlpemented yet */
+ return TRUE;
+}
+
+void
+msgUnpackHeader(void *buf, MsgHeader * header)
+{
+ header->versionPTP = flip16(*(UInteger16 *) (buf + 0));
+ header->versionNetwork = flip16(*(UInteger16 *) (buf + 2));
+ DBGV("msgUnpackHeader: versionPTP %d\n", header->versionPTP);
+ DBGV("msgUnpackHeader: versionNetwork %d\n", header->versionNetwork);
+
+ memcpy(header->subdomain, (buf + 4), 16);
+ DBGV("msgUnpackHeader: subdomain %s\n", header->subdomain);
+
+ header->messageType = *(UInteger8 *) (buf + 20);
+ header->sourceCommunicationTechnology = *(UInteger8 *) (buf + 21);
+ DBGV("msgUnpackHeader: messageType %d\n", header->messageType);
+ DBGV("msgUnpackHeader: sourceCommunicationTechnology %d\n", header->sourceCommunicationTechnology);
+
+ memcpy(header->sourceUuid, (buf + 22), 6);
+ DBGV("msgUnpackHeader: sourceUuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ header->sourceUuid[0], header->sourceUuid[1], header->sourceUuid[2],
+ header->sourceUuid[3], header->sourceUuid[4], header->sourceUuid[5]);
+
+ header->sourcePortId = flip16(*(UInteger16 *) (buf + 28));
+ header->sequenceId = flip16(*(UInteger16 *) (buf + 30));
+ DBGV("msgUnpackHeader: sourcePortId %d\n", header->sourcePortId);
+ DBGV("msgUnpackHeader: sequenceId %d\n", header->sequenceId);
+
+ header->control = *(UInteger8 *) (buf + 32);
+ DBGV("msgUnpackHeader: control %d\n", header->control);
+
+ memcpy(header->flags, (buf + 34), 2);
+ DBGV("msgUnpackHeader: flags %02hhx %02hhx\n", header->flags[0], header->flags[1]);
+}
+
+void
+msgUnpackSync(void *buf, MsgSync * sync)
+{
+ sync->originTimestamp.seconds = flip32(*(UInteger32 *) (buf + 40));
+ DBGV("msgUnpackSync: originTimestamp.seconds %u\n", sync->originTimestamp.seconds);
+ sync->originTimestamp.nanoseconds = flip32(*(Integer32 *) (buf + 44));
+ DBGV("msgUnpackSync: originTimestamp.nanoseconds %d\n", sync->originTimestamp.nanoseconds);
+ sync->epochNumber = flip16(*(UInteger16 *) (buf + 48));
+ DBGV("msgUnpackSync: epochNumber %d\n", sync->epochNumber);
+ sync->currentUTCOffset = flip16(*(Integer16 *) (buf + 50));
+ DBGV("msgUnpackSync: currentUTCOffset %d\n", sync->currentUTCOffset);
+ sync->grandmasterCommunicationTechnology = *(UInteger8 *) (buf + 53);
+ DBGV("msgUnpackSync: grandmasterCommunicationTechnology %d\n", sync->grandmasterCommunicationTechnology);
+ memcpy(sync->grandmasterClockUuid, (buf + 54), 6);
+ DBGV("msgUnpackSync: grandmasterClockUuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ sync->grandmasterClockUuid[0], sync->grandmasterClockUuid[1], sync->grandmasterClockUuid[2],
+ sync->grandmasterClockUuid[3], sync->grandmasterClockUuid[4], sync->grandmasterClockUuid[5]);
+ sync->grandmasterPortId = flip16(*(UInteger16 *) (buf + 60));
+ DBGV("msgUnpackSync: grandmasterPortId %d\n", sync->grandmasterPortId);
+ sync->grandmasterSequenceId = flip16(*(UInteger16 *) (buf + 62));
+ DBGV("msgUnpackSync: grandmasterSequenceId %d\n", sync->grandmasterSequenceId);
+ sync->grandmasterClockStratum = *(UInteger8 *) (buf + 67);
+ DBGV("msgUnpackSync: grandmasterClockStratum %d\n", sync->grandmasterClockStratum);
+ memcpy(sync->grandmasterClockIdentifier, (buf + 68), 4);
+ DBGV("msgUnpackSync: grandmasterClockIdentifier %c%c%c%c\n",
+ sync->grandmasterClockIdentifier[0], sync->grandmasterClockIdentifier[1],
+ sync->grandmasterClockIdentifier[2], sync->grandmasterClockIdentifier[3]);
+ sync->grandmasterClockVariance = flip16(*(Integer16 *) (buf + 74));
+ DBGV("msgUnpackSync: grandmasterClockVariance %d\n", sync->grandmasterClockVariance);
+ sync->grandmasterPreferred = *(UInteger8 *) (buf + 77);
+ DBGV("msgUnpackSync: grandmasterPreferred %d\n", sync->grandmasterPreferred);
+ sync->grandmasterIsBoundaryClock = *(UInteger8 *) (buf + 79);
+ DBGV("msgUnpackSync: grandmasterIsBoundaryClock %d\n", sync->grandmasterIsBoundaryClock);
+ sync->syncInterval = *(Integer8 *) (buf + 83);
+ DBGV("msgUnpackSync: syncInterval %d\n", sync->syncInterval);
+ sync->localClockVariance = flip16(*(Integer16 *) (buf + 86));
+ DBGV("msgUnpackSync: localClockVariance %d\n", sync->localClockVariance);
+ sync->localStepsRemoved = flip16(*(UInteger16 *) (buf + 90));
+ DBGV("msgUnpackSync: localStepsRemoved %d\n", sync->localStepsRemoved);
+ sync->localClockStratum = *(UInteger8 *) (buf + 95);
+ DBGV("msgUnpackSync: localClockStratum %d\n", sync->localClockStratum);
+ memcpy(sync->localClockIdentifer, (buf + 96), PTP_CODE_STRING_LENGTH);
+ DBGV("msgUnpackSync: localClockIdentifer %c%c%c%c\n",
+ sync->localClockIdentifer[0], sync->localClockIdentifer[1],
+ sync->localClockIdentifer[2], sync->localClockIdentifer[3]);
+ sync->parentCommunicationTechnology = *(UInteger8 *) (buf + 101);
+ DBGV("msgUnpackSync: parentCommunicationTechnology %d\n", sync->parentCommunicationTechnology);
+ memcpy(sync->parentUuid, (buf + 102), PTP_UUID_LENGTH);
+ DBGV("msgUnpackSync: parentUuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ sync->parentUuid[0], sync->parentUuid[1], sync->parentUuid[2],
+ sync->parentUuid[3], sync->parentUuid[4], sync->parentUuid[5]);
+ sync->parentPortField = flip16(*(UInteger16 *) (buf + 110));
+ DBGV("msgUnpackSync: parentPortField %d\n", sync->parentPortField);
+ sync->estimatedMasterVariance = flip16(*(Integer16 *) (buf + 114));
+ DBGV("msgUnpackSync: estimatedMasterVariance %d\n", sync->estimatedMasterVariance);
+ sync->estimatedMasterDrift = flip32(*(Integer32 *) (buf + 116));
+ DBGV("msgUnpackSync: estimatedMasterDrift %d\n", sync->estimatedMasterDrift);
+ sync->utcReasonable = *(UInteger8 *) (buf + 123);
+ DBGV("msgUnpackSync: utcReasonable %d\n", sync->utcReasonable);
+}
+
+void
+msgUnpackDelayReq(void *buf, MsgDelayReq * req)
+{
+}
+
+void
+msgUnpackFollowUp(void *buf, MsgFollowUp * follow)
+{
+ follow->associatedSequenceId = flip16(*(UInteger16 *) (buf + 42));
+ DBGV("msgUnpackFollowUp: associatedSequenceId %u\n", follow->associatedSequenceId);
+ follow->preciseOriginTimestamp.seconds = flip32(*(UInteger32 *) (buf + 44));
+ DBGV("msgUnpackFollowUp: preciseOriginTimestamp.seconds %u\n", follow->preciseOriginTimestamp.seconds);
+ follow->preciseOriginTimestamp.nanoseconds = flip32(*(Integer32 *) (buf + 48));
+ DBGV("msgUnpackFollowUp: preciseOriginTimestamp.nanoseconds %d\n", follow->preciseOriginTimestamp.nanoseconds);
+}
+
+void
+msgUnpackDelayResp(void *buf, MsgDelayResp * resp)
+{
+ resp->delayReceiptTimestamp.seconds = flip32(*(UInteger32 *) (buf + 40));
+ DBGV("msgUnpackDelayResp: delayReceiptTimestamp.seconds %u\n", resp->delayReceiptTimestamp.seconds);
+ resp->delayReceiptTimestamp.nanoseconds = flip32(*(Integer32 *) (buf + 44));
+ DBGV("msgUnpackDelayResp: delayReceiptTimestamp.nanoseconds %d\n", resp->delayReceiptTimestamp.nanoseconds);
+ resp->requestingSourceCommunicationTechnology = *(UInteger8 *) (buf + 49);
+ DBGV("msgUnpackDelayResp: requestingSourceCommunicationTechnology %d\n", resp->requestingSourceCommunicationTechnology);
+ memcpy(resp->requestingSourceUuid, (buf + 50), 6);
+ DBGV("msgUnpackDelayResp: requestingSourceUuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ resp->requestingSourceUuid[0], resp->requestingSourceUuid[1], resp->requestingSourceUuid[2],
+ resp->requestingSourceUuid[3], resp->requestingSourceUuid[4], resp->requestingSourceUuid[5]);
+ resp->requestingSourcePortId = flip16(*(UInteger16 *) (buf + 56));
+ DBGV("msgUnpackDelayResp: requestingSourcePortId %d\n", resp->requestingSourcePortId);
+ resp->requestingSourceSequenceId = flip16(*(UInteger16 *) (buf + 58));
+ DBGV("msgUnpackDelayResp: requestingSourceSequenceId %d\n", resp->requestingSourceSequenceId);
+}
+
+void
+msgUnpackManagement(void *buf, MsgManagement * manage)
+{
+ manage->targetCommunicationTechnology = *(UInteger8 *) (buf + 41);
+ DBGV("msgUnpackManagement: targetCommunicationTechnology %d\n", manage->targetCommunicationTechnology);
+ memcpy(manage->targetUuid, (buf + 42), 6);
+ DBGV("msgUnpackManagement: targetUuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ manage->targetUuid[0], manage->targetUuid[1], manage->targetUuid[2],
+ manage->targetUuid[3], manage->targetUuid[4], manage->targetUuid[5]);
+ manage->targetPortId = flip16(*(UInteger16 *) (buf + 48));
+ DBGV("msgUnpackManagement: targetPortId %d\n", manage->targetPortId);
+ manage->startingBoundaryHops = flip16(*(Integer16 *) (buf + 50));
+ DBGV("msgUnpackManagement: startingBoundaryHops %d\n", manage->startingBoundaryHops);
+ manage->boundaryHops = flip16(*(Integer16 *) (buf + 52));
+ DBGV("msgUnpackManagement: boundaryHops %d\n", manage->boundaryHops);
+ manage->managementMessageKey = *(UInteger8 *) (buf + 55);
+ DBGV("msgUnpackManagement: managementMessageKey %d\n", manage->managementMessageKey);
+ manage->parameterLength = flip16(*(UInteger16 *) (buf + 58));
+ DBGV("msgUnpackManagement: parameterLength %d\n", manage->parameterLength);
+
+ if (manage->managementMessageKey == PTP_MM_GET_FOREIGN_DATA_SET)
+ manage->recordKey = flip16(*(UInteger16 *) (buf + 62));
+}
+
+UInteger8
+msgUnloadManagement(void *buf, MsgManagement * manage,
+ PtpClock * ptpClock, RunTimeOpts * rtOpts)
+{
+ TimeInternal internalTime;
+ TimeRepresentation externalTime;
+
+ switch (manage->managementMessageKey) {
+ case PTP_MM_INITIALIZE_CLOCK:
+ if (ptpClock->initializable)
+ return PTP_INITIALIZING;
+ break;
+
+ case PTP_MM_GOTO_FAULTY_STATE:
+ DBG("event FAULT_DETECTED (forced by management message)\n");
+ return PTP_FAULTY;
+ break;
+
+ case PTP_MM_DISABLE_PORT:
+ if (manage->targetPortId == 1) {
+ DBG("event DESIGNATED_DISABLED\n");
+ return PTP_DISABLED;
+ }
+ break;
+
+ case PTP_MM_ENABLE_PORT:
+ if (manage->targetPortId == 1) {
+ DBG("event DESIGNATED_ENABLED\n");
+ return PTP_INITIALIZING;
+ }
+ break;
+
+ case PTP_MM_CLEAR_DESIGNATED_PREFERRED_MASTER:
+ ptpClock->preferred = FALSE;
+ break;
+
+ case PTP_MM_SET_DESIGNATED_PREFERRED_MASTER:
+ ptpClock->preferred = TRUE;
+ break;
+
+ case PTP_MM_DISABLE_BURST:
+ break;
+
+ case PTP_MM_ENABLE_BURST:
+ break;
+
+ case PTP_MM_SET_SYNC_INTERVAL:
+ rtOpts->syncInterval = *(Integer8 *) (buf + 63);
+ break;
+
+ case PTP_MM_SET_SUBDOMAIN:
+ memcpy(rtOpts->subdomainName, buf + 60, 16);
+ DBG("set subdomain to %s\n", rtOpts->subdomainName);
+ break;
+
+ case PTP_MM_SET_TIME:
+ externalTime.seconds = flip32(*(UInteger32 *) (buf + 60));
+ externalTime.nanoseconds = flip32(*(Integer32 *) (buf + 64));
+ toInternalTime(&internalTime, &externalTime, &ptpClock->halfEpoch);
+ setTime(&internalTime);
+ break;
+
+ case PTP_MM_UPDATE_DEFAULT_DATA_SET:
+ if (!rtOpts->slaveOnly)
+ ptpClock->clock_stratum = *(UInteger8 *) (buf + 63);
+ memcpy(ptpClock->clock_identifier, buf + 64, 4);
+ ptpClock->clock_variance = flip16(*(Integer16 *) (buf + 70));
+ ptpClock->preferred = *(UInteger8 *) (buf + 75);
+ rtOpts->syncInterval = *(UInteger8 *) (buf + 79);
+ memcpy(rtOpts->subdomainName, buf + 80, 16);
+ break;
+
+ case PTP_MM_UPDATE_GLOBAL_TIME_PROPERTIES:
+ ptpClock->current_utc_offset = flip16(*(Integer16 *) (buf + 62));
+ ptpClock->leap_59 = *(UInteger8 *) (buf + 67);
+ ptpClock->leap_61 = *(UInteger8 *) (buf + 71);
+ ptpClock->epoch_number = flip16(*(UInteger16 *) (buf + 74));
+ break;
+
+ default:
+ break;
+ }
+
+ return ptpClock->port_state;
+}
+
+void
+msgUnpackManagementPayload(void *buf, MsgManagement * manage)
+{
+ switch (manage->managementMessageKey) {
+ case PTP_MM_CLOCK_IDENTITY:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_CLOCK_IDENTITY\n");
+ manage->payload.clockIdentity.clockCommunicationTechnology = *(UInteger8 *) (buf + 63);
+ memcpy(manage->payload.clockIdentity.clockUuidField, buf + 64, PTP_UUID_LENGTH);
+ manage->payload.clockIdentity.clockPortField = flip16(*(UInteger16 *) (buf + 74));
+ memcpy(manage->payload.clockIdentity.manufacturerIdentity, buf + 76, MANUFACTURER_ID_LENGTH);
+ break;
+
+ case PTP_MM_DEFAULT_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_DEFAULT_DATA_SET\n");
+ manage->payload.defaultData.clockCommunicationTechnology = *(UInteger8 *) (buf + 63);
+ memcpy(manage->payload.defaultData.clockUuidField, buf + 64, PTP_UUID_LENGTH);
+ manage->payload.defaultData.clockPortField = flip16(*(UInteger16 *) (buf + 74));
+ manage->payload.defaultData.clockStratum = *(UInteger16 *) (buf + 79);
+ memcpy(manage->payload.defaultData.clockIdentifier, buf + 80, PTP_CODE_STRING_LENGTH);
+ manage->payload.defaultData.clockVariance = flip16(*(UInteger16 *) (buf + 86));
+ manage->payload.defaultData.clockFollowupCapable = *(UInteger8 *) (buf + 91);
+ manage->payload.defaultData.preferred = *(UInteger8 *) (buf + 95);
+ manage->payload.defaultData.initializable = *(UInteger8 *) (buf + 99);
+ manage->payload.defaultData.externalTiming = *(UInteger8 *) (buf + 103);
+ manage->payload.defaultData.isBoundaryClock = *(UInteger8 *) (buf + 107);
+ manage->payload.defaultData.syncInterval = *(UInteger8 *) (buf + 111);
+ memcpy(manage->payload.defaultData.subdomainName, buf + 112, PTP_SUBDOMAIN_NAME_LENGTH);
+ manage->payload.defaultData.numberPorts = flip16(*(UInteger16 *) (buf + 130));
+ manage->payload.defaultData.numberForeignRecords = flip16(*(UInteger16 *) (buf + 134));
+ break;
+
+ case PTP_MM_CURRENT_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_CURRENT_DATA_SET\n");
+ manage->payload.current.stepsRemoved = flip16(*(UInteger16 *) (buf + 62));
+ manage->payload.current.offsetFromMaster.seconds = flip32(*(UInteger32 *) (buf + 64));
+ manage->payload.current.offsetFromMaster.nanoseconds = flip32(*(UInteger32 *) (buf + 68));
+ manage->payload.current.oneWayDelay.seconds = flip32(*(UInteger32 *) (buf + 72));
+ manage->payload.current.oneWayDelay.nanoseconds = flip32(*(Integer32 *) (buf + 76));
+ break;
+
+ case PTP_MM_PARENT_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_PORT_DATA_SET\n");
+ manage->payload.parent.parentCommunicationTechnology = *(UInteger8 *) (buf + 63);
+ memcpy(manage->payload.parent.parentUuid, buf + 64, PTP_UUID_LENGTH);
+ manage->payload.parent.parentPortId = flip16(*(UInteger16 *) (buf + 74));
+ manage->payload.parent.parentLastSyncSequenceNumber = flip16(*(UInteger16 *) (buf + 74));
+ manage->payload.parent.parentFollowupCapable = *(UInteger8 *) (buf + 83);
+ manage->payload.parent.parentExternalTiming = *(UInteger8 *) (buf + 87);
+ manage->payload.parent.parentVariance = flip16(*(UInteger16 *) (buf + 90));
+ manage->payload.parent.parentStats = *(UInteger8 *) (buf + 85);
+ manage->payload.parent.observedVariance = flip16(*(Integer16 *) (buf + 98));
+ manage->payload.parent.observedDrift = flip32(*(Integer32 *) (buf + 100));
+ manage->payload.parent.utcReasonable = *(UInteger8 *) (buf + 107);
+ manage->payload.parent.grandmasterCommunicationTechnology = *(UInteger8 *) (buf + 111);
+ memcpy(manage->payload.parent.grandmasterUuidField, buf + 112, PTP_UUID_LENGTH);
+ manage->payload.parent.grandmasterPortIdField = flip16(*(UInteger16 *) (buf + 122));
+ manage->payload.parent.grandmasterStratum = *(UInteger8 *) (buf + 127);
+ memcpy(manage->payload.parent.grandmasterIdentifier, buf + 128, PTP_CODE_STRING_LENGTH);
+ manage->payload.parent.grandmasterVariance = flip16(*(Integer16 *) (buf + 134));
+ manage->payload.parent.grandmasterPreferred = *(UInteger8 *) (buf + 139);
+ manage->payload.parent.grandmasterIsBoundaryClock = *(UInteger8 *) (buf + 144);
+ manage->payload.parent.grandmasterSequenceNumber = flip16(*(UInteger16 *) (buf + 146));
+ break;
+
+ case PTP_MM_PORT_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_FOREIGN_DATA_SET\n");
+ manage->payload.port.returnedPortNumber = flip16(*(UInteger16 *) (buf + 62));
+ manage->payload.port.portState = *(UInteger8 *) (buf + 67);
+ manage->payload.port.lastSyncEventSequenceNumber = flip16(*(UInteger16 *) (buf + 70));
+ manage->payload.port.lastGeneralEventSequenceNumber = flip16(*(UInteger16 *) (buf + 74));
+ manage->payload.port.portCommunicationTechnology = *(UInteger8 *) (buf + 79);
+ memcpy(manage->payload.port.portUuidField, buf + 80, PTP_UUID_LENGTH);
+ manage->payload.port.portIdField = flip16(*(UInteger16 *) (buf + 90));
+ manage->payload.port.burstEnabled = *(UInteger8 *) (buf + 95);
+ manage->payload.port.subdomainAddressOctets = *(UInteger8 *) (buf + 97);
+ manage->payload.port.eventPortAddressOctets = *(UInteger8 *) (buf + 98);
+ manage->payload.port.generalPortAddressOctets = *(UInteger8 *) (buf + 99);
+ memcpy(manage->payload.port.subdomainAddress, buf + 100, SUBDOMAIN_ADDRESS_LENGTH);
+ memcpy(manage->payload.port.eventPortAddress, buf + 106, PORT_ADDRESS_LENGTH);
+ memcpy(manage->payload.port.generalPortAddress, buf + 110, PORT_ADDRESS_LENGTH);
+ break;
+
+ case PTP_MM_GLOBAL_TIME_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_GLOBAL_TIME_DATA_SET\n");
+ manage->payload.globalTime.localTime.seconds = flip32(*(UInteger32 *) (buf + 60));
+ manage->payload.globalTime.localTime.nanoseconds = flip32(*(Integer32 *) (buf + 64));
+ manage->payload.globalTime.currentUtcOffset = flip16(*(Integer16 *) (buf + 70));
+ manage->payload.globalTime.leap59 = *(UInteger8 *) (buf + 75);
+ manage->payload.globalTime.leap61 = *(UInteger8 *) (buf + 79);
+ manage->payload.globalTime.epochNumber = flip16(*(UInteger16 *) (buf + 82));
+ break;
+
+
+ case PTP_MM_FOREIGN_DATA_SET:
+ DBGV("msgUnloadManagementPayload: managementMessageKey PTP_MM_FOREIGN_DATA_SET\n");
+ manage->payload.foreign.returnedPortNumber = flip16(*(UInteger16 *) (buf + 62));
+ manage->payload.foreign.returnedRecordNumber = flip16(*(UInteger16 *) (buf + 68));
+ manage->payload.foreign.foreignMasterCommunicationTechnology = *(UInteger8 *) (buf + 71);
+ memcpy(manage->payload.foreign.foreignMasterUuid, buf + 72, PTP_UUID_LENGTH);
+ manage->payload.foreign.foreignMasterPortId = flip16(*(UInteger16 *) (buf + 82));
+ manage->payload.foreign.foreignMasterSyncs = flip16(*(UInteger16 *) (buf + 66));
+ break;
+
+ case PTP_MM_NULL:
+ DBGV("msgUnloadManagementPayload: managementMessageKey NULL\n");
+ break;
+
+ default:
+ DBGV("msgUnloadManagementPayload: managementMessageKey ?\n");
+ break;
+ }
+
+ return;
+}
+
+void
+msgPackHeader(void *buf, PtpClock * ptpClock)
+{
+ *(Integer32 *) (buf + 0) = shift16(flip16(VERSION_PTP), 0) | shift16(flip16(VERSION_NETWORK), 1);
+ memcpy((buf + 4), ptpClock->subdomain_name, 16);
+ *(Integer32 *) (buf + 20) = shift8(ptpClock->port_communication_technology, 1);
+ memcpy((buf + 22), ptpClock->port_uuid_field, 6);
+
+ if (ptpClock->external_timing)
+ setFlag((buf + 34), PTP_EXT_SYNC);
+ if (ptpClock->clock_followup_capable)
+ setFlag((buf + 34), PTP_ASSIST);
+ if (ptpClock->is_boundary_clock)
+ setFlag((buf + 34), PTP_BOUNDARY_CLOCK);
+}
+
+void
+msgPackSync(void *buf, Boolean burst,
+ TimeRepresentation * originTimestamp, PtpClock * ptpClock)
+{
+ *(UInteger8 *) (buf + 20) = 1; /* messageType */
+ *(Integer32 *) (buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_sync_event_sequence_number), 1);
+ *(UInteger8 *) (buf + 32) = PTP_SYNC_MESSAGE; /* control */
+ if (ptpClock->burst_enabled && burst)
+ setFlag((buf + 34), PTP_SYNC_BURST);
+ else
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ if (ptpClock->parent_stats)
+ setFlag((buf + 34), PARENT_STATS);
+ else
+ clearFlag((buf + 34), PARENT_STATS);
+
+
+ *(Integer32 *) (buf + 40) = flip32(originTimestamp->seconds);
+ *(Integer32 *) (buf + 44) = flip32(originTimestamp->nanoseconds);
+ *(Integer32 *) (buf + 48) = shift16(flip16(ptpClock->epoch_number), 0) | shift16(flip16(ptpClock->current_utc_offset), 1);
+ *(Integer32 *) (buf + 52) = shift8(ptpClock->grandmaster_communication_technology, 1);
+ memcpy((buf + 54), ptpClock->grandmaster_uuid_field, 6);
+ *(Integer32 *) (buf + 60) = shift16(flip16(ptpClock->grandmaster_port_id_field), 0) | shift16(flip16(ptpClock->grandmaster_sequence_number), 1);
+ *(Integer32 *) (buf + 64) = shift8(ptpClock->grandmaster_stratum, 3);
+ memcpy((buf + 68), ptpClock->grandmaster_identifier, 4);
+ *(Integer32 *) (buf + 72) = shift16(flip16(ptpClock->grandmaster_variance), 1);
+ *(Integer32 *) (buf + 76) = shift16(flip16(ptpClock->grandmaster_preferred), 0) | shift16(flip16(ptpClock->grandmaster_is_boundary_clock), 1);
+ *(Integer32 *) (buf + 80) = shift16(flip16(ptpClock->sync_interval), 1);
+ *(Integer32 *) (buf + 84) = shift16(flip16(ptpClock->clock_variance), 1);
+ *(Integer32 *) (buf + 88) = shift16(flip16(ptpClock->steps_removed), 1);
+ *(Integer32 *) (buf + 92) = shift8(ptpClock->clock_stratum, 3);
+ memcpy((buf + 96), ptpClock->clock_identifier, 4);
+ *(Integer32 *) (buf + 100) = shift8(ptpClock->parent_communication_technology, 1);
+ memcpy((buf + 102), ptpClock->parent_uuid, 6);
+ *(Integer32 *) (buf + 108) = shift16(flip16(ptpClock->parent_port_id), 1);
+ *(Integer32 *) (buf + 112) = shift16(flip16(ptpClock->observed_variance), 1);
+ *(Integer32 *) (buf + 116) = flip32(ptpClock->observed_drift);
+ *(Integer32 *) (buf + 120) = shift8(ptpClock->utc_reasonable, 3);
+}
+
+void
+msgPackDelayReq(void *buf, Boolean burst,
+ TimeRepresentation * originTimestamp, PtpClock * ptpClock)
+{
+ *(UInteger8 *) (buf + 20) = 1; /* messageType */
+ *(Integer32 *) (buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_sync_event_sequence_number), 1);
+ *(UInteger8 *) (buf + 32) = PTP_DELAY_REQ_MESSAGE; /* control */
+ if (ptpClock->burst_enabled && burst)
+ setFlag((buf + 34), PTP_SYNC_BURST);
+ else
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ if (ptpClock->parent_stats)
+ setFlag((buf + 34), PARENT_STATS);
+ else
+ clearFlag((buf + 34), PARENT_STATS);
+
+ *(Integer32 *) (buf + 40) = flip32(originTimestamp->seconds);
+ *(Integer32 *) (buf + 44) = flip32(originTimestamp->nanoseconds);
+ *(Integer32 *) (buf + 48) = shift16(flip16(ptpClock->epoch_number), 0) | shift16(flip16(ptpClock->current_utc_offset), 1);
+ *(Integer32 *) (buf + 52) = shift8(ptpClock->grandmaster_communication_technology, 1);
+ memcpy((buf + 54), ptpClock->grandmaster_uuid_field, 6);
+ *(Integer32 *) (buf + 60) = shift16(flip16(ptpClock->grandmaster_port_id_field), 0) | shift16(flip16(ptpClock->grandmaster_sequence_number), 1);
+ *(Integer32 *) (buf + 64) = shift8(ptpClock->grandmaster_stratum, 3);
+ memcpy((buf + 68), ptpClock->grandmaster_identifier, 4);
+ *(Integer32 *) (buf + 72) = shift16(flip16(ptpClock->grandmaster_variance), 1);
+ *(Integer32 *) (buf + 76) = shift16(flip16(ptpClock->grandmaster_preferred), 0) | shift16(flip16(ptpClock->grandmaster_is_boundary_clock), 1);
+ *(Integer32 *) (buf + 80) = shift16(flip16(ptpClock->sync_interval), 1);
+ *(Integer32 *) (buf + 84) = shift16(flip16(ptpClock->clock_variance), 1);
+ *(Integer32 *) (buf + 88) = shift16(flip16(ptpClock->steps_removed), 1);
+ *(Integer32 *) (buf + 92) = shift8(ptpClock->clock_stratum, 3);
+ memcpy((buf + 96), ptpClock->clock_identifier, 4);
+ *(Integer32 *) (buf + 100) = shift8(ptpClock->parent_communication_technology, 1);
+ memcpy((buf + 102), ptpClock->parent_uuid, 6);
+ *(Integer32 *) (buf + 108) = shift16(flip16(ptpClock->parent_port_id), 1);
+ *(Integer32 *) (buf + 112) = shift16(flip16(ptpClock->observed_variance), 1);
+ *(Integer32 *) (buf + 116) = flip32(ptpClock->observed_drift);
+ *(Integer32 *) (buf + 120) = shift8(ptpClock->utc_reasonable, 3);
+}
+
+void
+msgPackFollowUp(void *buf, UInteger16 associatedSequenceId,
+ TimeRepresentation * preciseOriginTimestamp, PtpClock * ptpClock)
+{
+ *(UInteger8 *) (buf + 20) = 2; /* messageType */
+ *(Integer32 *) (buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(UInteger8 *) (buf + 32) = PTP_FOLLOWUP_MESSAGE; /* control */
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ clearFlag((buf + 34), PARENT_STATS);
+
+ *(Integer32 *) (buf + 40) = shift16(flip16(associatedSequenceId), 1);
+ *(Integer32 *) (buf + 44) = flip32(preciseOriginTimestamp->seconds);
+ *(Integer32 *) (buf + 48) = flip32(preciseOriginTimestamp->nanoseconds);
+}
+
+void
+msgPackDelayResp(void *buf, MsgHeader * header,
+ TimeRepresentation * delayReceiptTimestamp, PtpClock * ptpClock)
+{
+ *(UInteger8 *) (buf + 20) = 2; /* messageType */
+ *(Integer32 *) (buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(UInteger8 *) (buf + 32) = PTP_DELAY_RESP_MESSAGE; /* control */
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ clearFlag((buf + 34), PARENT_STATS);
+
+ *(Integer32 *) (buf + 40) = flip32(delayReceiptTimestamp->seconds);
+ *(Integer32 *) (buf + 44) = flip32(delayReceiptTimestamp->nanoseconds);
+ *(Integer32 *) (buf + 48) = shift8(header->sourceCommunicationTechnology, 1);
+ memcpy(buf + 50, header->sourceUuid, 6);
+ *(Integer32 *) (buf + 56) = shift16(flip16(header->sourcePortId), 0) | shift16(flip16(header->sequenceId), 1);
+}
+
+UInteger16
+msgPackManagement(void *buf, MsgManagement * manage, PtpClock * ptpClock)
+{
+ *(UInteger8 *) (buf + 20) = 2; /* messageType */
+ *(Integer32 *) (buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(UInteger8 *) (buf + 32) = PTP_MANAGEMENT_MESSAGE; /* control */
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ clearFlag((buf + 34), PARENT_STATS);
+ *(Integer32 *) (buf + 40) = shift8(manage->targetCommunicationTechnology, 1);
+ memcpy(buf + 42, manage->targetUuid, 6);
+ *(Integer32 *) (buf + 48) = shift16(flip16(manage->targetPortId), 0) | shift16(flip16(MM_STARTING_BOUNDARY_HOPS), 1);
+ *(Integer32 *) (buf + 52) = shift16(flip16(MM_STARTING_BOUNDARY_HOPS), 0);
+
+ *(UInteger8 *) (buf + 55) = manage->managementMessageKey;
+
+ switch (manage->managementMessageKey) {
+ case PTP_MM_GET_FOREIGN_DATA_SET:
+ *(UInteger16 *) (buf + 62) = manage->recordKey;
+ *(Integer32 *) (buf + 56) = shift16(flip16(4), 1);
+ return 64;
+
+ default:
+ *(Integer32 *) (buf + 56) = shift16(flip16(0), 1);
+ return 60;
+ }
+}
+
+UInteger16
+msgPackManagementResponse(void *buf, MsgHeader * header, MsgManagement * manage, PtpClock * ptpClock)
+{
+ TimeInternal internalTime;
+ TimeRepresentation externalTime;
+
+ *(UInteger8 *) (buf + 20) = 2; /* messageType */
+ *(Integer32 *) (buf + 28) = shift16(flip16(ptpClock->port_id_field), 0) | shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(UInteger8 *) (buf + 32) = PTP_MANAGEMENT_MESSAGE; /* control */
+ clearFlag((buf + 34), PTP_SYNC_BURST);
+ clearFlag((buf + 34), PARENT_STATS);
+ *(Integer32 *) (buf + 40) = shift8(header->sourceCommunicationTechnology, 1);
+ memcpy(buf + 42, header->sourceUuid, 6);
+ *(Integer32 *) (buf + 48) = shift16(flip16(header->sourcePortId), 0) | shift16(flip16(MM_STARTING_BOUNDARY_HOPS), 1);
+ *(Integer32 *) (buf + 52) = shift16(flip16(manage->startingBoundaryHops - manage->boundaryHops + 1), 0);
+
+ switch (manage->managementMessageKey) {
+ case PTP_MM_OBTAIN_IDENTITY:
+ *(UInteger8 *) (buf + 55) = PTP_MM_CLOCK_IDENTITY;
+ *(Integer32 *) (buf + 56) = shift16(flip16(64), 1);
+ *(Integer32 *) (buf + 60) = shift8(ptpClock->clock_communication_technology, 3);
+ memcpy(buf + 64, ptpClock->clock_uuid_field, 6);
+ *(Integer32 *) (buf + 72) = shift16(flip16(ptpClock->clock_port_id_field), 1);
+ memcpy((buf + 76), MANUFACTURER_ID, 48);
+ return 124;
+
+ case PTP_MM_GET_DEFAULT_DATA_SET:
+ *(UInteger8 *) (buf + 55) = PTP_MM_DEFAULT_DATA_SET;
+ *(Integer32 *) (buf + 56) = shift16(flip16(76), 1);
+ *(Integer32 *) (buf + 60) = shift8(ptpClock->clock_communication_technology, 3);
+ memcpy(buf + 64, ptpClock->clock_uuid_field, 6);
+ *(Integer32 *) (buf + 72) = shift16(flip16(ptpClock->clock_port_id_field), 1);
+ *(Integer32 *) (buf + 76) = shift8(ptpClock->clock_stratum, 3);
+ memcpy(buf + 80, ptpClock->clock_identifier, 4);
+ *(Integer32 *) (buf + 84) = shift16(flip16(ptpClock->clock_variance), 1);
+ *(Integer32 *) (buf + 88) = shift8(ptpClock->clock_followup_capable, 3);
+ *(Integer32 *) (buf + 92) = shift8(ptpClock->preferred, 3);
+ *(Integer32 *) (buf + 96) = shift8(ptpClock->initializable, 3);
+ *(Integer32 *) (buf + 100) = shift8(ptpClock->external_timing, 3);
+ *(Integer32 *) (buf + 104) = shift8(ptpClock->is_boundary_clock, 3);
+ *(Integer32 *) (buf + 108) = shift8(ptpClock->sync_interval, 3);
+ memcpy(buf + 112, ptpClock->subdomain_name, 16);
+ *(Integer32 *) (buf + 128) = shift16(flip16(ptpClock->number_ports), 1);
+ *(Integer32 *) (buf + 132) = shift16(flip16(ptpClock->number_foreign_records), 1);
+ return 136;
+
+ case PTP_MM_GET_CURRENT_DATA_SET:
+ *(UInteger8 *) (buf + 55) = PTP_MM_CURRENT_DATA_SET;
+ *(Integer32 *) (buf + 56) = shift16(flip16(20), 1);
+ *(Integer32 *) (buf + 60) = shift16(flip16(ptpClock->steps_removed), 1);
+
+ fromInternalTime(&ptpClock->offset_from_master, &externalTime, 0);
+ *(Integer32 *) (buf + 64) = flip32(externalTime.seconds);
+ *(Integer32 *) (buf + 68) = flip32(externalTime.nanoseconds);
+
+ fromInternalTime(&ptpClock->one_way_delay, &externalTime, 0);
+ *(Integer32 *) (buf + 72) = flip32(externalTime.seconds);
+ *(Integer32 *) (buf + 76) = flip32(externalTime.nanoseconds);
+ return 80;
+
+ case PTP_MM_GET_PARENT_DATA_SET:
+ *(UInteger8 *) (buf + 55) = PTP_MM_PARENT_DATA_SET;
+ *(Integer32 *) (buf + 56) = shift16(flip16(90), 1);
+ *(Integer32 *) (buf + 60) = shift8(ptpClock->parent_communication_technology, 3);
+ memcpy(buf + 64, ptpClock->parent_uuid, 6);
+ *(Integer32 *) (buf + 72) = shift16(flip16(ptpClock->parent_port_id), 1);
+ *(Integer32 *) (buf + 76) = shift16(flip16(ptpClock->parent_last_sync_sequence_number), 1);
+ *(Integer32 *) (buf + 80) = shift8(ptpClock->parent_followup_capable, 1);
+ *(Integer32 *) (buf + 84) = shift8(ptpClock->parent_external_timing, 3);
+ *(Integer32 *) (buf + 88) = shift16(flip16(ptpClock->parent_variance), 1);
+ *(Integer32 *) (buf + 92) = shift8(ptpClock->parent_stats, 3);
+ *(Integer32 *) (buf + 96) = shift16(flip16(ptpClock->observed_variance), 1);
+ *(Integer32 *) (buf + 100) = flip32(ptpClock->observed_drift);
+ *(Integer32 *) (buf + 104) = shift8(ptpClock->utc_reasonable, 3);
+ *(Integer32 *) (buf + 108) = shift8(ptpClock->grandmaster_communication_technology, 3);
+ memcpy(buf + 112, ptpClock->grandmaster_uuid_field, 6);
+ *(Integer32 *) (buf + 120) = shift16(flip16(ptpClock->grandmaster_port_id_field), 1);
+ *(Integer32 *) (buf + 124) = shift8(ptpClock->grandmaster_stratum, 3);
+ memcpy(buf + 128, ptpClock->grandmaster_identifier, 4);
+ *(Integer32 *) (buf + 132) = shift16(flip16(ptpClock->grandmaster_variance), 1);
+ *(Integer32 *) (buf + 136) = shift8(ptpClock->grandmaster_preferred, 3);
+ *(Integer32 *) (buf + 140) = shift8(ptpClock->grandmaster_is_boundary_clock, 3);
+ *(Integer32 *) (buf + 144) = shift16(flip16(ptpClock->grandmaster_sequence_number), 1);
+ return 148;
+
+ case PTP_MM_GET_PORT_DATA_SET:
+ if (manage->targetPortId && manage->targetPortId != ptpClock->port_id_field) {
+ *(UInteger8 *) (buf + 55) = PTP_MM_NULL;
+ *(Integer32 *) (buf + 56) = shift16(flip16(0), 1);
+ return 0;
+ }
+ *(UInteger8 *) (buf + 55) = PTP_MM_PORT_DATA_SET;
+ *(Integer32 *) (buf + 56) = shift16(flip16(52), 1);
+ *(Integer32 *) (buf + 60) = shift16(flip16(ptpClock->port_id_field), 1);
+ *(Integer32 *) (buf + 64) = shift8(ptpClock->port_state, 3);
+ *(Integer32 *) (buf + 68) = shift16(flip16(ptpClock->last_sync_event_sequence_number), 1);
+ *(Integer32 *) (buf + 72) = shift16(flip16(ptpClock->last_general_event_sequence_number), 1);
+ *(Integer32 *) (buf + 76) = shift8(ptpClock->port_communication_technology, 3);
+ memcpy(buf + 80, ptpClock->port_uuid_field, 6);
+ *(Integer32 *) (buf + 88) = shift16(flip16(ptpClock->port_id_field), 1);
+ *(Integer32 *) (buf + 92) = shift8(ptpClock->burst_enabled, 3);
+ *(Integer32 *) (buf + 96) = shift8(4, 1) | shift8(2, 2) | shift8(2, 3);
+ memcpy(buf + 100, ptpClock->subdomain_address, 4);
+ memcpy(buf + 106, ptpClock->event_port_address, 2);
+ memcpy(buf + 110, ptpClock->general_port_address, 2);
+ return 112;
+
+ case PTP_MM_GET_GLOBAL_TIME_DATA_SET:
+ *(UInteger8 *) (buf + 55) = PTP_MM_GLOBAL_TIME_DATA_SET;
+ *(Integer32 *) (buf + 56) = shift16(flip16(24), 1);
+
+ getTime(&internalTime);
+ fromInternalTime(&internalTime, &externalTime, ptpClock->halfEpoch);
+ *(Integer32 *) (buf + 60) = flip32(externalTime.seconds);
+ *(Integer32 *) (buf + 64) = flip32(externalTime.nanoseconds);
+
+ *(Integer32 *) (buf + 68) = shift16(flip16(ptpClock->current_utc_offset), 1);
+ *(Integer32 *) (buf + 72) = shift8(ptpClock->leap_59, 3);
+ *(Integer32 *) (buf + 76) = shift8(ptpClock->leap_61, 3);
+ *(Integer32 *) (buf + 80) = shift16(flip16(ptpClock->epoch_number), 1);
+ return 84;
+
+ case PTP_MM_GET_FOREIGN_DATA_SET:
+ if ((manage->targetPortId && manage->targetPortId != ptpClock->port_id_field)
+ || !manage->recordKey || manage->recordKey > ptpClock->number_foreign_records) {
+ *(UInteger8 *) (buf + 55) = PTP_MM_NULL;
+ *(Integer32 *) (buf + 56) = shift16(flip16(0), 1);
+ return 0;
+ }
+ *(UInteger8 *) (buf + 55) = PTP_MM_FOREIGN_DATA_SET;
+ *(Integer32 *) (buf + 56) = shift16(flip16(28), 1);
+ *(Integer32 *) (buf + 60) = shift16(flip16(ptpClock->port_id_field), 1);
+ *(Integer32 *) (buf + 64) = shift16(flip16(manage->recordKey - 1), 1);
+ *(Integer32 *) (buf + 68) = shift8(ptpClock->foreign[manage->recordKey - 1].foreign_master_communication_technology, 3);
+ memcpy(buf + 72, ptpClock->foreign[manage->recordKey - 1].foreign_master_uuid, 6);
+ *(Integer32 *) (buf + 80) = shift16(flip16(ptpClock->foreign[manage->recordKey - 1].foreign_master_port_id), 1);
+ *(Integer32 *) (buf + 84) = shift16(flip16(ptpClock->foreign[manage->recordKey - 1].foreign_master_syncs), 1);
+ return 88;
+
+ default:
+ return 0;
+ }
+}
diff --git a/third_party/ptpd-1.1.0/src/dep/net.c b/third_party/ptpd-1.1.0/src/dep/net.c new file mode 100644 index 0000000..76c1ac3 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep/net.c @@ -0,0 +1,570 @@ +/**
+ * @file net.c
+ * @date Tue Jul 20 16:17:49 2010
+ *
+ * @brief Functions to interact with the network sockets and NIC driver.
+ *
+ *
+ */
+
+#include "../ptpd.h"
+
+Boolean
+lookupSubdomainAddress(Octet * subdomainName, Octet * subdomainAddress)
+{
+ UInteger32 h;
+
+ /* set multicast group address based on subdomainName */
+ if (!memcmp(subdomainName, DEFAULT_PTP_DOMAIN_NAME, PTP_SUBDOMAIN_NAME_LENGTH))
+ memcpy(subdomainAddress, DEFAULT_PTP_DOMAIN_ADDRESS, NET_ADDRESS_LENGTH);
+ else if (!memcmp(subdomainName, ALTERNATE_PTP_DOMAIN1_NAME, PTP_SUBDOMAIN_NAME_LENGTH))
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN1_ADDRESS, NET_ADDRESS_LENGTH);
+ else if (!memcmp(subdomainName, ALTERNATE_PTP_DOMAIN2_NAME, PTP_SUBDOMAIN_NAME_LENGTH))
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN2_ADDRESS, NET_ADDRESS_LENGTH);
+ else if (!memcmp(subdomainName, ALTERNATE_PTP_DOMAIN3_NAME, PTP_SUBDOMAIN_NAME_LENGTH))
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN3_ADDRESS, NET_ADDRESS_LENGTH);
+ else {
+ h = crc_algorithm(subdomainName, PTP_SUBDOMAIN_NAME_LENGTH) % 3;
+ switch (h) {
+ case 0:
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN1_ADDRESS, NET_ADDRESS_LENGTH);
+ break;
+ case 1:
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN2_ADDRESS, NET_ADDRESS_LENGTH);
+ break;
+ case 2:
+ memcpy(subdomainAddress, ALTERNATE_PTP_DOMAIN3_ADDRESS, NET_ADDRESS_LENGTH);
+ break;
+ default:
+ ERROR("handle out of range for '%s'!\n", subdomainName);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+UInteger8
+lookupCommunicationTechnology(UInteger8 communicationTechnology)
+{
+#if defined(linux)
+
+ switch (communicationTechnology) {
+ case ARPHRD_ETHER:
+ case ARPHRD_EETHER:
+ case ARPHRD_IEEE802:
+ return PTP_ETHER;
+
+ default:
+ break;
+ }
+
+#elif defined(BSD_INTERFACE_FUNCTIONS)
+
+#endif
+
+ return PTP_DEFAULT;
+}
+
+UInteger32
+findIface(Octet * ifaceName, UInteger8 * communicationTechnology,
+ Octet * uuid, NetPath * netPath)
+{
+#if defined(linux)
+
+ /* depends on linux specific ioctls (see 'netdevice' man page) */
+ int i, flags;
+ struct ifconf data;
+ struct ifreq device[IFCONF_LENGTH];
+
+ data.ifc_len = sizeof(device);
+ data.ifc_req = device;
+
+ memset(data.ifc_buf, 0, data.ifc_len);
+
+ flags = IFF_UP | IFF_RUNNING | IFF_MULTICAST;
+
+ /* look for an interface if none specified */
+ if (ifaceName[0] != '\0') {
+ i = 0;
+ memcpy(device[i].ifr_name, ifaceName, IFACE_NAME_LENGTH);
+
+ if (ioctl(netPath->eventSock, SIOCGIFHWADDR, &device[i]) < 0)
+ DBGV("failed to get hardware address\n");
+ else if ((*communicationTechnology = lookupCommunicationTechnology(device[i].ifr_hwaddr.sa_family)) == PTP_DEFAULT)
+ DBGV("unsupported communication technology (%d)\n", *communicationTechnology);
+ else
+ memcpy(uuid, device[i].ifr_hwaddr.sa_data, PTP_UUID_LENGTH);
+ } else {
+ /* no iface specified */
+ /* get list of network interfaces */
+ if (ioctl(netPath->eventSock, SIOCGIFCONF, &data) < 0) {
+ PERROR("failed query network interfaces");
+ return 0;
+ }
+ if (data.ifc_len >= sizeof(device))
+ DBG("device list may exceed allocated space\n");
+
+ /* search through interfaces */
+ for (i = 0; i < data.ifc_len / sizeof(device[0]); ++i) {
+ DBGV("%d %s %s\n", i, device[i].ifr_name, inet_ntoa(((struct sockaddr_in *)&device[i].ifr_addr)->sin_addr));
+
+ if (ioctl(netPath->eventSock, SIOCGIFFLAGS, &device[i]) < 0)
+ DBGV("failed to get device flags\n");
+ else if ((device[i].ifr_flags & flags) != flags)
+ DBGV("does not meet requirements (%08x, %08x)\n", device[i].ifr_flags, flags);
+ else if (ioctl(netPath->eventSock, SIOCGIFHWADDR, &device[i]) < 0)
+ DBGV("failed to get hardware address\n");
+ else if ((*communicationTechnology = lookupCommunicationTechnology(device[i].ifr_hwaddr.sa_family)) == PTP_DEFAULT)
+ DBGV("unsupported communication technology (%d)\n", *communicationTechnology);
+ else {
+ DBGV("found interface (%s)\n", device[i].ifr_name);
+
+ memcpy(uuid, device[i].ifr_hwaddr.sa_data, PTP_UUID_LENGTH);
+ memcpy(ifaceName, device[i].ifr_name, IFACE_NAME_LENGTH);
+
+ break;
+ }
+ }
+ }
+
+ if (ifaceName[0] == '\0') {
+ ERROR("failed to find a usable interface\n");
+ return 0;
+ }
+ if (ioctl(netPath->eventSock, SIOCGIFADDR, &device[i]) < 0) {
+ PERROR("failed to get ip address");
+ return 0;
+ }
+ return ((struct sockaddr_in *)&device[i].ifr_addr)->sin_addr.s_addr;
+
+#elif defined(BSD_INTERFACE_FUNCTIONS)
+
+ struct ifaddrs *if_list, *ifv4, *ifh;
+
+ if (getifaddrs(&if_list) < 0) {
+ PERROR("getifaddrs() failed");
+ return FALSE;
+ }
+ /* find an IPv4, multicast, UP interface, right name(if supplied) */
+ for (ifv4 = if_list; ifv4 != NULL; ifv4 = ifv4->ifa_next) {
+ if ((ifv4->ifa_flags & IFF_UP) == 0)
+ continue;
+ if ((ifv4->ifa_flags & IFF_RUNNING) == 0)
+ continue;
+ if ((ifv4->ifa_flags & IFF_LOOPBACK))
+ continue;
+ if ((ifv4->ifa_flags & IFF_MULTICAST) == 0)
+ continue;
+ if (ifv4->ifa_addr->sa_family != AF_INET) /* must have IPv4
+ * address */
+ continue;
+
+ if (ifaceName[0] && strncmp(ifv4->ifa_name, ifaceName, IF_NAMESIZE) != 0)
+ continue;
+
+ break;
+ }
+
+ if (ifv4 == NULL) {
+ if (ifaceName[0]) {
+ ERROR("interface \"%s\" does not exist, or is not appropriate\n", ifaceName);
+ return FALSE;
+ }
+ ERROR("no suitable interfaces found!");
+ return FALSE;
+ }
+ /* find the AF_LINK info associated with the chosen interface */
+ for (ifh = if_list; ifh != NULL; ifh = ifh->ifa_next) {
+ if (ifh->ifa_addr->sa_family != AF_LINK)
+ continue;
+ if (strncmp(ifv4->ifa_name, ifh->ifa_name, IF_NAMESIZE) == 0)
+ break;
+ }
+
+ if (ifh == NULL) {
+ ERROR("could not get hardware address for interface \"%s\"\n", ifv4->ifa_name);
+ return FALSE;
+ }
+ /* check that the interface TYPE is OK */
+ if (((struct sockaddr_dl *)ifh->ifa_addr)->sdl_type != IFT_ETHER) {
+ ERROR("\"%s\" is not an ethernet interface!\n", ifh->ifa_name);
+ return FALSE;
+ }
+
+ DBG("==> %s %s %s\n", ifv4->ifa_name,
+ inet_ntoa(((struct sockaddr_in *)ifv4->ifa_addr)->sin_addr),
+ ether_ntoa((struct ether_addr *)
+ LLADDR((struct sockaddr_dl *)ifh->ifa_addr)));
+
+ *communicationTechnology = PTP_ETHER;
+ memcpy(ifaceName, ifh->ifa_name, IFACE_NAME_LENGTH);
+ memcpy(uuid, LLADDR((struct sockaddr_dl *)ifh->ifa_addr), PTP_UUID_LENGTH);
+
+ return ((struct sockaddr_in *)ifv4->ifa_addr)->sin_addr.s_addr;
+
+#endif
+}
+
+/* start all of the UDP stuff */
+/* must specify 'subdomainName', optionally 'ifaceName', if not then pass ifaceName == "" */
+/* returns other args */
+/* on socket options, see the 'socket(7)' and 'ip' man pages */
+Boolean
+netInit(NetPath * netPath, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ int temp, i;
+ struct in_addr interfaceAddr, netAddr;
+ struct sockaddr_in addr;
+ struct ip_mreq imr;
+ char addrStr[NET_ADDRESS_LENGTH];
+ char *s;
+
+ DBG("netInit\n");
+
+ /* open sockets */
+ if ((netPath->eventSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0
+ || (netPath->generalSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ PERROR("failed to initalize sockets");
+ return FALSE;
+ }
+ /* find a network interface */
+ if (!(interfaceAddr.s_addr = findIface(rtOpts->ifaceName, &ptpClock->port_communication_technology,
+ ptpClock->port_uuid_field, netPath)))
+ return FALSE;
+
+ temp = 1; /* allow address reuse */
+ if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0
+ || setsockopt(netPath->generalSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0) {
+ DBG("failed to set socket reuse\n");
+ }
+ /* bind sockets */
+ /*
+ * need INADDR_ANY to allow receipt of multi-cast and uni-cast
+ * messages
+ */
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = htons(PTP_EVENT_PORT);
+ if (bind(netPath->eventSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
+ PERROR("failed to bind event socket");
+ return FALSE;
+ }
+ addr.sin_port = htons(PTP_GENERAL_PORT);
+ if (bind(netPath->generalSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
+ PERROR("failed to bind general socket");
+ return FALSE;
+ }
+ /* set general and port address */
+ *(Integer16 *) ptpClock->event_port_address = PTP_EVENT_PORT;
+ *(Integer16 *) ptpClock->general_port_address = PTP_GENERAL_PORT;
+
+ /* send a uni-cast address if specified (useful for testing) */
+ if (rtOpts->unicastAddress[0]) {
+ if (!inet_aton(rtOpts->unicastAddress, &netAddr)) {
+ ERROR("failed to encode uni-cast address: %s\n", rtOpts->unicastAddress);
+ return FALSE;
+ }
+ netPath->unicastAddr = netAddr.s_addr;
+ } else
+ netPath->unicastAddr = 0;
+
+ /* resolve PTP subdomain */
+ if (!lookupSubdomainAddress(rtOpts->subdomainName, addrStr))
+ return FALSE;
+
+ if (!inet_aton(addrStr, &netAddr)) {
+ ERROR("failed to encode multi-cast address: %s\n", addrStr);
+ return FALSE;
+ }
+ netPath->multicastAddr = netAddr.s_addr;
+
+ s = addrStr;
+ for (i = 0; i < SUBDOMAIN_ADDRESS_LENGTH; ++i) {
+ ptpClock->subdomain_address[i] = strtol(s, &s, 0);
+
+ if (!s)
+ break;
+
+ ++s;
+ }
+
+ /* multicast send only on specified interface */
+ imr.imr_multiaddr.s_addr = netAddr.s_addr;
+ imr.imr_interface.s_addr = interfaceAddr.s_addr;
+ if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0
+ || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_IF, &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0) {
+ PERROR("failed to enable multi-cast on the interface");
+ return FALSE;
+ }
+ /* join multicast group (for receiving) on specified interface */
+ if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) < 0
+ || setsockopt(netPath->generalSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) < 0) {
+ PERROR("failed to join the multi-cast group");
+ return FALSE;
+ }
+ /* set socket time-to-live */
+ if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_TTL, &rtOpts->ttl, sizeof(int)) < 0
+ || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_TTL, &rtOpts->ttl, sizeof(int)) < 0) {
+ PERROR("failed to set the multi-cast time-to-live");
+ return FALSE;
+ }
+ /* enable loopback */
+ temp = 1;
+ if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_MULTICAST_LOOP, &temp, sizeof(int)) < 0
+ || setsockopt(netPath->generalSock, IPPROTO_IP, IP_MULTICAST_LOOP, &temp, sizeof(int)) < 0) {
+ PERROR("failed to enable multi-cast loopback");
+ return FALSE;
+ }
+ /* make timestamps available through recvmsg() */
+
+ temp = 1;
+#if defined(linux)
+ if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_TIMESTAMP, &temp, sizeof(int)) < 0
+ || setsockopt(netPath->generalSock, SOL_SOCKET, SO_TIMESTAMP, &temp, sizeof(int)) < 0) {
+#else /* BSD */
+ if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_BINTIME, &temp, sizeof(int)) < 0
+ || setsockopt(netPath->generalSock, SOL_SOCKET, SO_BINTIME, &temp, sizeof(int)) < 0) {
+#endif /* linux or BSD */
+ PERROR("failed to enable receive time stamps");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* shut down the UDP stuff */
+Boolean
+netShutdown(NetPath * netPath)
+{
+ struct ip_mreq imr;
+
+ imr.imr_multiaddr.s_addr = netPath->multicastAddr;
+ imr.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ setsockopt(netPath->eventSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(struct ip_mreq));
+ setsockopt(netPath->generalSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(struct ip_mreq));
+
+ netPath->multicastAddr = 0;
+ netPath->unicastAddr = 0;
+
+ if (netPath->eventSock > 0)
+ close(netPath->eventSock);
+ netPath->eventSock = -1;
+
+ if (netPath->generalSock > 0)
+ close(netPath->generalSock);
+ netPath->generalSock = -1;
+
+ return TRUE;
+}
+
+int
+netSelect(TimeInternal * timeout, NetPath * netPath)
+{
+ int ret, nfds;
+ fd_set readfds;
+ struct timeval tv, *tv_ptr;
+
+ if (timeout < 0)
+ return FALSE;
+
+ FD_ZERO(&readfds);
+ FD_SET(netPath->eventSock, &readfds);
+ FD_SET(netPath->generalSock, &readfds);
+
+ if (timeout) {
+ tv.tv_sec = timeout->seconds;
+ tv.tv_usec = timeout->nanoseconds / 1000;
+ tv_ptr = &tv;
+ } else
+ tv_ptr = 0;
+
+ if (netPath->eventSock > netPath->generalSock)
+ nfds = netPath->eventSock;
+ else
+ nfds = netPath->generalSock;
+
+ ret = select(nfds + 1, &readfds, 0, 0, tv_ptr) > 0;
+ if (ret < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+ }
+ return ret;
+}
+
+ssize_t
+netRecvEvent(Octet * buf, TimeInternal * time, NetPath * netPath)
+{
+ ssize_t ret;
+ struct msghdr msg;
+ struct iovec vec[1];
+ struct sockaddr_in from_addr;
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof(struct timeval))];
+ } cmsg_un;
+ struct cmsghdr *cmsg;
+#if defined(linux)
+ struct timeval *tv;
+#else /* FreeBSD */
+ struct timespec ts;
+#endif /* FreeBSD or Linux */
+
+ vec[0].iov_base = buf;
+ vec[0].iov_len = PACKET_SIZE;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&from_addr, 0, sizeof(from_addr));
+ memset(buf, 0, PACKET_SIZE);
+ memset(&cmsg_un, 0, sizeof(cmsg_un));
+
+ msg.msg_name = (caddr_t)&from_addr;
+ msg.msg_namelen = sizeof(from_addr);
+ msg.msg_iov = vec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsg_un.control;
+ msg.msg_controllen = sizeof(cmsg_un.control);
+ msg.msg_flags = 0;
+
+ ret = recvmsg(netPath->eventSock, &msg, MSG_DONTWAIT);
+ if (ret <= 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ return ret;
+ }
+ if (msg.msg_flags & MSG_TRUNC) {
+ ERROR("received truncated message\n");
+ return 0;
+ }
+ /* get time stamp of packet */
+ if (!time) {
+ ERROR("null receive time stamp argument\n");
+ return 0;
+ }
+ if (msg.msg_flags & MSG_CTRUNC) {
+ ERROR("received truncated ancillary data\n");
+ return 0;
+ }
+ if (msg.msg_controllen < sizeof(cmsg_un.control)) {
+ ERROR("received short ancillary data (%d/%d)\n",
+ msg.msg_controllen, (int)sizeof(cmsg_un.control));
+
+ return 0;
+ }
+
+#if defined(linux)
+ tv = 0;
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_TIMESTAMP)
+ tv = (struct timeval *)CMSG_DATA(cmsg);
+
+ if (tv) {
+ time->seconds = tv->tv_sec;
+ time->nanoseconds = tv->tv_usec * 1000;
+ DBGV("kernel recv time stamp %us %dns\n", time->seconds, time->nanoseconds);
+ } else {
+ /*
+ * do not try to get by with recording the time here, better
+ * to fail because the time recorded could be well after the
+ * message receive, which would put a big spike in the
+ * offset signal sent to the clock servo
+ */
+ DBG("no recieve time stamp\n");
+ return 0;
+ }
+#else /* FreeBSD */
+ bzero(&ts, sizeof(ts));
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_BINTIME)
+ bintime2timespec((struct bintime *)CMSG_DATA(cmsg),
+ &ts);
+
+ if (ts.tv_sec != 0) {
+ time->seconds = ts.tv_sec;
+ time->nanoseconds = ts.tv_nsec;
+ DBGV("kernel recv time stamp %us %dns\n", time->seconds, time->nanoseconds);
+ } else {
+ /*
+ * do not try to get by with recording the time here, better
+ * to fail because the time recorded could be well after the
+ * message receive, which would put a big spike in the
+ * offset signal sent to the clock servo
+ */
+ DBG("no recieve time stamp\n");
+ return 0;
+ }
+#endif /* FreeBSD or Linux */
+
+ return ret;
+}
+
+ssize_t
+netRecvGeneral(Octet * buf, NetPath * netPath)
+{
+ ssize_t ret;
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof(struct sockaddr_in);
+
+ ret = recvfrom(netPath->generalSock, buf, PACKET_SIZE, MSG_DONTWAIT, (struct sockaddr *)&addr, &addr_len);
+ if (ret <= 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+
+ return ret;
+ }
+ return ret;
+}
+
+ssize_t
+netSendEvent(Octet * buf, UInteger16 length, NetPath * netPath)
+{
+ ssize_t ret;
+ struct sockaddr_in addr;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(PTP_EVENT_PORT);
+ addr.sin_addr.s_addr = netPath->multicastAddr;
+
+ ret = sendto(netPath->eventSock, buf, length, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
+ if (ret <= 0)
+ DBG("error sending multi-cast event message\n");
+
+ if (netPath->unicastAddr) {
+ addr.sin_addr.s_addr = netPath->unicastAddr;
+
+ ret = sendto(netPath->eventSock, buf, length, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
+ if (ret <= 0)
+ DBG("error sending uni-cast event message\n");
+ }
+ return ret;
+}
+
+ssize_t
+netSendGeneral(Octet * buf, UInteger16 length, NetPath * netPath)
+{
+ ssize_t ret;
+ struct sockaddr_in addr;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(PTP_GENERAL_PORT);
+ addr.sin_addr.s_addr = netPath->multicastAddr;
+
+ ret = sendto(netPath->generalSock, buf, length, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
+ if (ret <= 0)
+ DBG("error sending multi-cast general message\n");
+
+ if (netPath->unicastAddr) {
+ addr.sin_addr.s_addr = netPath->unicastAddr;
+
+ ret = sendto(netPath->eventSock, buf, length, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
+ if (ret <= 0)
+ DBG("error sending uni-cast general message\n");
+ }
+ return ret;
+}
diff --git a/third_party/ptpd-1.1.0/src/dep/ptpd_dep.h b/third_party/ptpd-1.1.0/src/dep/ptpd_dep.h new file mode 100644 index 0000000..63cf674 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep/ptpd_dep.h @@ -0,0 +1,154 @@ +/**
+ * @file ptpd_dep.h
+ * @date Tue Jul 20 16:18:39 2010
+ *
+ * @brief External definitions for inclusion elsewhere.
+ *
+ *
+ */
+
+#ifndef PTPD_DEP_H
+#define PTPD_DEP_H
+
+#include<stdlib.h>
+#include<stdio.h>
+#include<string.h>
+#include<unistd.h>
+#include<errno.h>
+#include<signal.h>
+#include<fcntl.h>
+#include<sys/stat.h>
+#include<time.h>
+#include<sys/time.h>
+#include<sys/timex.h>
+#include<sys/socket.h>
+#include<sys/select.h>
+#include<sys/ioctl.h>
+#include<arpa/inet.h>
+#include<stdarg.h>
+#include<syslog.h>
+#include<limits.h>
+
+/* system messages */
+#define ERROR(x, ...) message(LOG_ERR, x, ##__VA_ARGS__)
+#define PERROR(x, ...) message(LOG_ERR, x ": %m\n", ##__VA_ARGS__)
+#define NOTIFY(x, ...) message(LOG_NOTICE, x, ##__VA_ARGS__)
+#define INFO(x, ...) message(LOG_INFO, x, ##__VA_ARGS__)
+
+/* debug messages */
+#ifdef PTPD_DBGV
+#define PTPD_DBG
+#define DBGV(x, ...) message(LOG_DEBUG, x, ##__VA_ARGS__)
+#else
+#define DBGV(x, ...)
+#endif
+
+#ifdef PTPD_DBG
+#define DBG(x, ...) message(LOG_DEBUG, x, ##__VA_ARGS__)
+#else
+#define DBG(x, ...)
+#endif
+
+/* endian corrections */
+#if defined(PTPD_MSBF)
+#define shift8(x,y) ( (x) << ((3-y)<<3) )
+#define shift16(x,y) ( (x) << ((1-y)<<4) )
+#elif defined(PTPD_LSBF)
+#define shift8(x,y) ( (x) << ((y)<<3) )
+#define shift16(x,y) ( (x) << ((y)<<4) )
+#endif
+
+#define flip16(x) htons(x)
+#define flip32(x) htonl(x)
+
+/* i don't know any target platforms that do not have htons and htonl,
+ but here are generic funtions just in case */
+/*
+#if defined(PTPD_MSBF)
+#define flip16(x) (x)
+#define flip32(x) (x)
+#elif defined(PTPD_LSBF)
+static inline Integer16 flip16(Integer16 x)
+{
+ return (((x) >> 8) & 0x00ff) | (((x) << 8) & 0xff00);
+}
+
+static inline Integer32 flip32(x)
+{
+ return (((x) >> 24) & 0x000000ff) | (((x) >> 8 ) & 0x0000ff00) |
+ (((x) << 8 ) & 0x00ff0000) | (((x) << 24) & 0xff000000);
+}
+#endif
+*/
+
+/* bit array manipulation */
+#define getFlag(x,y) !!( *(UInteger8*)((x)+((y)<8?1:0)) & (1<<((y)<8?(y):(y)-8)) )
+#define setFlag(x,y) ( *(UInteger8*)((x)+((y)<8?1:0)) |= 1<<((y)<8?(y):(y)-8) )
+#define clearFlag(x,y) ( *(UInteger8*)((x)+((y)<8?1:0)) &= ~(1<<((y)<8?(y):(y)-8)) )
+
+
+/* msg.c */
+Boolean msgPeek(void *, ssize_t);
+void msgUnpackHeader(void *, MsgHeader *);
+void msgUnpackSync(void *, MsgSync *);
+void msgUnpackDelayReq(void *, MsgDelayReq *);
+void msgUnpackFollowUp(void *, MsgFollowUp *);
+void msgUnpackDelayResp(void *, MsgDelayResp *);
+void msgUnpackManagement(void *, MsgManagement *);
+UInteger8 msgUnloadManagement(void *, MsgManagement *, PtpClock *, RunTimeOpts *);
+void msgUnpackManagementPayload(void *buf, MsgManagement * manage);
+void msgPackHeader(void *, PtpClock *);
+void msgPackSync(void *, Boolean, TimeRepresentation *, PtpClock *);
+void msgPackDelayReq(void *, Boolean, TimeRepresentation *, PtpClock *);
+void msgPackFollowUp(void *, UInteger16, TimeRepresentation *, PtpClock *);
+void msgPackDelayResp(void *, MsgHeader *, TimeRepresentation *, PtpClock *);
+UInteger16 msgPackManagement(void *, MsgManagement *, PtpClock *);
+UInteger16 msgPackManagementResponse(void *, MsgHeader *, MsgManagement *, PtpClock *);
+
+/* net.c */
+/* linux API dependent */
+Boolean netInit(NetPath *, RunTimeOpts *, PtpClock *);
+Boolean netShutdown(NetPath *);
+int netSelect(TimeInternal *, NetPath *);
+ssize_t netRecvEvent(Octet *, TimeInternal *, NetPath *);
+ssize_t netRecvGeneral(Octet *, NetPath *);
+ssize_t netSendEvent(Octet *, UInteger16, NetPath *);
+ssize_t netSendGeneral(Octet *, UInteger16, NetPath *);
+
+/* servo.c */
+void initClock(RunTimeOpts *, PtpClock *);
+void
+updateDelay(TimeInternal *, TimeInternal *,
+ one_way_delay_filter *, RunTimeOpts *, PtpClock *);
+void
+updateOffset(TimeInternal *, TimeInternal *,
+ offset_from_master_filter *, RunTimeOpts *, PtpClock *);
+void updateClock(RunTimeOpts *, PtpClock *);
+
+/* startup.c */
+/* unix API dependent */
+int logToFile();
+int recordToFile();
+PtpClock *ptpdStartup(int, char **, Integer16 *, RunTimeOpts *);
+void ptpdShutdown(void);
+
+/* sys.c */
+char *translatePortState(PtpClock *ptpClock);
+/* unix API dependent */
+void message(int priority, const char *format, ...);
+void displayStats(RunTimeOpts *, PtpClock *);
+Boolean nanoSleep(TimeInternal *);
+void getTime(TimeInternal *);
+void setTime(TimeInternal *);
+UInteger16 getRand(UInteger32 *);
+Boolean adjFreq(Integer32);
+
+/* timer.c */
+void initTimer(void);
+void timerUpdate(IntervalTimer *);
+void timerStop(UInteger16, IntervalTimer *);
+void timerStart(UInteger16, UInteger16, IntervalTimer *);
+Boolean timerExpired(UInteger16, IntervalTimer *);
+
+
+#endif
diff --git a/third_party/ptpd-1.1.0/src/dep/servo.c b/third_party/ptpd-1.1.0/src/dep/servo.c new file mode 100644 index 0000000..b888593 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep/servo.c @@ -0,0 +1,215 @@ +/**
+ * @file servo.c
+ * @date Tue Jul 20 16:19:19 2010
+ *
+ * @brief Code which implements the clock servo in software.
+ *
+ *
+ */
+
+#include "../ptpd.h"
+
+void
+initClock(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ DBG("initClock\n");
+
+ /* clear vars */
+ ptpClock->master_to_slave_delay.seconds = ptpClock->master_to_slave_delay.nanoseconds = 0;
+ ptpClock->slave_to_master_delay.seconds = ptpClock->slave_to_master_delay.nanoseconds = 0;
+ ptpClock->observed_variance = 0;
+ ptpClock->observed_drift = 0; /* clears clock servo accumulator (the
+ * I term) */
+ ptpClock->owd_filt.s_exp = 0; /* clears one-way delay filter */
+ ptpClock->halfEpoch = ptpClock->halfEpoch || rtOpts->halfEpoch;
+ rtOpts->halfEpoch = 0;
+
+ /* level clock */
+ if (!rtOpts->noAdjust)
+ adjFreq(0);
+}
+
+void
+updateDelay(TimeInternal * send_time, TimeInternal * recv_time,
+ one_way_delay_filter * owd_filt, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ Integer16 s;
+ TimeInternal slave_to_master_delay;
+
+ DBGV("updateDelay\n");
+
+ /* calc 'slave_to_master_delay' */
+ subTime(&slave_to_master_delay, recv_time, send_time);
+
+ if (rtOpts->maxDelay) { /* If maxDelay is 0 then it's OFF */
+ if (slave_to_master_delay.seconds && rtOpts->maxDelay) {
+ INFO("updateDelay aborted, delay greater than 1"
+ " second.");
+ return;
+ }
+
+ if (slave_to_master_delay.nanoseconds > rtOpts->maxDelay) {
+ INFO("updateDelay aborted, delay %d greater than "
+ "administratively set maximum %d\n",
+ slave_to_master_delay.nanoseconds,
+ rtOpts->maxDelay);
+ return;
+ }
+ }
+
+ ptpClock->slave_to_master_delay = slave_to_master_delay;
+
+ /* update 'one_way_delay' */
+ addTime(&ptpClock->one_way_delay, &ptpClock->master_to_slave_delay, &ptpClock->slave_to_master_delay);
+ ptpClock->one_way_delay.seconds /= 2;
+ ptpClock->one_way_delay.nanoseconds /= 2;
+
+ if (ptpClock->one_way_delay.seconds) {
+ /* cannot filter with secs, clear filter */
+ owd_filt->s_exp = owd_filt->nsec_prev = 0;
+ return;
+ }
+ /* avoid overflowing filter */
+ s = rtOpts->s;
+ while (abs(owd_filt->y) >> (31 - s))
+ --s;
+
+ /* crank down filter cutoff by increasing 's_exp' */
+ if (owd_filt->s_exp < 1)
+ owd_filt->s_exp = 1;
+ else if (owd_filt->s_exp < 1 << s)
+ ++owd_filt->s_exp;
+ else if (owd_filt->s_exp > 1 << s)
+ owd_filt->s_exp = 1 << s;
+
+ /* filter 'one_way_delay' */
+ owd_filt->y = (owd_filt->s_exp - 1) * owd_filt->y / owd_filt->s_exp +
+ (ptpClock->one_way_delay.nanoseconds / 2 + owd_filt->nsec_prev / 2) / owd_filt->s_exp;
+
+ owd_filt->nsec_prev = ptpClock->one_way_delay.nanoseconds;
+ ptpClock->one_way_delay.nanoseconds = owd_filt->y;
+
+ DBG("delay filter %d, %d\n", owd_filt->y, owd_filt->s_exp);
+}
+
+void
+updateOffset(TimeInternal * send_time, TimeInternal * recv_time,
+ offset_from_master_filter * ofm_filt, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ TimeInternal master_to_slave_delay;
+ DBGV("updateOffset\n");
+
+ /* calc 'master_to_slave_delay' */
+ subTime(&master_to_slave_delay, recv_time, send_time);
+
+ if (rtOpts->maxDelay) { /* If maxDelay is 0 then it's OFF */
+ if (master_to_slave_delay.seconds && rtOpts->maxDelay) {
+ INFO("updateDelay aborted, delay greater than 1"
+ " second.");
+ return;
+ }
+
+ if (master_to_slave_delay.nanoseconds > rtOpts->maxDelay) {
+ INFO("updateDelay aborted, delay %d greater than "
+ "administratively set maximum %d\n",
+ master_to_slave_delay.nanoseconds,
+ rtOpts->maxDelay);
+ return;
+ }
+ }
+ ptpClock->master_to_slave_delay = master_to_slave_delay;
+
+ /* update 'offset_from_master' */
+ subTime(&ptpClock->offset_from_master, &ptpClock->master_to_slave_delay, &ptpClock->one_way_delay);
+
+ if (ptpClock->offset_from_master.seconds) {
+ /* cannot filter with secs, clear filter */
+ ofm_filt->nsec_prev = 0;
+ return;
+ }
+ /* filter 'offset_from_master' */
+ ofm_filt->y = ptpClock->offset_from_master.nanoseconds / 2 + ofm_filt->nsec_prev / 2;
+ ofm_filt->nsec_prev = ptpClock->offset_from_master.nanoseconds;
+ ptpClock->offset_from_master.nanoseconds = ofm_filt->y;
+
+ DBGV("offset filter %d\n", ofm_filt->y);
+}
+
+void
+updateClock(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ Integer32 adj;
+ TimeInternal timeTmp;
+
+ DBGV("updateClock\n");
+
+ if (rtOpts->maxReset) { /* If maxReset is 0 then it's OFF */
+ if (ptpClock->offset_from_master.seconds) {
+ INFO("updateClock aborted, offset greater than 1"
+ " second.");
+ goto display;
+ }
+
+ if (ptpClock->offset_from_master.nanoseconds >
+ rtOpts->maxReset) {
+ INFO("updateClock aborted, offset %d greater than "
+ "administratively set maximum %d\n",
+ ptpClock->offset_from_master.nanoseconds,
+ rtOpts->maxReset);
+ goto display;
+ }
+ }
+
+ if (ptpClock->offset_from_master.seconds) {
+ /* if secs, reset clock or set freq adjustment to max */
+ if (!rtOpts->noAdjust) {
+ if (!rtOpts->noResetClock) {
+ getTime(&timeTmp);
+ subTime(&timeTmp, &timeTmp, &ptpClock->offset_from_master);
+ setTime(&timeTmp);
+ initClock(rtOpts, ptpClock);
+ } else {
+ adj = ptpClock->offset_from_master.nanoseconds > 0 ? ADJ_FREQ_MAX : -ADJ_FREQ_MAX;
+ adjFreq(-adj);
+ }
+ }
+ } else {
+ /* the PI controller */
+
+ /* no negative or zero attenuation */
+ if (rtOpts->ap < 1)
+ rtOpts->ap = 1;
+ if (rtOpts->ai < 1)
+ rtOpts->ai = 1;
+
+ /* the accumulator for the I component */
+ ptpClock->observed_drift += ptpClock->offset_from_master.nanoseconds / rtOpts->ai;
+
+ /* clamp the accumulator to ADJ_FREQ_MAX for sanity */
+ if (ptpClock->observed_drift > ADJ_FREQ_MAX)
+ ptpClock->observed_drift = ADJ_FREQ_MAX;
+ else if (ptpClock->observed_drift < -ADJ_FREQ_MAX)
+ ptpClock->observed_drift = -ADJ_FREQ_MAX;
+
+ adj = ptpClock->offset_from_master.nanoseconds / rtOpts->ap + ptpClock->observed_drift;
+
+ /* apply controller output as a clock tick rate adjustment */
+ if (!rtOpts->noAdjust)
+ adjFreq(-adj);
+ }
+
+display:
+
+ if (rtOpts->displayStats)
+ displayStats(rtOpts, ptpClock);
+
+ DBGV("master-to-slave delay: %10ds %11dns\n",
+ ptpClock->master_to_slave_delay.seconds, ptpClock->master_to_slave_delay.nanoseconds);
+ DBGV("slave-to-master delay: %10ds %11dns\n",
+ ptpClock->slave_to_master_delay.seconds, ptpClock->slave_to_master_delay.nanoseconds);
+ DBGV("one-way delay: %10ds %11dns\n",
+ ptpClock->one_way_delay.seconds, ptpClock->one_way_delay.nanoseconds);
+ DBG("offset from master: %10ds %11dns\n",
+ ptpClock->offset_from_master.seconds, ptpClock->offset_from_master.nanoseconds);
+ DBG("observed drift: %10d\n", ptpClock->observed_drift);
+}
diff --git a/third_party/ptpd-1.1.0/src/dep/startup.c b/third_party/ptpd-1.1.0/src/dep/startup.c new file mode 100644 index 0000000..edbcbfd --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep/startup.c @@ -0,0 +1,364 @@ +/**
+ * @file startup.c
+ * @date Wed Jun 23 09:33:27 2010
+ *
+ * @brief Code to handle daemon startup, including command line args
+ *
+ * The function in this file are called when the daemon starts up
+ * and include the getopt() command line argument parsing.
+ */
+
+#include "../ptpd.h"
+
+PtpClock *ptpClock;
+
+/**
+ * Signal handler for catching a close signal
+ *
+ * @param sig
+ */
+void
+catch_close(int sig)
+{
+ char *s;
+
+ ptpdShutdown();
+
+ switch (sig) {
+ case SIGINT:
+ s = "interrupt";
+ break;
+
+ case SIGTERM:
+ s = "terminate";
+ break;
+
+ default:
+ s = "?";
+ }
+
+ NOTIFY("shutdown on %s signal\n", s);
+
+ exit(0);
+}
+
+/**
+ * Signal handler for HUP which tells us to swap the log file.
+ *
+ * @param sig
+ */
+void
+catch_sighup(int sig)
+{
+ if(!logToFile())
+ NOTIFY("SIGHUP failed\n");
+ else
+ NOTIFY("I've been SIGHUP'd\n");
+ if(!recordToFile())
+ NOTIFY("SIGHUP failed\n");
+ else
+ NOTIFY("I've been SIGHUP'd\n");
+
+}
+
+/**
+ * Log output to a file
+ *
+ *
+ * @return True if success, False if failure
+ */
+int
+logToFile()
+{
+ extern RunTimeOpts rtOpts;
+ if(rtOpts.logFd != -1)
+ close(rtOpts.logFd);
+
+ if((rtOpts.logFd = creat(rtOpts.file, 0444)) != -1) {
+ dup2(rtOpts.logFd, STDOUT_FILENO);
+ dup2(rtOpts.logFd, STDERR_FILENO);
+ }
+ return (rtOpts.logFd != -1);
+}
+
+/**
+ * Record quality data for later correlation
+ *
+ *
+ * @return True if success, False if failure
+ */
+int
+recordToFile()
+{
+ extern RunTimeOpts rtOpts;
+
+ if (rtOpts.recordFP != NULL)
+ fclose(rtOpts.recordFP);
+
+ if ((rtOpts.recordFP = fopen(rtOpts.recordFile, "w")) == NULL)
+ PERROR("could not open sync recording file");
+ else
+ setlinebuf(rtOpts.recordFP);
+ return (rtOpts.recordFP != NULL);
+}
+
+void
+ptpdShutdown()
+{
+ netShutdown(&ptpClock->netPath);
+
+ free(ptpClock->foreign);
+ free(ptpClock);
+}
+
+PtpClock *
+ptpdStartup(int argc, char **argv, Integer16 * ret, RunTimeOpts * rtOpts)
+{
+ int c, nondaemon = 0, noclose = 0;
+
+ /* parse command line arguments */
+ while ((c = getopt(argc, argv, "?cf:dDR:xM:O:ta:w:b:u:l:o:e:hy:m:gpSs:i:v:n:k:rT:")) != -1) {
+ switch (c) {
+ case '?':
+ printf(
+ "\nUsage: ptpd [OPTION]\n\n"
+ "-? show this page\n"
+ "\n"
+ "-c run in command line (non-daemon) mode\n"
+ "-f FILE send stats to FILE\n"
+ "-S send output to syslog \n"
+ "-T set multicast time to live\n"
+ "-d display stats\n"
+ "-D display stats in .csv format\n"
+ "-R record data about sync packets in a file\n"
+ "\n"
+ "-x do not reset the clock if off by more than one second\n"
+ "-O do not reset the clock if offset is more than NUMBER nanoseconds\n"
+ "-M do not accept delay values of more than NUMBER nanoseconds\n"
+ "-t do not adjust the system clock\n"
+ "-a NUMBER,NUMBER specify clock servo P and I attenuations\n"
+ "-w NUMBER specify one way delay filter stiffness\n"
+ "\n"
+ "-b NAME bind PTP to network interface NAME\n"
+ "-u ADDRESS also send uni-cast to ADDRESS\n"
+ "-l NUMBER,NUMBER specify inbound, outbound latency in nsec\n"
+ "\n"
+ "-o NUMBER specify current UTC offset\n"
+ "-e NUMBER specify epoch NUMBER\n"
+ "-h specify half epoch\n"
+ "\n"
+ "-y NUMBER specify sync interval in 2^NUMBER sec\n"
+ "-m NUMBER specify max number of foreign master records\n"
+ "\n"
+ "-g run as slave only\n"
+ "-p make this a preferred clock\n"
+ "-s NUMBER specify system clock stratum\n"
+ "-i NAME specify system clock identifier\n"
+ "-v NUMBER specify system clock allen variance\n"
+ "\n"
+ "-n NAME specify PTP subdomain name (not related to IP or DNS)\n"
+ "\n"
+ "-k NUMBER,NUMBER send a management message of key, record, then exit\n"
+ "\n"
+ );
+ *ret = 0;
+ return 0;
+
+ case 'c':
+ nondaemon = 1;
+ break;
+
+ case 'S':
+ rtOpts->useSysLog = TRUE;
+ break;
+ case 'T':
+ rtOpts->ttl = atoi(optarg);
+ break;
+ case 'f':
+ strncpy(rtOpts->file, optarg, PATH_MAX);
+ if(logToFile())
+ noclose = 1;
+ else
+ PERROR("could not open output file");
+ break;
+
+ case 'd':
+#ifndef PTPD_DBG
+ rtOpts->displayStats = TRUE;
+#endif
+ break;
+
+ case 'D':
+#ifndef PTPD_DBG
+ rtOpts->displayStats = TRUE;
+ rtOpts->csvStats = TRUE;
+#endif
+ break;
+
+ case 'R':
+ strncpy(rtOpts->recordFile, optarg, PATH_MAX);
+ if (recordToFile())
+ noclose = 1;
+ else
+ PERROR("could not open quality file");
+ break;
+
+ case 'x':
+ rtOpts->noResetClock = TRUE;
+ break;
+
+ case 'O':
+ rtOpts->maxReset = atoi(optarg);
+ if (rtOpts->maxReset > 1000000000) {
+ PERROR("Use -x to prevent jumps of more"
+ " than one second.");
+ *ret = 1;
+ return (0);
+ }
+ break;
+ case 'M':
+ rtOpts->maxDelay = atoi(optarg);
+ if (rtOpts->maxDelay > 1000000000) {
+ PERROR("Use -x to prevent jumps of more"
+ " than one second.");
+ *ret = 1;
+ return (0);
+ }
+ break;
+ case 't':
+ rtOpts->noAdjust = TRUE;
+ break;
+
+ case 'a':
+ rtOpts->ap = strtol(optarg, &optarg, 0);
+ if (optarg[0])
+ rtOpts->ai = strtol(optarg + 1, 0, 0);
+ break;
+
+ case 'w':
+ rtOpts->s = strtol(optarg, &optarg, 0);
+ break;
+
+ case 'b':
+ memset(rtOpts->ifaceName, 0, IFACE_NAME_LENGTH);
+ strncpy(rtOpts->ifaceName, optarg, IFACE_NAME_LENGTH);
+ break;
+
+ case 'u':
+ strncpy(rtOpts->unicastAddress, optarg, NET_ADDRESS_LENGTH);
+ break;
+
+ case 'l':
+ rtOpts->inboundLatency.nanoseconds = strtol(optarg, &optarg, 0);
+ if (optarg[0])
+ rtOpts->outboundLatency.nanoseconds = strtol(optarg + 1, 0, 0);
+ break;
+
+ case 'o':
+ rtOpts->currentUtcOffset = strtol(optarg, &optarg, 0);
+ break;
+
+ case 'e':
+ rtOpts->epochNumber = strtoul(optarg, &optarg, 0);
+ break;
+
+ case 'h':
+ rtOpts->halfEpoch = TRUE;
+ break;
+
+ case 'y':
+ rtOpts->syncInterval = strtol(optarg, 0, 0);
+ break;
+
+ case 'm':
+ rtOpts->max_foreign_records = strtol(optarg, 0, 0);
+ if (rtOpts->max_foreign_records < 1)
+ rtOpts->max_foreign_records = 1;
+ break;
+
+ case 'g':
+ rtOpts->slaveOnly = TRUE;
+ break;
+
+ case 'p':
+ rtOpts->clockPreferred = TRUE;
+ break;
+
+ case 's':
+ rtOpts->clockStratum = strtol(optarg, 0, 0);
+ if (rtOpts->clockStratum <= 0)
+ rtOpts->clockStratum = 255;
+ break;
+
+ case 'i':
+ memset(rtOpts->clockIdentifier, 0, PTP_CODE_STRING_LENGTH);
+ strncpy(rtOpts->clockIdentifier, optarg, PTP_CODE_STRING_LENGTH);
+ break;
+
+ case 'v':
+ rtOpts->clockVariance = strtol(optarg, 0, 0);
+ break;
+
+ case 'n':
+ memset(rtOpts->subdomainName, 0, PTP_SUBDOMAIN_NAME_LENGTH);
+ strncpy(rtOpts->subdomainName, optarg, PTP_SUBDOMAIN_NAME_LENGTH);
+ break;
+
+ case 'k':
+ rtOpts->probe = TRUE;
+
+ rtOpts->probe_management_key = strtol(optarg, &optarg, 0);
+ if (optarg[0])
+ rtOpts->probe_record_key = strtol(optarg + 1, 0, 0);
+
+ nondaemon = 1;
+ break;
+
+ case 'r':
+ ERROR("The '-r' option has been removed because it is now the default behaviour.\n");
+ ERROR("Use the '-x' option to disable clock resetting.\n");
+ *ret = 1;
+ return 0;
+
+ default:
+ *ret = 1;
+ return 0;
+ }
+ }
+
+ ptpClock = (PtpClock *) calloc(1, sizeof(PtpClock));
+ if (!ptpClock) {
+ PERROR("failed to allocate memory for protocol engine data");
+ *ret = 2;
+ return 0;
+ } else {
+ DBG("allocated %d bytes for protocol engine data\n", (int)sizeof(PtpClock));
+ ptpClock->foreign = (ForeignMasterRecord *) calloc(rtOpts->max_foreign_records, sizeof(ForeignMasterRecord));
+ if (!ptpClock->foreign) {
+ PERROR("failed to allocate memory for foreign master data");
+ *ret = 2;
+ free(ptpClock);
+ return 0;
+ } else {
+ DBG("allocated %d bytes for foreign master data\n", (int)(rtOpts->max_foreign_records * sizeof(ForeignMasterRecord)));
+ }
+ }
+
+#ifndef PTPD_NO_DAEMON
+ if (!nondaemon) {
+ if (daemon(0, noclose) == -1) {
+ PERROR("failed to start as daemon");
+ *ret = 3;
+ return 0;
+ }
+ DBG("running as daemon\n");
+ }
+#endif
+
+ signal(SIGINT, catch_close);
+ signal(SIGTERM, catch_close);
+ signal(SIGHUP, catch_sighup);
+
+ *ret = 0;
+ return ptpClock;
+}
diff --git a/third_party/ptpd-1.1.0/src/dep/sys.c b/third_party/ptpd-1.1.0/src/dep/sys.c new file mode 100644 index 0000000..9e1221e --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep/sys.c @@ -0,0 +1,282 @@ +/**
+ * @file sys.c
+ * @date Tue Jul 20 16:19:46 2010
+ *
+ * @brief Code to call kernel time routines and also display server statistics.
+ *
+ *
+ */
+
+#include "../ptpd.h"
+
+
+int
+isTimeInternalNegative(const TimeInternal * p)
+{
+ return (p->seconds < 0) || (p->nanoseconds < 0);
+}
+
+
+int
+snprint_TimeInternal(char *s, int max_len, const TimeInternal * p)
+{
+ int len = 0;
+
+ if (isTimeInternalNegative(p))
+ len += snprintf(&s[len], max_len - len, "-");
+
+ len += snprintf(&s[len], max_len - len, "%d.%09d",
+ abs(p->seconds), abs(p->nanoseconds));
+
+ return len;
+}
+
+
+
+int
+snprint_ClockIdentity(char *s, int max_len, const Octet uuid[PTP_UUID_LENGTH], const char *info)
+{
+ int len = 0;
+ int i;
+
+ if (info)
+ len += snprintf(&s[len], max_len - len, "%s", info);
+
+ for (i = 0; ;) {
+ len += snprintf(&s[len], max_len - len, "%02x", (unsigned char) uuid[i]);
+
+ if (++i >= PTP_UUID_LENGTH)
+ break;
+
+ // uncomment the line below to print a separator after each byte except the last one
+ // len += snprintf(&s[len], max_len - len, "%s", "-");
+ }
+
+ return len;
+}
+
+
+int
+snprint_PortIdentity(char *s, int max_len, const Octet uuid[PTP_UUID_LENGTH],
+ UInteger16 portId, const char *info)
+{
+ int len = 0;
+
+ if (info)
+ len += snprintf(&s[len], max_len - len, "%s", info);
+
+ len += snprint_ClockIdentity(&s[len], max_len - len, uuid, NULL);
+ len += snprintf(&s[len], max_len - len, ":%02x", portId);
+ return len;
+}
+
+
+void
+message(int priority, const char *format, ...)
+{
+ extern RunTimeOpts rtOpts;
+ va_list ap;
+ va_start(ap, format);
+ if(rtOpts.useSysLog) {
+ static Boolean logOpened;
+ if(!logOpened) {
+ openlog("ptpd", 0, LOG_USER);
+ logOpened = TRUE;
+ }
+ vsyslog(priority, format, ap);
+ } else {
+ fprintf(stderr, "(ptpd %s) ",
+ priority == LOG_EMERG ? "emergency" :
+ priority == LOG_ALERT ? "alert" :
+ priority == LOG_CRIT ? "critical" :
+ priority == LOG_ERR ? "error" :
+ priority == LOG_WARNING ? "warning" :
+ priority == LOG_NOTICE ? "notice" :
+ priority == LOG_INFO ? "info" :
+ priority == LOG_DEBUG ? "debug" :
+ "???");
+ vfprintf(stderr, format, ap);
+ }
+ va_end(ap);
+}
+
+char *
+translatePortState(PtpClock *ptpClock)
+{
+ char *s;
+ switch(ptpClock->port_state) {
+ case PTP_INITIALIZING: s = "init"; break;
+ case PTP_FAULTY: s = "flt"; break;
+ case PTP_LISTENING: s = "lstn"; break;
+ case PTP_PASSIVE: s = "pass"; break;
+ case PTP_UNCALIBRATED: s = "uncl"; break;
+ case PTP_SLAVE: s = "slv"; break;
+ case PTP_PRE_MASTER: s = "pmst"; break;
+ case PTP_MASTER: s = "mst"; break;
+ case PTP_DISABLED: s = "dsbl"; break;
+ default: s = "?"; break;
+ }
+ return s;
+}
+
+void
+displayStats(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ static int start = 1;
+ static char sbuf[SCREEN_BUFSZ];
+ int len = 0;
+ struct timeval now;
+ char time_str[MAXTIMESTR];
+
+ if (start && rtOpts->csvStats) {
+ start = 0;
+ printf("timestamp, state, clock ID, one way delay, "
+ "offset from master, master to slave, "
+ "slave to master, drift, variance");
+ fflush(stdout);
+ }
+ memset(sbuf, ' ', sizeof(sbuf));
+
+ gettimeofday(&now, 0);
+ strftime(time_str, MAXTIMESTR, "%Y-%m-%d %X", localtime(&now.tv_sec));
+
+ len += snprintf(sbuf + len, sizeof(sbuf) - len, "%s%s:%06d, %s",
+ rtOpts->csvStats ? "\n" : "\rstate: ",
+ time_str, (int)now.tv_usec,
+ translatePortState(ptpClock));
+
+ if (ptpClock->port_state == PTP_SLAVE) {
+ len += snprint_PortIdentity(sbuf + len, sizeof(sbuf) - len,
+ ptpClock->parent_uuid, ptpClock->parent_port_id, ", ");
+
+ /*
+ * if grandmaster ID differs from parent port ID then also
+ * print GM ID
+ */
+ if (memcmp(ptpClock->grandmaster_uuid_field,
+ ptpClock->parent_uuid, PTP_UUID_LENGTH)) {
+ len += snprint_ClockIdentity(sbuf + len,
+ sizeof(sbuf) - len,
+ ptpClock->grandmaster_uuid_field,
+ " GM:");
+ }
+
+ len += snprintf(sbuf + len, sizeof(sbuf) - len, ", ");
+
+ if (!rtOpts->csvStats)
+ len += snprintf(sbuf + len,
+ sizeof(sbuf) - len, "owd: ");
+
+ len += snprint_TimeInternal(sbuf + len, sizeof(sbuf) - len,
+ &ptpClock->one_way_delay);
+
+ len += snprintf(sbuf + len, sizeof(sbuf) - len, ", ");
+
+ if (!rtOpts->csvStats)
+ len += snprintf(sbuf + len, sizeof(sbuf) - len,
+ "ofm: ");
+
+ len += snprint_TimeInternal(sbuf + len, sizeof(sbuf) - len,
+ &ptpClock->offset_from_master);
+
+ len += snprintf(sbuf + len, sizeof(sbuf) - len,
+ ", %s%d.%09d" ", %s%d.%09d",
+ rtOpts->csvStats ? "" : "stm: ",
+ ptpClock->slave_to_master_delay.seconds,
+ abs(ptpClock->slave_to_master_delay.nanoseconds),
+ rtOpts->csvStats ? "" : "mts: ",
+ ptpClock->master_to_slave_delay.seconds,
+ abs(ptpClock->master_to_slave_delay.nanoseconds));
+
+ len += snprintf(sbuf + len, sizeof(sbuf) - len,
+ ", %s%d",
+ rtOpts->csvStats ? "" : "drift: ",
+ ptpClock->observed_drift);
+
+ len += snprintf(sbuf + len, sizeof(sbuf) - len,
+ ", %s%d",
+ rtOpts->csvStats ? "" : "var: ",
+ ptpClock->observed_variance);
+ }
+ else {
+ if (ptpClock->port_state == PTP_MASTER) {
+ len += snprint_ClockIdentity(sbuf + len, sizeof(sbuf) - len,
+ ptpClock->clock_uuid_field, " (ID:");
+ len += snprintf(sbuf + len, sizeof(sbuf) - len, ")");
+ }
+ }
+ write(1, sbuf, rtOpts->csvStats ? len : SCREEN_MAXSZ + 1);
+}
+
+Boolean
+nanoSleep(TimeInternal * t)
+{
+ struct timespec ts, tr;
+
+ ts.tv_sec = t->seconds;
+ ts.tv_nsec = t->nanoseconds;
+
+ if (nanosleep(&ts, &tr) < 0) {
+ t->seconds = tr.tv_sec;
+ t->nanoseconds = tr.tv_nsec;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void
+getTime(TimeInternal * time)
+{
+#if defined(linux)
+
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ time->seconds = tv.tv_sec;
+ time->nanoseconds = tv.tv_usec * 1000;
+
+#else /* FreeBSD */
+
+ struct timespec tp;
+ if (clock_gettime(CLOCK_REALTIME, &tp) < 0) {
+ PERROR("clock_gettime() failed, exiting.");
+ exit(0);
+ }
+ time->seconds = tp.tv_sec;
+ time->nanoseconds = tp.tv_nsec;
+#endif /* FreeBSD or Linux */
+}
+
+void
+setTime(TimeInternal * time)
+{
+ struct timeval tv;
+
+ tv.tv_sec = time->seconds;
+ tv.tv_usec = time->nanoseconds / 1000;
+ settimeofday(&tv, 0);
+
+ NOTIFY("resetting system clock to %ds %dns\n",
+ time->seconds, time->nanoseconds);
+}
+
+UInteger16
+getRand(UInteger32 * seed)
+{
+ return rand_r((unsigned int *)seed);
+}
+
+Boolean
+adjFreq(Integer32 adj)
+{
+ struct timex t;
+
+ if (adj > ADJ_FREQ_MAX)
+ adj = ADJ_FREQ_MAX;
+ else if (adj < -ADJ_FREQ_MAX)
+ adj = -ADJ_FREQ_MAX;
+
+ t.modes = MOD_FREQUENCY;
+ t.freq = adj * ((1 << 16) / 1000);
+
+ return !adjtimex(&t);
+}
diff --git a/third_party/ptpd-1.1.0/src/dep/timer.c b/third_party/ptpd-1.1.0/src/dep/timer.c new file mode 100644 index 0000000..4bd7f80 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/dep/timer.c @@ -0,0 +1,96 @@ +/**
+ * @file timer.c
+ * @date Wed Jun 23 09:41:26 2010
+ *
+ * @brief The timers which run the state machine.
+ *
+ * Timers in the PTP daemon are run off of the signal system.
+ */
+
+#include "../ptpd.h"
+
+#define TIMER_INTERVAL 1
+int elapsed;
+
+void
+catch_alarm(int sig)
+{
+ elapsed += TIMER_INTERVAL;
+
+ DBGV("catch_alarm: elapsed %d\n", elapsed);
+}
+
+void
+initTimer(void)
+{
+ struct itimerval itimer;
+
+ DBG("initTimer\n");
+
+ signal(SIGALRM, SIG_IGN);
+
+ elapsed = 0;
+ itimer.it_value.tv_sec = itimer.it_interval.tv_sec = TIMER_INTERVAL;
+ itimer.it_value.tv_usec = itimer.it_interval.tv_usec = 0;
+
+ signal(SIGALRM, catch_alarm);
+ setitimer(ITIMER_REAL, &itimer, 0);
+}
+
+void
+timerUpdate(IntervalTimer * itimer)
+{
+ int i, delta;
+
+ delta = elapsed;
+ elapsed = 0;
+
+ if (delta <= 0)
+ return;
+
+ for (i = 0; i < TIMER_ARRAY_SIZE; ++i) {
+ if (itimer[i].interval > 0 && (itimer[i].left -= delta) <= 0) {
+ itimer[i].left = itimer[i].interval;
+ itimer[i].expire = TRUE;
+ DBGV("timerUpdate: timer %u expired\n", i);
+ }
+ }
+}
+
+void
+timerStop(UInteger16 index, IntervalTimer * itimer)
+{
+ if (index >= TIMER_ARRAY_SIZE)
+ return;
+
+ itimer[index].interval = 0;
+}
+
+void
+timerStart(UInteger16 index, UInteger16 interval, IntervalTimer * itimer)
+{
+ if (index >= TIMER_ARRAY_SIZE)
+ return;
+
+ itimer[index].expire = FALSE;
+ itimer[index].left = interval;
+ itimer[index].interval = itimer[index].left;
+
+ DBGV("timerStart: set timer %d to %d\n", index, interval);
+}
+
+Boolean
+timerExpired(UInteger16 index, IntervalTimer * itimer)
+{
+ timerUpdate(itimer);
+
+ if (index >= TIMER_ARRAY_SIZE)
+ return FALSE;
+
+ if (!itimer[index].expire)
+ return FALSE;
+
+ itimer[index].expire = FALSE;
+
+ return TRUE;
+}
diff --git a/third_party/ptpd-1.1.0/src/probe.c b/third_party/ptpd-1.1.0/src/probe.c new file mode 100644 index 0000000..8fdadcf --- /dev/null +++ b/third_party/ptpd-1.1.0/src/probe.c @@ -0,0 +1,284 @@ +/**
+ * @file probe.c
+ * @date Tue Jul 20 16:13:30 2010
+ *
+ * @brief Management packet handling
+ *
+ *
+ */
+
+#include "ptpd.h"
+
+#define KEY_ARRAY_LEN 6
+UInteger8 management_key_array[KEY_ARRAY_LEN] =
+{PTP_MM_OBTAIN_IDENTITY, PTP_MM_GET_DEFAULT_DATA_SET, PTP_MM_GET_CURRENT_DATA_SET,
+PTP_MM_GET_PARENT_DATA_SET, PTP_MM_GET_PORT_DATA_SET, PTP_MM_GET_GLOBAL_TIME_DATA_SET};
+
+void displayHeader(MsgHeader *);
+void displayManagement(MsgHeader *, MsgManagement *);
+
+void
+probe(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ UInteger16 i;
+ UInteger16 length;
+ TimeInternal interval, now, finish, timestamp;
+
+ /* check */
+ if (rtOpts->probe_management_key == PTP_MM_UPDATE_DEFAULT_DATA_SET
+ || rtOpts->probe_management_key == PTP_MM_UPDATE_GLOBAL_TIME_PROPERTIES
+ || rtOpts->probe_management_key == PTP_MM_SET_SYNC_INTERVAL) {
+ ERROR("send not supported for that management message\n");
+ return;
+ }
+ /* init */
+ if (!netInit(&ptpClock->netPath, rtOpts, ptpClock)) {
+ ERROR("failed to initialize network\n");
+ return;
+ }
+ initData(rtOpts, ptpClock);
+ msgPackHeader(ptpClock->msgObuf, ptpClock);
+
+ memset(&ptpClock->msgTmp.manage, 0, sizeof(MsgManagement));
+ ptpClock->msgTmp.manage.targetCommunicationTechnology = PTP_DEFAULT;
+
+ /* send */
+ for (i = 0; i < KEY_ARRAY_LEN; ++i) {
+ if (rtOpts->probe_management_key > 0) {
+ ptpClock->msgTmp.manage.managementMessageKey = rtOpts->probe_management_key;
+ ptpClock->msgTmp.manage.recordKey = rtOpts->probe_record_key;
+ } else
+ ptpClock->msgTmp.manage.managementMessageKey = management_key_array[i];
+
+ if (!(length = msgPackManagement(ptpClock->msgObuf, &ptpClock->msgTmp.manage, ptpClock))) {
+ ERROR("failed to pack management message\n");
+ return;
+ }
+ printf("\n(sending managementMessageKey %hhu)\n", ptpClock->msgTmp.manage.managementMessageKey);
+
+ if (!netSendGeneral(ptpClock->msgObuf, length, &ptpClock->netPath)) {
+ ERROR("failed to send message\n");
+ return;
+ }
+ if (rtOpts->probe_management_key > 0)
+ break;
+ }
+
+ getTime(&finish);
+ finish.seconds += PTP_SYNC_INTERVAL_TIMEOUT(ptpClock->sync_interval);
+ for (;;) {
+ interval.seconds = PTP_SYNC_INTERVAL_TIMEOUT(ptpClock->sync_interval);
+ interval.nanoseconds = 0;
+ netSelect(&interval, &ptpClock->netPath);
+
+ netRecvEvent(ptpClock->msgIbuf, ×tamp, &ptpClock->netPath);
+
+ if (netRecvGeneral(ptpClock->msgIbuf, &ptpClock->netPath)) {
+ msgUnpackHeader(ptpClock->msgIbuf, &ptpClock->msgTmpHeader);
+
+ if (ptpClock->msgTmpHeader.control == PTP_MANAGEMENT_MESSAGE) {
+ msgUnpackManagement(ptpClock->msgIbuf, &ptpClock->msgTmp.manage);
+ msgUnpackManagementPayload(ptpClock->msgIbuf, &ptpClock->msgTmp.manage);
+
+ displayManagement(&ptpClock->msgTmpHeader, &ptpClock->msgTmp.manage);
+ }
+ fflush(stdout);
+ }
+ getTime(&now);
+ if (now.seconds > finish.seconds || (now.seconds == finish.seconds
+ && now.nanoseconds > finish.nanoseconds))
+ break;
+ }
+
+ /* done */
+ printf("\n");
+ ptpdShutdown();
+
+ exit(0);
+}
+
+void
+displayHeader(MsgHeader * header)
+{
+ printf(
+ " sourceCommunicationTechnology %hhu\n"
+ " sourceUuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n"
+ " sourcePortId %hu\n",
+ header->sourceCommunicationTechnology,
+ header->sourceUuid[0], header->sourceUuid[1], header->sourceUuid[2],
+ header->sourceUuid[3], header->sourceUuid[4], header->sourceUuid[5],
+ header->sourcePortId);
+}
+
+void
+displayManagement(MsgHeader * header, MsgManagement * manage)
+{
+ Integer16 i;
+
+ switch (manage->managementMessageKey) {
+ case PTP_MM_CLOCK_IDENTITY:
+ printf("\n");
+ displayHeader(header);
+ printf(" managementMessageKey %hhu (PTP_MM_CLOCK_IDENTITY)\n", manage->managementMessageKey);
+ printf(" clockCommunicationTechnology %hhu\n", manage->payload.clockIdentity.clockCommunicationTechnology);
+ printf(" clockUuidField %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ manage->payload.clockIdentity.clockUuidField[0], manage->payload.clockIdentity.clockUuidField[1],
+ manage->payload.clockIdentity.clockUuidField[2], manage->payload.clockIdentity.clockUuidField[3],
+ manage->payload.clockIdentity.clockUuidField[4], manage->payload.clockIdentity.clockUuidField[5]);
+ printf(" clockPortField %hu\n", manage->payload.clockIdentity.clockPortField);
+ printf(" manufacturerIdentity ");
+ for (i = 0; i < MANUFACTURER_ID_LENGTH && manage->payload.clockIdentity.manufacturerIdentity[i]; ++i)
+ putchar(manage->payload.clockIdentity.manufacturerIdentity[i]);
+ putchar('\n');
+ break;
+
+ case PTP_MM_DEFAULT_DATA_SET:
+ printf("\n");
+ displayHeader(header);
+ printf(" managementMessageKey %hhu (PTP_MM_DEFAULT_DATA_SET)\n", manage->managementMessageKey);
+ printf(" clockCommunicationTechnology %hhu\n", manage->payload.defaultData.clockCommunicationTechnology);
+ printf(" clockUuidField %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ manage->payload.defaultData.clockUuidField[0], manage->payload.defaultData.clockUuidField[1],
+ manage->payload.defaultData.clockUuidField[2], manage->payload.defaultData.clockUuidField[3],
+ manage->payload.defaultData.clockUuidField[4], manage->payload.defaultData.clockUuidField[5]);
+ printf(" clockPortField %hu\n", manage->payload.defaultData.clockPortField);
+ printf(" clockStratum %hhu\n", manage->payload.defaultData.clockStratum);
+ printf(" clockIdentifier ");
+ for (i = 0; i < PTP_CODE_STRING_LENGTH && manage->payload.defaultData.clockIdentifier[i]; ++i)
+ putchar(manage->payload.defaultData.clockIdentifier[i]);
+ putchar('\n');
+ printf(" clockVariance %hd\n", manage->payload.defaultData.clockVariance);
+ printf(" clockFollowupCapable %hhu\n", manage->payload.defaultData.clockFollowupCapable);
+ printf(" preferred %hhu\n", manage->payload.defaultData.preferred);
+ printf(" initializable %hhu\n", manage->payload.defaultData.initializable);
+ printf(" externalTiming %hhu\n", manage->payload.defaultData.externalTiming);
+ printf(" isBoundaryClock %hhu\n", manage->payload.defaultData.isBoundaryClock);
+ printf(" syncInterval %hhd\n", manage->payload.defaultData.syncInterval);
+ printf(" subdomainName ");
+ for (i = 0; i < PTP_SUBDOMAIN_NAME_LENGTH && manage->payload.defaultData.subdomainName[i]; ++i)
+ putchar(manage->payload.defaultData.subdomainName[i]);
+ putchar('\n');
+ printf(" numberPorts %hu\n", manage->payload.defaultData.numberPorts);
+ printf(" numberForeignRecords %hu\n", manage->payload.defaultData.numberForeignRecords);
+ break;
+
+ case PTP_MM_CURRENT_DATA_SET:
+ printf("\n");
+ displayHeader(header);
+ printf(" managementMessageKey %hhu (PTP_MM_CURRENT_DATA_SET)\n", manage->managementMessageKey);
+ printf(" stepsRemoved %hu\n", manage->payload.current.stepsRemoved);
+ printf(" offsetFromMaster %s%u.%09d\n",
+ manage->payload.current.offsetFromMaster.nanoseconds & 0x80000000 ? "-" : "",
+ manage->payload.current.offsetFromMaster.seconds,
+ manage->payload.current.offsetFromMaster.nanoseconds & ~0x80000000);
+ printf(" oneWayDelay %s%u.%09d\n",
+ manage->payload.current.oneWayDelay.nanoseconds & 0x80000000 ? "-" : "",
+ manage->payload.current.oneWayDelay.seconds,
+ manage->payload.current.oneWayDelay.nanoseconds & ~0x80000000);
+ break;
+
+ case PTP_MM_PARENT_DATA_SET:
+ printf("\n");
+ displayHeader(header);
+ printf(" managementMessageKey %hhu (PTP_MM_PARENT_DATA_SET)\n", manage->managementMessageKey);
+ printf(" parentCommunicationTechnology %hhu\n", manage->payload.parent.parentCommunicationTechnology);
+ printf(" parentUuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ manage->payload.parent.parentUuid[0], manage->payload.parent.parentUuid[1],
+ manage->payload.parent.parentUuid[2], manage->payload.parent.parentUuid[3],
+ manage->payload.parent.parentUuid[4], manage->payload.parent.parentUuid[5]);
+ printf(" parentPortId %hu\n", manage->payload.parent.parentPortId);
+ printf(" parentLastSyncSequenceNumber %hu\n", manage->payload.parent.parentLastSyncSequenceNumber);
+ printf(" parentFollowupCapable %hhu\n", manage->payload.parent.parentFollowupCapable);
+ printf(" parentExternalTiming %hhu\n", manage->payload.parent.parentExternalTiming);
+ printf(" parentVariance %hd\n", manage->payload.parent.parentVariance);
+ printf(" parentStats %hhu\n", manage->payload.parent.parentStats);
+ printf(" observedVariance %hd\n", manage->payload.parent.observedVariance);
+ printf(" observedDrift %d\n", manage->payload.parent.observedDrift);
+ printf(" utcReasonable %hhu\n", manage->payload.parent.utcReasonable);
+ printf(" grandmasterCommunicationTechnology %hhu\n", manage->payload.parent.grandmasterCommunicationTechnology);
+ printf(" grandmasterUuidField %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ manage->payload.parent.grandmasterUuidField[0], manage->payload.parent.grandmasterUuidField[1],
+ manage->payload.parent.grandmasterUuidField[2], manage->payload.parent.grandmasterUuidField[3],
+ manage->payload.parent.grandmasterUuidField[4], manage->payload.parent.grandmasterUuidField[5]);
+ printf(" grandmasterPortIdField %hu\n", manage->payload.parent.grandmasterPortIdField);
+ printf(" grandmasterStratum %hhu\n", manage->payload.parent.grandmasterStratum);
+ printf(" grandmasterIdentifier ");
+ for (i = 0; i < PTP_CODE_STRING_LENGTH && manage->payload.parent.grandmasterIdentifier[i]; ++i)
+ putchar(manage->payload.parent.grandmasterIdentifier[i]);
+ putchar('\n');
+ printf(" grandmasterVariance %hd\n", manage->payload.parent.grandmasterVariance);
+ printf(" grandmasterPreferred %hhu\n", manage->payload.parent.grandmasterPreferred);
+ printf(" grandmasterIsBoundaryClock %hhu\n", manage->payload.parent.grandmasterIsBoundaryClock);
+ printf(" grandmasterSequenceNumber %hu\n", manage->payload.parent.grandmasterSequenceNumber);
+ break;
+
+ case PTP_MM_PORT_DATA_SET:
+ printf("\n");
+ displayHeader(header);
+ printf(" managementMessageKey %hhu (PTP_MM_PORT_DATA_SET)\n", manage->managementMessageKey);
+ printf(" returnedPortNumber %hu\n", manage->payload.port.returnedPortNumber);
+ printf(" portState %hhu\n", manage->payload.port.portState);
+ printf(" lastSyncEventSequenceNumber %hu\n", manage->payload.port.lastSyncEventSequenceNumber);
+ printf(" lastGeneralEventSequenceNumber %hu\n", manage->payload.port.lastGeneralEventSequenceNumber);
+ printf(" portCommunicationTechnology %hhu\n", manage->payload.port.portCommunicationTechnology);
+ printf(" portUuidField %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ manage->payload.port.portUuidField[0], manage->payload.port.portUuidField[1],
+ manage->payload.port.portUuidField[2], manage->payload.port.portUuidField[3],
+ manage->payload.port.portUuidField[4], manage->payload.port.portUuidField[5]);
+ printf(" portIdField %hu\n", manage->payload.port.portIdField);
+ printf(" burstEnabled %hhu\n", manage->payload.port.burstEnabled);
+ printf(" subdomainAddressOctets %hhu\n", manage->payload.port.subdomainAddressOctets);
+ printf(" eventPortAddressOctets %hhu\n", manage->payload.port.eventPortAddressOctets);
+ printf(" generalPortAddressOctets %hhu\n", manage->payload.port.generalPortAddressOctets);
+ printf(" subdomainAddress ");
+ printf("%hhu", manage->payload.port.subdomainAddress[0]);
+ for (i = 1; i < SUBDOMAIN_ADDRESS_LENGTH; ++i)
+ printf(".%hhu", manage->payload.port.subdomainAddress[i]);
+ putchar('\n');
+ printf(" eventPortAddress %hu\n", *(UInteger16 *) manage->payload.port.eventPortAddress);
+ printf(" generalPortAddress %hu\n", *(UInteger16 *) manage->payload.port.generalPortAddress);
+ break;
+
+ case PTP_MM_GLOBAL_TIME_DATA_SET:
+ printf("\n");
+ displayHeader(header);
+ printf(" managementMessageKey %hhu (PTP_MM_GLOBAL_TIME_DATA_SET)\n", manage->managementMessageKey);
+ printf(" localTime %s%u.%09d\n",
+ manage->payload.globalTime.localTime.nanoseconds & 0x80000000 ? "-" : "",
+ manage->payload.globalTime.localTime.seconds,
+ manage->payload.globalTime.localTime.nanoseconds & ~0x80000000);
+ printf(" currentUtcOffset %hd\n", manage->payload.globalTime.currentUtcOffset);
+ printf(" leap59 %hhu\n", manage->payload.globalTime.leap59);
+ printf(" leap61 %hhu\n", manage->payload.globalTime.leap61);
+ printf(" epochNumber %hu\n", manage->payload.globalTime.epochNumber);
+ break;
+
+
+ case PTP_MM_FOREIGN_DATA_SET:
+ printf("\n");
+ displayHeader(header);
+ printf(" managementMessageKey %hhu (PTP_MM_FOREIGN_DATA_SET)\n", manage->managementMessageKey);
+ printf(" returnedPortNumber %hu\n", manage->payload.foreign.returnedPortNumber);
+ printf(" returnedRecordNumber %hu\n", manage->payload.foreign.returnedRecordNumber);
+ printf(" foreignMasterCommunicationTechnology %hu\n", manage->payload.foreign.foreignMasterCommunicationTechnology);
+ printf(" foreignMasterUuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ manage->payload.foreign.foreignMasterUuid[0], manage->payload.foreign.foreignMasterUuid[1],
+ manage->payload.foreign.foreignMasterUuid[2], manage->payload.foreign.foreignMasterUuid[3],
+ manage->payload.foreign.foreignMasterUuid[4], manage->payload.foreign.foreignMasterUuid[5]);
+
+ printf(" foreignMasterPortId %hu\n", manage->payload.foreign.foreignMasterPortId);
+ printf(" foreignMasterSyncs %hu\n", manage->payload.foreign.foreignMasterSyncs);
+ break;
+
+ case PTP_MM_NULL:
+ printf("\n");
+ displayHeader(header);
+ printf(" managementMessageKey %hhu (NULL)\n", manage->managementMessageKey);
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+}
diff --git a/third_party/ptpd-1.1.0/src/protocol.c b/third_party/ptpd-1.1.0/src/protocol.c new file mode 100644 index 0000000..4db8e95 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/protocol.c @@ -0,0 +1,865 @@ +/**
+ * @file protocol.c
+ * @date Wed Jun 23 09:40:39 2010
+ *
+ * @brief The code that handles the IEEE-1588 protocol and state machine
+ *
+ *
+ */
+
+#include "ptpd.h"
+
+Boolean doInit(RunTimeOpts *, PtpClock *);
+void doState(RunTimeOpts *, PtpClock *);
+void toState(UInteger8, RunTimeOpts *, PtpClock *);
+
+void handle(RunTimeOpts *, PtpClock *);
+void handleSync(MsgHeader *, Octet *, ssize_t, TimeInternal *, Boolean, RunTimeOpts *, PtpClock *);
+void handleFollowUp(MsgHeader *, Octet *, ssize_t, Boolean, RunTimeOpts *, PtpClock *);
+void handleDelayReq(MsgHeader *, Octet *, ssize_t, TimeInternal *, Boolean, RunTimeOpts *, PtpClock *);
+void handleDelayResp(MsgHeader *, Octet *, ssize_t, Boolean, RunTimeOpts *, PtpClock *);
+void handleManagement(MsgHeader *, Octet *, ssize_t, Boolean, RunTimeOpts *, PtpClock *);
+
+void issueSync(RunTimeOpts *, PtpClock *);
+void issueFollowup(TimeInternal *, RunTimeOpts *, PtpClock *);
+void issueDelayReq(RunTimeOpts *, PtpClock *);
+void issueDelayResp(TimeInternal *, MsgHeader *, RunTimeOpts *, PtpClock *);
+void issueManagement(MsgHeader *, MsgManagement *, RunTimeOpts *, PtpClock *);
+
+MsgSync *addForeign(Octet *, MsgHeader *, PtpClock *);
+
+/* Initialize the PTPD stack.
+ *
+ * NB: This function was added by TI!
+ */
+void protocol_first(RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+ DBG("event POWERUP\n");
+
+ toState(PTP_INITIALIZING, rtOpts, ptpClock);
+
+ if(ptpClock->port_state != PTP_INITIALIZING)
+ doState(rtOpts, ptpClock);
+ else if(!doInit(rtOpts, ptpClock))
+ return;
+
+ if(ptpClock->message_activity)
+ DBGV("activity\n");
+#if 0
+ else
+ DBGV("no activity\n");
+#endif
+}
+
+/* Perform one iteration of the PTPD state machine. This function does not
+ * block and may be used in non-RTOS systems where the main loop needs to do
+ * more than process the PTPD stack.
+ *
+ * NB: This function was added by TI!
+ */
+void protocol_loop(RunTimeOpts *rtOpts, PtpClock *ptpClock)
+{
+ if(ptpClock->port_state != PTP_INITIALIZING)
+ doState(rtOpts, ptpClock);
+ else if(!doInit(rtOpts, ptpClock))
+ return;
+
+ if(ptpClock->message_activity)
+ DBGV("activity\n");
+#if 0
+ else
+ DBGV("no activity\n");
+#endif
+}
+
+/* loop forever. doState() has a switch for the actions and events to be
+ checked for 'port_state'. the actions and events may or may not change
+ 'port_state' by calling toState(), but once they are done we loop around
+ again and perform the actions required for the new 'port_state'. */
+void
+protocol(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ DBG("event POWERUP\n");
+
+ toState(PTP_INITIALIZING, rtOpts, ptpClock);
+
+ DBGV("Debug Initializing...");
+
+ for (;;) {
+ if (ptpClock->port_state != PTP_INITIALIZING)
+ doState(rtOpts, ptpClock);
+ else if (!doInit(rtOpts, ptpClock))
+ return;
+
+ if (ptpClock->message_activity)
+ DBGV("activity\n");
+ else
+ DBGV("no activity\n");
+ }
+}
+
+Boolean
+doInit(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ DBG("manufacturerIdentity: %s\n", MANUFACTURER_ID);
+
+ /* initialize networking */
+ netShutdown(&ptpClock->netPath);
+ if (!netInit(&ptpClock->netPath, rtOpts, ptpClock)) {
+ ERROR("failed to initialize network\n");
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ return FALSE;
+ }
+ /* initialize other stuff */
+ initData(rtOpts, ptpClock);
+ initTimer();
+ initClock(rtOpts, ptpClock);
+ m1(ptpClock);
+ msgPackHeader(ptpClock->msgObuf, ptpClock);
+
+ DBG("sync message interval: %d\n", PTP_SYNC_INTERVAL_TIMEOUT(ptpClock->sync_interval));
+ DBG("clock identifier: %s\n", ptpClock->clock_identifier);
+ DBG("256*log2(clock variance): %d\n", ptpClock->clock_variance);
+ DBG("clock stratum: %d\n", ptpClock->clock_stratum);
+ DBG("clock preferred?: %s\n", ptpClock->preferred ? "yes" : "no");
+ DBG("bound interface name: %s\n", rtOpts->ifaceName);
+ DBG("communication technology: %d\n", ptpClock->port_communication_technology);
+ DBG("uuid: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ ptpClock->port_uuid_field[0], ptpClock->port_uuid_field[1], ptpClock->port_uuid_field[2],
+ ptpClock->port_uuid_field[3], ptpClock->port_uuid_field[4], ptpClock->port_uuid_field[5]);
+ DBG("PTP subdomain name: %s\n", ptpClock->subdomain_name);
+ DBG("subdomain address: %hhx.%hhx.%hhx.%hhx\n",
+ ptpClock->subdomain_address[0], ptpClock->subdomain_address[1],
+ ptpClock->subdomain_address[2], ptpClock->subdomain_address[3]);
+ DBG("event port address: %hhx %hhx\n",
+ ptpClock->event_port_address[0], ptpClock->event_port_address[1]);
+ DBG("general port address: %hhx %hhx\n",
+ ptpClock->general_port_address[0], ptpClock->general_port_address[1]);
+
+ toState(PTP_LISTENING, rtOpts, ptpClock);
+ return TRUE;
+}
+
+/* handle actions and events for 'port_state' */
+void
+doState(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ UInteger8 state;
+
+ ptpClock->message_activity = FALSE;
+
+ switch (ptpClock->port_state) {
+ case PTP_LISTENING:
+ case PTP_PASSIVE:
+ case PTP_SLAVE:
+ case PTP_MASTER:
+ if (ptpClock->record_update) {
+ ptpClock->record_update = FALSE;
+ state = bmc(ptpClock->foreign, rtOpts, ptpClock);
+ if (state != ptpClock->port_state)
+ toState(state, rtOpts, ptpClock);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (ptpClock->port_state) {
+ case PTP_FAULTY:
+ /* imaginary troubleshooting */
+
+ DBG("event FAULT_CLEARED\n");
+ toState(PTP_INITIALIZING, rtOpts, ptpClock);
+ return;
+
+ case PTP_LISTENING:
+ case PTP_PASSIVE:
+ case PTP_UNCALIBRATED:
+ case PTP_SLAVE:
+ handle(rtOpts, ptpClock);
+
+ if (timerExpired(SYNC_RECEIPT_TIMER, ptpClock->itimer)) {
+ DBG("event SYNC_RECEIPT_TIMEOUT_EXPIRES\n");
+ ptpClock->number_foreign_records = 0;
+ ptpClock->foreign_record_i = 0;
+ if (!rtOpts->slaveOnly && ptpClock->clock_stratum != 255) {
+ m1(ptpClock);
+ toState(PTP_MASTER, rtOpts, ptpClock);
+ } else if (ptpClock->port_state != PTP_LISTENING)
+ toState(PTP_LISTENING, rtOpts, ptpClock);
+ }
+ break;
+
+ case PTP_MASTER:
+ if (timerExpired(SYNC_INTERVAL_TIMER, ptpClock->itimer)) {
+ DBGV("event SYNC_INTERVAL_TIMEOUT_EXPIRES\n");
+ issueSync(rtOpts, ptpClock);
+ }
+ handle(rtOpts, ptpClock);
+
+ if (rtOpts->slaveOnly || ptpClock->clock_stratum == 255)
+ toState(PTP_LISTENING, rtOpts, ptpClock);
+
+ break;
+
+ case PTP_DISABLED:
+ handle(rtOpts, ptpClock);
+ break;
+
+ default:
+ DBG("do unrecognized state\n");
+ break;
+ }
+}
+
+/* perform actions required when leaving 'port_state' and entering 'state' */
+void
+toState(UInteger8 state, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ ptpClock->message_activity = TRUE;
+
+ /* leaving state tasks */
+ switch (ptpClock->port_state) {
+ case PTP_MASTER:
+ timerStop(SYNC_INTERVAL_TIMER, ptpClock->itimer);
+ timerStart(SYNC_RECEIPT_TIMER, PTP_SYNC_RECEIPT_TIMEOUT(ptpClock->sync_interval), ptpClock->itimer);
+ break;
+
+ case PTP_SLAVE:
+ initClock(rtOpts, ptpClock);
+ break;
+
+ default:
+ break;
+ }
+
+ /* entering state tasks */
+ switch (state) {
+ case PTP_INITIALIZING:
+ DBG("state PTP_INITIALIZING\n");
+ timerStop(SYNC_RECEIPT_TIMER, ptpClock->itimer);
+
+ ptpClock->port_state = PTP_INITIALIZING;
+ break;
+
+ case PTP_FAULTY:
+ DBG("state PTP_FAULTY\n");
+ timerStop(SYNC_RECEIPT_TIMER, ptpClock->itimer);
+
+ ptpClock->port_state = PTP_FAULTY;
+ break;
+
+ case PTP_DISABLED:
+ DBG("state change to PTP_DISABLED\n");
+ timerStop(SYNC_RECEIPT_TIMER, ptpClock->itimer);
+
+ ptpClock->port_state = PTP_DISABLED;
+ break;
+
+ case PTP_LISTENING:
+ DBG("state PTP_LISTENING\n");
+
+ timerStart(SYNC_RECEIPT_TIMER, PTP_SYNC_RECEIPT_TIMEOUT(ptpClock->sync_interval), ptpClock->itimer);
+
+ ptpClock->port_state = PTP_LISTENING;
+ break;
+
+ case PTP_MASTER:
+ DBG("state PTP_MASTER\n");
+
+ if (ptpClock->port_state != PTP_PRE_MASTER)
+ timerStart(SYNC_INTERVAL_TIMER, PTP_SYNC_INTERVAL_TIMEOUT(ptpClock->sync_interval), ptpClock->itimer);
+
+ timerStop(SYNC_RECEIPT_TIMER, ptpClock->itimer);
+
+ ptpClock->port_state = PTP_MASTER;
+ break;
+
+ case PTP_PASSIVE:
+ DBG("state PTP_PASSIVE\n");
+ ptpClock->port_state = PTP_PASSIVE;
+ break;
+
+ case PTP_UNCALIBRATED:
+ DBG("state PTP_UNCALIBRATED\n");
+ ptpClock->port_state = PTP_UNCALIBRATED;
+ break;
+
+ case PTP_SLAVE:
+ DBG("state PTP_PTP_SLAVE\n");
+
+ initClock(rtOpts, ptpClock);
+
+ /*
+ * R is chosen to allow a few syncs before we first get a
+ * one-way delay estimate
+ */
+ /*
+ * this is to allow the offset filter to fill for an
+ * accurate initial clock reset
+ */
+ ptpClock->Q = 0;
+ ptpClock->R = getRand(&ptpClock->random_seed) % 4 + 4;
+ DBG("Q = %d, R = %d\n", ptpClock->Q, ptpClock->R);
+
+ ptpClock->waitingForFollow = FALSE;
+ ptpClock->delay_req_send_time.seconds = 0;
+ ptpClock->delay_req_send_time.nanoseconds = 0;
+ ptpClock->delay_req_receive_time.seconds = 0;
+ ptpClock->delay_req_receive_time.nanoseconds = 0;
+
+ timerStart(SYNC_RECEIPT_TIMER, PTP_SYNC_RECEIPT_TIMEOUT(ptpClock->sync_interval), ptpClock->itimer);
+
+ ptpClock->port_state = PTP_SLAVE;
+ break;
+
+ default:
+ DBG("to unrecognized state\n");
+ break;
+ }
+
+ NOTIFY("Port state changed to %s\n", translatePortState(ptpClock));
+
+ if (rtOpts->displayStats)
+ displayStats(rtOpts, ptpClock);
+}
+
+/* check and handle received messages */
+void
+handle(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ int ret;
+ ssize_t length;
+ Boolean isFromSelf;
+ TimeInternal time = {0, 0};
+
+ if (!ptpClock->message_activity) {
+ ret = netSelect(0, &ptpClock->netPath);
+ if (ret < 0) {
+ PERROR("failed to poll sockets");
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ return;
+ } else if (!ret) {
+ DBGV("handle: nothing\n");
+ return;
+ }
+ /* else length > 0 */
+ }
+ DBGV("handle: something\n");
+
+ length = netRecvEvent(ptpClock->msgIbuf, &time, &ptpClock->netPath);
+ if (length < 0) {
+ PERROR("failed to receive on the event socket");
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ return;
+ } else if (!length) {
+ length = netRecvGeneral(ptpClock->msgIbuf, &ptpClock->netPath);
+ if (length < 0) {
+ PERROR("failed to receive on the general socket");
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ return;
+ } else if (!length)
+ return;
+ }
+ ptpClock->message_activity = TRUE;
+
+ if (!msgPeek(ptpClock->msgIbuf, length))
+ return;
+
+ if (length < HEADER_LENGTH) {
+ ERROR("message shorter than header length\n");
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ return;
+ }
+ msgUnpackHeader(ptpClock->msgIbuf, &ptpClock->msgTmpHeader);
+
+ DBGV("event Receipt of Message\n"
+ " version %d\n"
+ " type %d\n"
+ " uuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n"
+ " sequence %d\n"
+ " time %us %dns\n",
+ ptpClock->msgTmpHeader.versionPTP,
+ ptpClock->msgTmpHeader.control,
+ ptpClock->msgTmpHeader.sourceUuid[0], ptpClock->msgTmpHeader.sourceUuid[1],
+ ptpClock->msgTmpHeader.sourceUuid[2], ptpClock->msgTmpHeader.sourceUuid[3],
+ ptpClock->msgTmpHeader.sourceUuid[4], ptpClock->msgTmpHeader.sourceUuid[5],
+ ptpClock->msgTmpHeader.sequenceId,
+ time.seconds, time.nanoseconds);
+
+ if (ptpClock->msgTmpHeader.versionPTP != VERSION_PTP) {
+ DBGV("ignore version %d message\n", ptpClock->msgTmpHeader.versionPTP);
+ return;
+ }
+ if (memcmp(ptpClock->msgTmpHeader.subdomain, ptpClock->subdomain_name,
+ PTP_SUBDOMAIN_NAME_LENGTH)) {
+ DBGV("ignore message from subdomain %s\n", ptpClock->msgTmpHeader.subdomain);
+ return;
+ }
+ isFromSelf = ptpClock->msgTmpHeader.sourceCommunicationTechnology == ptpClock->port_communication_technology
+ && ptpClock->msgTmpHeader.sourcePortId == ptpClock->port_id_field
+ && !memcmp(ptpClock->msgTmpHeader.sourceUuid, ptpClock->port_uuid_field, PTP_UUID_LENGTH);
+
+ /*
+ * subtract the inbound latency adjustment if it is not a loop back
+ * and the time stamp seems reasonable
+ */
+ if (!isFromSelf && time.seconds > 0)
+ subTime(&time, &time, &rtOpts->inboundLatency);
+
+ switch (ptpClock->msgTmpHeader.control) {
+ case PTP_SYNC_MESSAGE:
+ handleSync(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, length, &time, isFromSelf, rtOpts, ptpClock);
+ break;
+
+ case PTP_FOLLOWUP_MESSAGE:
+ handleFollowUp(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, length, isFromSelf, rtOpts, ptpClock);
+ break;
+
+ case PTP_DELAY_REQ_MESSAGE:
+ handleDelayReq(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, length, &time, isFromSelf, rtOpts, ptpClock);
+ break;
+
+ case PTP_DELAY_RESP_MESSAGE:
+ handleDelayResp(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, length, isFromSelf, rtOpts, ptpClock);
+ break;
+
+ case PTP_MANAGEMENT_MESSAGE:
+ handleManagement(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, length, isFromSelf, rtOpts, ptpClock);
+ break;
+
+ default:
+ DBG("handle: unrecognized message\n");
+ break;
+ }
+}
+
+void
+handleSync(MsgHeader * header, Octet * msgIbuf, ssize_t length, TimeInternal * time, Boolean isFromSelf, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ MsgSync *sync;
+ TimeInternal originTimestamp;
+
+ if (length < SYNC_PACKET_LENGTH) {
+ ERROR("short sync message\n");
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ return;
+ }
+ switch (ptpClock->port_state) {
+ case PTP_FAULTY:
+ case PTP_INITIALIZING:
+ case PTP_DISABLED:
+ DBGV("handleSync: disreguard\n");
+ return;
+
+ case PTP_UNCALIBRATED:
+ case PTP_SLAVE:
+ if (isFromSelf) {
+ DBG("handleSync: ignore from self\n");
+ return;
+ }
+ if (getFlag(header->flags, PTP_SYNC_BURST) && !ptpClock->burst_enabled)
+ return;
+
+ DBGV("handleSync: looking for uuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ ptpClock->parent_uuid[0], ptpClock->parent_uuid[1], ptpClock->parent_uuid[2],
+ ptpClock->parent_uuid[3], ptpClock->parent_uuid[4], ptpClock->parent_uuid[5]);
+
+ if (header->sequenceId > ptpClock->parent_last_sync_sequence_number
+ && header->sourceCommunicationTechnology == ptpClock->parent_communication_technology
+ && header->sourcePortId == ptpClock->parent_port_id
+ && !memcmp(header->sourceUuid, ptpClock->parent_uuid, PTP_UUID_LENGTH)) {
+ /* addForeign() takes care of msgUnpackSync() */
+ ptpClock->record_update = TRUE;
+ sync = addForeign(ptpClock->msgIbuf, &ptpClock->msgTmpHeader, ptpClock);
+
+ if (sync->syncInterval != ptpClock->sync_interval) {
+ DBGV("message's sync interval is %d, but clock's is %d\n", sync->syncInterval, ptpClock->sync_interval);
+ /*
+ * spec recommends handling a sync interval
+ * discrepancy as a fault
+ */
+ }
+ ptpClock->sync_receive_time.seconds = time->seconds;
+ ptpClock->sync_receive_time.nanoseconds = time->nanoseconds;
+
+ if (!getFlag(header->flags, PTP_ASSIST)) {
+ ptpClock->waitingForFollow = FALSE;
+
+ toInternalTime(&originTimestamp, &sync->originTimestamp, &ptpClock->halfEpoch);
+ updateOffset(&originTimestamp, &ptpClock->sync_receive_time,
+ &ptpClock->ofm_filt, rtOpts, ptpClock);
+ updateClock(rtOpts, ptpClock);
+ } else {
+ ptpClock->waitingForFollow = TRUE;
+ }
+
+ s1(header, sync, ptpClock);
+
+ if (!(--ptpClock->R)) {
+ issueDelayReq(rtOpts, ptpClock);
+
+ ptpClock->Q = 0;
+ ptpClock->R = getRand(&ptpClock->random_seed) % (PTP_DELAY_REQ_INTERVAL - 2) + 2;
+ DBG("Q = %d, R = %d\n", ptpClock->Q, ptpClock->R);
+ }
+ DBGV("SYNC_RECEIPT_TIMER reset\n");
+ timerStart(SYNC_RECEIPT_TIMER, PTP_SYNC_RECEIPT_TIMEOUT(ptpClock->sync_interval), ptpClock->itimer);
+
+#ifndef NO_FILE_SYSTEM
+ if (rtOpts->recordFP != NULL)
+ fprintf(rtOpts->recordFP, "%d %llu\n",
+ header->sequenceId,
+ ((time->seconds * 1000000000ULL) +
+ time->nanoseconds));
+#endif
+ } else {
+ DBGV("handleSync: unwanted\n");
+ }
+
+ case PTP_MASTER:
+ default:
+ if (header->sourceCommunicationTechnology == ptpClock->clock_communication_technology
+ || header->sourceCommunicationTechnology == PTP_DEFAULT
+ || ptpClock->clock_communication_technology == PTP_DEFAULT) {
+ if (!isFromSelf) {
+ ptpClock->record_update = TRUE;
+ addForeign(ptpClock->msgIbuf, &ptpClock->msgTmpHeader, ptpClock);
+ } else if (ptpClock->port_state == PTP_MASTER && ptpClock->clock_followup_capable) {
+ addTime(time, time, &rtOpts->outboundLatency);
+ issueFollowup(time, rtOpts, ptpClock);
+ }
+ }
+ break;
+ }
+}
+
+void
+handleFollowUp(MsgHeader * header, Octet * msgIbuf, ssize_t length, Boolean isFromSelf, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ MsgFollowUp *follow;
+ TimeInternal preciseOriginTimestamp;
+
+ if (length < FOLLOW_UP_PACKET_LENGTH) {
+ ERROR("short folow up message\n");
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ return;
+ }
+ switch (ptpClock->port_state) {
+ case PTP_SLAVE:
+ if (isFromSelf) {
+ DBG("handleFollowUp: ignore from self\n");
+ return;
+ }
+ if (getFlag(header->flags, PTP_SYNC_BURST) && !ptpClock->burst_enabled)
+ return;
+
+ DBGV("handleFollowUp: looking for uuid %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ ptpClock->parent_uuid[0], ptpClock->parent_uuid[1], ptpClock->parent_uuid[2],
+ ptpClock->parent_uuid[3], ptpClock->parent_uuid[4], ptpClock->parent_uuid[5]);
+
+ follow = &ptpClock->msgTmp.follow;
+ msgUnpackFollowUp(ptpClock->msgIbuf, follow);
+
+ if (ptpClock->waitingForFollow
+ && follow->associatedSequenceId == ptpClock->parent_last_sync_sequence_number
+ && header->sourceCommunicationTechnology == ptpClock->parent_communication_technology
+ && header->sourcePortId == ptpClock->parent_port_id
+ && !memcmp(header->sourceUuid, ptpClock->parent_uuid, PTP_UUID_LENGTH)) {
+ ptpClock->waitingForFollow = FALSE;
+
+ toInternalTime(&preciseOriginTimestamp, &follow->preciseOriginTimestamp, &ptpClock->halfEpoch);
+ updateOffset(&preciseOriginTimestamp, &ptpClock->sync_receive_time,
+ &ptpClock->ofm_filt, rtOpts, ptpClock);
+ updateClock(rtOpts, ptpClock);
+ } else {
+ DBGV("handleFollowUp: unwanted\n");
+ }
+ break;
+
+ default:
+ DBGV("handleFollowUp: disreguard\n");
+ return;
+ }
+}
+
+void
+handleDelayReq(MsgHeader * header, Octet * msgIbuf, ssize_t length, TimeInternal * time, Boolean isFromSelf, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ if (length < DELAY_REQ_PACKET_LENGTH) {
+ ERROR("short delay request message\n");
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ return;
+ }
+ switch (ptpClock->port_state) {
+ case PTP_MASTER:
+ if (isFromSelf) {
+ DBG("handleDelayReq: ignore from self\n");
+ return;
+ }
+ if (header->sourceCommunicationTechnology == ptpClock->clock_communication_technology
+ || header->sourceCommunicationTechnology == PTP_DEFAULT
+ || ptpClock->clock_communication_technology == PTP_DEFAULT) {
+ issueDelayResp(time, &ptpClock->msgTmpHeader, rtOpts, ptpClock);
+ }
+ break;
+
+ case PTP_SLAVE:
+ if (isFromSelf) {
+ DBG("handleDelayReq: self\n");
+
+ ptpClock->delay_req_send_time.seconds = time->seconds;
+ ptpClock->delay_req_send_time.nanoseconds = time->nanoseconds;
+
+ addTime(&ptpClock->delay_req_send_time, &ptpClock->delay_req_send_time, &rtOpts->outboundLatency);
+
+ if (ptpClock->delay_req_receive_time.seconds) {
+ updateDelay(&ptpClock->delay_req_send_time,
+ &ptpClock->delay_req_receive_time,
+ &ptpClock->owd_filt, rtOpts,
+ ptpClock);
+
+ ptpClock->delay_req_send_time.seconds = 0;
+ ptpClock->delay_req_send_time.nanoseconds = 0;
+ ptpClock->delay_req_receive_time.seconds = 0;
+ ptpClock->delay_req_receive_time.nanoseconds = 0;
+ }
+ }
+ break;
+
+ default:
+ DBGV("handleDelayReq: disreguard\n");
+ return;
+ }
+}
+
+void
+handleDelayResp(MsgHeader * header, Octet * msgIbuf, ssize_t length, Boolean isFromSelf, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ MsgDelayResp *resp;
+
+ if (length < DELAY_RESP_PACKET_LENGTH) {
+ ERROR("short delay request message\n");
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ return;
+ }
+ switch (ptpClock->port_state) {
+ case PTP_SLAVE:
+ if (isFromSelf) {
+ DBG("handleDelayResp: ignore from self\n");
+ return;
+ }
+ resp = &ptpClock->msgTmp.resp;
+ msgUnpackDelayResp(ptpClock->msgIbuf, resp);
+
+ if (ptpClock->sentDelayReq
+ && resp->requestingSourceSequenceId == ptpClock->sentDelayReqSequenceId
+ && resp->requestingSourceCommunicationTechnology == ptpClock->port_communication_technology
+ && resp->requestingSourcePortId == ptpClock->port_id_field
+ && !memcmp(resp->requestingSourceUuid, ptpClock->port_uuid_field, PTP_UUID_LENGTH)
+ && header->sourceCommunicationTechnology == ptpClock->parent_communication_technology
+ && header->sourcePortId == ptpClock->parent_port_id
+ && !memcmp(header->sourceUuid, ptpClock->parent_uuid, PTP_UUID_LENGTH)) {
+ ptpClock->sentDelayReq = FALSE;
+
+ toInternalTime(&ptpClock->delay_req_receive_time, &resp->delayReceiptTimestamp, &ptpClock->halfEpoch);
+
+ if (ptpClock->delay_req_send_time.seconds) {
+ updateDelay(&ptpClock->delay_req_send_time, &ptpClock->delay_req_receive_time,
+ &ptpClock->owd_filt, rtOpts, ptpClock);
+
+ ptpClock->delay_req_send_time.seconds = 0;
+ ptpClock->delay_req_send_time.nanoseconds = 0;
+ ptpClock->delay_req_receive_time.seconds = 0;
+ ptpClock->delay_req_receive_time.nanoseconds = 0;
+ }
+ } else {
+ DBGV("handleDelayResp: unwanted\n");
+ }
+ break;
+
+ default:
+ DBGV("handleDelayResp: disreguard\n");
+ return;
+ }
+}
+
+void
+handleManagement(MsgHeader * header, Octet * msgIbuf, ssize_t length, Boolean isFromSelf, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ MsgManagement *manage;
+
+ UInteger8 state;
+
+ if (ptpClock->port_state == PTP_INITIALIZING)
+ return;
+
+ manage = &ptpClock->msgTmp.manage;
+ msgUnpackManagement(ptpClock->msgIbuf, manage);
+
+ if ((manage->targetCommunicationTechnology == ptpClock->clock_communication_technology
+ && !memcmp(manage->targetUuid, ptpClock->clock_uuid_field, PTP_UUID_LENGTH))
+ || ((manage->targetCommunicationTechnology == PTP_DEFAULT
+ || manage->targetCommunicationTechnology == ptpClock->clock_communication_technology)
+ && !sum(manage->targetUuid, PTP_UUID_LENGTH))) {
+ switch (manage->managementMessageKey) {
+ case PTP_MM_OBTAIN_IDENTITY:
+ case PTP_MM_GET_DEFAULT_DATA_SET:
+ case PTP_MM_GET_CURRENT_DATA_SET:
+ case PTP_MM_GET_PARENT_DATA_SET:
+ case PTP_MM_GET_PORT_DATA_SET:
+ case PTP_MM_GET_GLOBAL_TIME_DATA_SET:
+ case PTP_MM_GET_FOREIGN_DATA_SET:
+ issueManagement(header, manage, rtOpts, ptpClock);
+ break;
+
+ default:
+ ptpClock->record_update = TRUE;
+ state = msgUnloadManagement(ptpClock->msgIbuf, manage, ptpClock, rtOpts);
+ if (state != ptpClock->port_state)
+ toState(state, rtOpts, ptpClock);
+ break;
+ }
+ } else {
+ DBG("handleManagement: unwanted\n");
+ }
+}
+
+/* pack and send various messages */
+void
+issueSync(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ TimeInternal internalTime;
+ TimeRepresentation originTimestamp;
+
+ ++ptpClock->last_sync_event_sequence_number;
+ ptpClock->grandmaster_sequence_number = ptpClock->last_sync_event_sequence_number;
+
+ getTime(&internalTime);
+ fromInternalTime(&internalTime, &originTimestamp, ptpClock->halfEpoch);
+ msgPackSync(ptpClock->msgObuf, FALSE, &originTimestamp, ptpClock);
+
+ if (!netSendEvent(ptpClock->msgObuf, SYNC_PACKET_LENGTH, &ptpClock->netPath))
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ else
+ DBGV("sent sync message\n");
+}
+
+void
+issueFollowup(TimeInternal * time, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ TimeRepresentation preciseOriginTimestamp;
+
+ ++ptpClock->last_general_event_sequence_number;
+
+ fromInternalTime(time, &preciseOriginTimestamp, ptpClock->halfEpoch);
+ msgPackFollowUp(ptpClock->msgObuf, ptpClock->last_sync_event_sequence_number, &preciseOriginTimestamp, ptpClock);
+
+ if (!netSendGeneral(ptpClock->msgObuf, FOLLOW_UP_PACKET_LENGTH, &ptpClock->netPath))
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ else
+ DBGV("sent followup message\n");
+}
+
+void
+issueDelayReq(RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ TimeInternal internalTime;
+ TimeRepresentation originTimestamp;
+
+ ptpClock->sentDelayReq = TRUE;
+ ptpClock->sentDelayReqSequenceId = ++ptpClock->last_sync_event_sequence_number;
+
+ getTime(&internalTime);
+ fromInternalTime(&internalTime, &originTimestamp, ptpClock->halfEpoch);
+ msgPackDelayReq(ptpClock->msgObuf, FALSE, &originTimestamp, ptpClock);
+
+ if (!netSendEvent(ptpClock->msgObuf, DELAY_REQ_PACKET_LENGTH, &ptpClock->netPath))
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ else
+ DBGV("sent delay request message\n");
+}
+
+void
+issueDelayResp(TimeInternal * time, MsgHeader * header, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ TimeRepresentation delayReceiptTimestamp;
+
+ ++ptpClock->last_general_event_sequence_number;
+
+ fromInternalTime(time, &delayReceiptTimestamp, ptpClock->halfEpoch);
+ msgPackDelayResp(ptpClock->msgObuf, header, &delayReceiptTimestamp, ptpClock);
+
+ if (!netSendGeneral(ptpClock->msgObuf, DELAY_RESP_PACKET_LENGTH, &ptpClock->netPath))
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ else
+ DBGV("sent delay response message\n");
+}
+
+void
+issueManagement(MsgHeader * header, MsgManagement * manage, RunTimeOpts * rtOpts, PtpClock * ptpClock)
+{
+ UInteger16 length;
+
+ ++ptpClock->last_general_event_sequence_number;
+
+ if (!(length = msgPackManagementResponse(ptpClock->msgObuf, header, manage, ptpClock)))
+ return;
+
+ if (!netSendGeneral(ptpClock->msgObuf, length, &ptpClock->netPath))
+ toState(PTP_FAULTY, rtOpts, ptpClock);
+ else
+ DBGV("sent management message\n");
+}
+
+/* add or update an entry in the foreign master data set */
+MsgSync *
+addForeign(Octet * buf, MsgHeader * header, PtpClock * ptpClock)
+{
+ int i, j;
+ Boolean found = FALSE;
+
+ DBGV("updateForeign\n");
+
+ j = ptpClock->foreign_record_best;
+ for (i = 0; i < ptpClock->number_foreign_records; ++i) {
+ if (header->sourceCommunicationTechnology == ptpClock->foreign[j].foreign_master_communication_technology
+ && header->sourcePortId == ptpClock->foreign[j].foreign_master_port_id
+ && !memcmp(header->sourceUuid, ptpClock->foreign[j].foreign_master_uuid, PTP_UUID_LENGTH)) {
+ ++ptpClock->foreign[j].foreign_master_syncs;
+ found = TRUE;
+ DBGV("updateForeign: update record %d\n", j);
+ break;
+ }
+ j = (j + 1) % ptpClock->number_foreign_records;
+ }
+
+ if (!found) {
+ if (ptpClock->number_foreign_records < ptpClock->max_foreign_records)
+ ++ptpClock->number_foreign_records;
+
+ j = ptpClock->foreign_record_i;
+
+ ptpClock->foreign[j].foreign_master_communication_technology =
+ header->sourceCommunicationTechnology;
+ ptpClock->foreign[j].foreign_master_port_id =
+ header->sourcePortId;
+ memcpy(ptpClock->foreign[j].foreign_master_uuid,
+ header->sourceUuid, PTP_UUID_LENGTH);
+
+ DBG("updateForeign: new record (%d,%d) %d %d %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ ptpClock->foreign_record_i, ptpClock->number_foreign_records,
+ ptpClock->foreign[j].foreign_master_communication_technology,
+ ptpClock->foreign[j].foreign_master_port_id,
+ ptpClock->foreign[j].foreign_master_uuid[0], ptpClock->foreign[j].foreign_master_uuid[1],
+ ptpClock->foreign[j].foreign_master_uuid[2], ptpClock->foreign[j].foreign_master_uuid[3],
+ ptpClock->foreign[j].foreign_master_uuid[4], ptpClock->foreign[j].foreign_master_uuid[5]);
+
+ ptpClock->foreign_record_i = (ptpClock->foreign_record_i + 1) % ptpClock->max_foreign_records;
+ }
+ msgUnpackHeader(buf, &ptpClock->foreign[j].header);
+ msgUnpackSync(buf, &ptpClock->foreign[j].sync);
+
+ return &ptpClock->foreign[j].sync;
+}
diff --git a/third_party/ptpd-1.1.0/src/ptpd.8 b/third_party/ptpd-1.1.0/src/ptpd.8 new file mode 100644 index 0000000..2452d7f --- /dev/null +++ b/third_party/ptpd-1.1.0/src/ptpd.8 @@ -0,0 +1,143 @@ +.\" -*- nroff -*"
+.TH ptpd 8 "August 9, 2010" "version 1.1.0" "Precision Time Protocol daemon"
+.SH NAME
+ptpd \- Precision Time Protocol daemon
+.SH SYNOPSIS
+.B ptpd
+
+[-?]
+[-c]
+[-S]
+[-f FILE]
+[-R FILE]
+[-d]
+[-D]
+[-x]
+[-M NUMBER]
+[-t]
+[-T ttl]
+[-a NUMBER,NUMBER]
+[-w NUMBER]
+[-b NAME]
+[-u ADDRESS]
+[-l NUMBER,NUMBER]
+[-o NUMBER]
+[-e NUMBER]
+[-y NUMBER]
+[-m NUMBER]
+[-g]
+[-p]
+[-s NUMBER]
+[-i NAME]
+[-v NUMBER]
+[-n NAME]
+[-k NUMBER,NUMBER]
+
+.SH DESCRIPTION
+Implements version 1 of the Precision Time Protocol (PTP) as defined
+by the IEEE 1588 standard. PTP was developed to provide very precise
+time coordination of LAN connected computers.
+.PP
+PTPd is a complete implementation of the IEEE 1588 specification for a
+standard (non-boundary) clock. PTPd has been tested with and is known
+to work properly with other IEEE 1588 implementations. The source code
+for PTPd is freely available under a BSD-style license. Thanks to
+contributions from users, PTPd is becoming an increasingly portable,
+interoperable, and stable IEEE 1588 implementation.
+.PP
+For more information, see http://ptpd.sourceforge.net/
+.SH OPTIONS
+.TP
+.B \-?
+display a short help text
+.TP
+.B \-c
+run in command line (non-daemon) mode
+.TP
+.B \-S
+log information to syslog
+.TP
+.B \-f FILE
+send output to FILE
+.TP
+.B \-R FILE
+record quality data to FILE
+.TP
+.B \-d
+display stats
+.TP
+.B \-D
+display stats in .csv format
+.TP
+.B \-x
+do not reset the clock if off by more than one second
+.TP
+.B \-M NUMBER
+do not reset the clock if off by more than NUMBER nanoseconds
+.TP
+.B \-t
+do not adjust the system clock
+.TP
+.B \-T
+set multicast TTL for packets. Defaults to 1.
+.TP
+.B \-a NUMBER,NUMBER
+specify clock servo P and I attenuations
+.TP
+.B \-w NUMBER
+specify one way delay filter stiffness
+.TP
+.B \-b NAME
+bind PTP to network interface NAME
+.TP
+.B \-u ADDRESS
+don't multicast, send messages unicast to ADDRESS
+.TP
+.B \-l NUMBER,NUMBER
+specify inbound, outbound latency in nsec
+.TP
+.B \-o NUMBER
+specify current UTC offset
+.TP
+.B \-e NUMBER
+specify epoch NUMBER
+.TP
+.B \-y NUMBER
+specify sync interval in 2^NUMBER sec
+.TP
+.B \-m NUMBER
+specify max number of foreign master records
+.TP
+.B \-g
+run as slave only
+.TP
+.B \-p
+make this a preferred clock
+.TP
+.B \-s NUMBER
+specify system clock stratum
+.TP
+.B \-i NAME
+specify system clock identifier
+.TP
+.B \-v NUMBER
+specify system clock allen variance
+.TP
+.B \-n NAME
+specify PTP subdomain name (not related to IP or DNS)
+.TP
+.B \-k NUMBER,NUMBER
+send a management message of key, record, then exit
+
+.SH AUTHORS
+.PP
+Originally written and maintained by Kendall Correll
+<kendall_c@users.sourceforge.net>
+.PP
+Steven Kreuzer <skreuzer@freebsd.org>
+.PP
+George Neville-Neil <gnn@freebsd.org>
+.PP
+This manual page was originally written by Andrew Straw
+<strawman@astraw.com> for the Debian Project (but may be used by
+others).
diff --git a/third_party/ptpd-1.1.0/src/ptpd.c b/third_party/ptpd-1.1.0/src/ptpd.c new file mode 100644 index 0000000..f137ae5 --- /dev/null +++ b/third_party/ptpd-1.1.0/src/ptpd.c @@ -0,0 +1,59 @@ +/**
+ * @file ptpd.c
+ * @date Wed Jun 23 10:13:38 2010
+ *
+ * @brief The main() function for the PTP daemon
+ *
+ * This file contains very little code, as should be obvious,
+ * and only serves to tie together the rest of the daemon.
+ * All of the default options are set here, but command line
+ * arguments are processed in the ptpdStartup() routine called
+ * below.
+ */
+
+#include "ptpd.h"
+
+RunTimeOpts rtOpts; /* statically allocated run-time
+ * configuration data */
+
+int
+main(int argc, char **argv)
+{
+ PtpClock *ptpClock;
+ Integer16 ret;
+
+ /* initialize run-time options to reasonable values */
+ rtOpts.syncInterval = DEFAULT_SYNC_INTERVAL;
+ memcpy(rtOpts.subdomainName, DEFAULT_PTP_DOMAIN_NAME, PTP_SUBDOMAIN_NAME_LENGTH);
+ memcpy(rtOpts.clockIdentifier, IDENTIFIER_DFLT, PTP_CODE_STRING_LENGTH);
+ rtOpts.clockVariance = DEFAULT_CLOCK_VARIANCE;
+ rtOpts.clockStratum = DEFAULT_CLOCK_STRATUM;
+ rtOpts.unicastAddress[0] = 0;
+ rtOpts.inboundLatency.nanoseconds = DEFAULT_INBOUND_LATENCY;
+ rtOpts.outboundLatency.nanoseconds = DEFAULT_OUTBOUND_LATENCY;
+ rtOpts.noResetClock = DEFAULT_NO_RESET_CLOCK;
+ rtOpts.s = DEFAULT_DELAY_S;
+ rtOpts.ap = DEFAULT_AP;
+ rtOpts.ai = DEFAULT_AI;
+ rtOpts.max_foreign_records = DEFAULT_MAX_FOREIGN_RECORDS;
+ rtOpts.currentUtcOffset = DEFAULT_UTC_OFFSET;
+ rtOpts.logFd = -1;
+ rtOpts.recordFP = NULL;
+ rtOpts.useSysLog = FALSE;
+ rtOpts.ttl = 1;
+
+ if (!(ptpClock = ptpdStartup(argc, argv, &ret, &rtOpts)))
+ return ret;
+
+ if (rtOpts.probe) {
+ probe(&rtOpts, ptpClock);
+ } else {
+ /* do the protocol engine */
+ protocol(&rtOpts, ptpClock);
+ }
+
+ ptpdShutdown();
+
+ NOTIFY("self shutdown, probably due to an error\n");
+ return 1;
+}
diff --git a/third_party/ptpd-1.1.0/src/ptpd.h b/third_party/ptpd-1.1.0/src/ptpd.h new file mode 100644 index 0000000..b0abe7e --- /dev/null +++ b/third_party/ptpd-1.1.0/src/ptpd.h @@ -0,0 +1,49 @@ +/**
+ * @file ptpd.h
+ * @mainpage Ptpd Documentation
+ * @authors Martin Burnicki, Alexandre van Kempen, Steven Kreuzer,
+ * George Neville-Neil
+ * @version 1.0
+ * @date Tue Jul 20 16:15:04 2010
+ *
+ *
+ */
+
+#ifndef PTPD_H
+#define PTPD_H
+
+/* Definitions and dependencies for the TI TivaWare port */
+#include "constants.h"
+#include "dep-tiva/constants_dep.h"
+#include "dep-tiva/datatypes_dep.h"
+#include "datatypes.h"
+#include "dep-tiva/ptpd_dep.h"
+
+/* arith.c */
+UInteger32 crc_algorithm(Octet *, Integer16);
+UInteger32 sum(Octet *, Integer16);
+void fromInternalTime(TimeInternal *, TimeRepresentation *, Boolean);
+void toInternalTime(TimeInternal *, TimeRepresentation *, Boolean *);
+void normalizeTime(TimeInternal *);
+void addTime(TimeInternal *, TimeInternal *, TimeInternal *);
+void subTime(TimeInternal *, TimeInternal *, TimeInternal *);
+
+/* bmc.c */
+UInteger8 bmc(ForeignMasterRecord *, RunTimeOpts *, PtpClock *);
+void m1 (PtpClock *);
+void s1 (MsgHeader *, MsgSync *, PtpClock *);
+void initData(RunTimeOpts *, PtpClock *);
+
+/* probe.c */
+void probe(RunTimeOpts *, PtpClock *);
+
+/* protocol.c */
+void protocol(RunTimeOpts *, PtpClock *);
+
+/* Split versions of protocol() that may be used when no RTOS is present.
+ * These functions were added by TI.
+ */
+void protocol_first(RunTimeOpts*,PtpClock*);
+void protocol_loop(RunTimeOpts*,PtpClock*);
+
+#endif
diff --git a/third_party/ptpd-1.1.0/tools/filter_response.m b/third_party/ptpd-1.1.0/tools/filter_response.m new file mode 100644 index 0000000..5c20163 --- /dev/null +++ b/third_party/ptpd-1.1.0/tools/filter_response.m @@ -0,0 +1,29 @@ +#!/usr/bin/octave -qf
+
+# the IIR filter
+s = 2^4;
+a = [ s -(s-1) ];
+b = [ 1/2 1/2 ];
+
+[h w] = freqz(b, a, 100000);
+
+subplot(211);
+plot(w/pi,abs(h),";;");
+axis();
+#plot(w/pi,20*log(abs(h)));
+#axis([0 1 -120 0]);
+#semilogx(w/pi,20*log(abs(h)),";;");
+#axis([1e-3 1 -120 0]);
+ylabel("gain");
+
+subplot(212);
+plot(w/pi,unwrap(angle(h)),";;");
+axis([0 1 -pi 0]);
+#semilogx(w/pi,unwrap(angle(h)),";;");
+#axis([1e-3 1 -pi 0]);
+ylabel("phase (rad)");
+xlabel("frequency");
+replot;
+
+pause;
+
diff --git a/third_party/ptpd-1.1.0/tools/offset_stats.m b/third_party/ptpd-1.1.0/tools/offset_stats.m new file mode 100644 index 0000000..26af4c2 --- /dev/null +++ b/third_party/ptpd-1.1.0/tools/offset_stats.m @@ -0,0 +1,102 @@ +#!/usr/bin/octave -qf
+
+printf("start\n");
+
+load t;
+load tr;
+
+# time window to analyze
+t_beg = 1;
+t_fin = length(t);
+
+# parameters for synthetic reference time
+#start_time = round(t(t_beg));
+#sample_interval = 1;
+
+# parameters for histogram
+h_beg = -15e-6;
+h_fin = 15e-6;
+h_sz = 1e-6;
+
+# parameters for allan variance
+# tune for your computational power
+tau_beg = 1;
+tau_fin = length(t)/10;
+tau_maxsamps = 100;
+
+# ----------
+
+printf("data loaded\n");
+
+# create synthetic reference time
+#tr = t;
+#tr(t_beg) = start_time;
+#for k = (t_beg+1):t_fin
+#
+# tr(k) = tr(k-1) + sample_interval;
+#
+#endfor
+
+# time offset computation
+o = t - tr;
+
+o_min = min(o(t_beg:t_fin));
+o_max = max(o(t_beg:t_fin));
+o_mean = mean(o(t_beg:t_fin));
+
+# relative tick rate computation
+r = t;
+for k = (t_beg+1):t_fin
+
+ r(k) = o(k) - o(k-1);
+
+endfor
+
+r_min = min(r((t_beg+1):t_fin));
+r_max = max(r((t_beg+1):t_fin));
+r_mean = mean(r((t_beg+1):t_fin));
+
+figure;
+h_bins = h_beg:h_sz:h_fin;
+hist( o(t_beg:t_fin), h_bins, 1);
+
+printf("histogram plotted\n");
+
+figure;
+subplot(211);
+plot( t_beg:t_fin, o(t_beg:t_fin), "r;time offset;",
+ [t_beg t_fin], [o_min o_min], "g;;",
+ [t_beg t_fin], [o_max o_max], "g;;",
+ [t_beg t_fin], [o_mean o_mean], "b;;");
+subplot(212);
+plot( (t_beg+1):t_fin, r((t_beg+1):t_fin), "r;relative tick rate;",
+ [(t_beg+1) t_fin], [r_min r_min], "g;;",
+ [(t_beg+1) t_fin], [r_max r_max], "g;;",
+ [(t_beg+1) t_fin], [r_mean r_mean], "b;;")
+replot;
+
+printf("offset plotted\n");
+
+# the allan vaiance computation from the IEEE 1588 spec
+a = t;
+for tau = tau_beg:tau_fin
+
+ beg = t_beg;
+ if (t_fin-2*tau) > tau_maxsamps
+ fin = tau_maxsamps;
+ else
+ fin = (t_fin-2*tau);
+ end
+
+ a(tau) = sum((t(beg:fin) - 2*t((beg+tau):(fin+tau)) + t((beg+2*tau):(fin+2*tau))).^2);
+ a(tau) /= 2*(fin-beg)*(tau^2);
+
+endfor
+
+figure;
+loglog( tau_beg:tau_fin, a(tau_beg:tau_fin), ";allan variance;");
+replot;
+
+printf("variance plotted\n");
+input("done\n");
+
diff --git a/third_party/ptpd-1.1.0/tools/ptp_plot.py b/third_party/ptpd-1.1.0/tools/ptp_plot.py new file mode 100644 index 0000000..7c43dec --- /dev/null +++ b/third_party/ptpd-1.1.0/tools/ptp_plot.py @@ -0,0 +1,170 @@ +#! /usr/bin/env python2.6
+# Copyright (c) 2010, Neville-Neil Consulting
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# Neither the name of Neville-Neil Consulting nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: George V. Neville-Neil
+#
+# Description:
+
+"""ptp_plot.py -- Plot PTP delays reported by the slave.
+
+This program takes a ptp log file generated by the slave
+and plots various times on a graph
+
+This program requires at least python2.6 as well as numpy
+and gnuplot support.
+
+"""
+
+import csv
+import datetime
+import subprocess
+import sys
+import tempfile
+
+from numpy import *
+
+import Gnuplot, Gnuplot.funcutils
+
+def usage():
+ sys.exit()
+
+def main():
+
+ from optparse import OptionParser
+
+ parser = OptionParser()
+ parser.add_option("-a", "--all", dest="all", default=0,
+ help="show all entries")
+ parser.add_option("-t", "--type", dest="type", default="delay",
+ help="plot the delay or offset")
+ parser.add_option("-l", "--logfile", dest="logfile", default=None,
+ help="logfile to use")
+ parser.add_option("-s", "--start", dest="start", default="09:30:00",
+ help="start time")
+ parser.add_option("-e", "--end", dest="end", default="16:30:00",
+ help="end time")
+ parser.add_option("-r", "--roll", dest="roll", type=int, default=0,
+ help="number of days to roll at the start")
+ parser.add_option("-p", "--print", dest="png", default=None,
+ help="file to print the graph to")
+ parser.add_option("-y", "--ymin", dest="ymin", default="0.000000",
+ help="minimum y value")
+ parser.add_option("-Y", "--ymax", dest="ymax", default="0.001000",
+ help="maximum y value")
+ parser.add_option("-S", "--save", dest="save", default=None,
+ help="save file name")
+
+
+ (options, args) = parser.parse_args()
+
+ if ((options.type != "delay") and (options.type != "offset")):
+ print "You must choose either delay or offset."
+ usage()
+
+ try:
+ logfile = csv.reader(open(options.logfile, "rb"))
+ except:
+ print "Could not open %s" % options.logfile
+ sys.exit()
+
+ #
+ # This is an ugly hack, but it turns out that gnuplot
+ # is better able to plot time data if we write it out
+ # in the familiar format to a temporary file and
+ # then plot from the file rather than building up
+ # arrays of data.
+ #
+ tmpfile = tempfile.NamedTemporaryFile()
+
+ savefile = None
+
+ if (options.save != None):
+ savefile = open(options.save, "w")
+
+
+ first = True
+ for line in logfile:
+ # Split off the microseconds
+ try:
+ dt = line[0].rpartition(':')[0]
+ except:
+ continue
+ now = datetime.datetime.strptime(dt, "%Y-%m-%d %H:%M:%S")
+ if (first == True):
+ if (options.all == 0):
+ start = datetime.datetime.strptime(options.start, "%H:%M:%S")
+ else:
+ start = now
+ start = start.replace(year=now.year, month=now.month,
+ day=now.day + options.roll)
+ end = datetime.datetime.strptime(options.end, "%H:%M:%S")
+ end = end.replace(year=now.year, month=now.month,
+ day=now.day + options.roll)
+ first = False
+ if ((now > end) and (options.all == 0)):
+ break
+ if ((now > start) or (options.all != 0)):
+ if (options.type == "delay"):
+ tmpfile.write("%s %f\n" % (dt, float(line[3])))
+ if (savefile != None):
+ savefile.write("%s %f\n" % (dt, float(line[3])))
+ else:
+ tmpfile.write("%s %f\n" % (dt, float(line[4])))
+ if (savefile != None):
+ savefile.write("%s %f\n" % (dt, float(line[4])))
+
+ plotter = Gnuplot.Gnuplot(debug=1)
+ plotter('set data style dots')
+ if (options.type == "delay"):
+ plotter.set_range('yrange', [options.ymin, options.ymax])
+ plotter.ylabel('Seconds\\nOne Way Delay')
+ else:
+ plotter.set_range('yrange', [options.ymin, options.ymax])
+ plotter.ylabel('Seconds\\nOffset')
+ if (options.all == 0):
+ plotter.xlabel(options.logfile + " " + options.start + " - " + options.end)
+ else:
+ plotter.xlabel(options.logfile + " " + str(start) + " - " + str(now))
+ plotter('set xdata time')
+ plotter('set timefmt "%Y-%m-%d %H:%M:%S"')
+
+ tmpfile.flush()
+ plotter.plot(Gnuplot.File(tmpfile.name, using='1:3'))
+
+ if (options.png != None):
+ plotter.hardcopy(options.logfile + "-" + options.type + ".png", terminal='png')
+ raw_input('Press return to exit')
+ else:
+ raw_input('Press return to exit')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/third_party/ptpd-1.1.0/tools/quality_correlate.py b/third_party/ptpd-1.1.0/tools/quality_correlate.py new file mode 100644 index 0000000..cea5dd0 --- /dev/null +++ b/third_party/ptpd-1.1.0/tools/quality_correlate.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python2.6
+# Copyright (c) 2010, Neville-Neil Consulting
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# Neither the name of Neville-Neil Consulting nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: George V. Neville-Neil
+#
+# Description: This program reads a pair of PTPd quality files,
+# generated with the -R option, correlates and graphs the differences
+# between the time each host saw a SYNC which is an easy way to
+# measure the quality of time synchronization between two clients
+# a timing service.
+
+import sys
+
+from numpy import *
+
+import Gnuplot, Gnuplot.funcutils
+
+import gzip
+import os
+
+def main():
+
+ from optparse import OptionParser
+
+ parser = OptionParser()
+ parser.add_option("-y", "--ymin", dest="ymin", default=0,
+ help="minimum y value")
+ parser.add_option("-Y", "--ymax", dest="ymax", default=1000000,
+ help="maximum y value")
+ parser.add_option("-N", "--Names", dest="hosts", nargs=2, default=None,
+ help="host list for sync graph")
+ parser.add_option("-s", "--start", dest="start", type="int", default=0,
+ help="starting sequence number")
+ parser.add_option("-p", "--print", dest="png", default=None,
+ help="print the graph to a file")
+ parser.add_option("-o", "--output", dest="output", default=None,
+ help="save the correlated data to a file.")
+ parser.add_option("-d", "--debug", dest="debug", type="int", default=0,
+ help="print debugging info (verbose)")
+ (options, args) = parser.parse_args()
+
+ if (options.output != None):
+ try:
+ outfile = open(options.output, "w")
+ except:
+ print "cannot open %s for writing" % options.output
+
+ files = []
+ for filename in options.hosts:
+ if (os.path.splitext(filename)[1] == '.gz'):
+ file = gzip.open(filename)
+ else:
+ file = open(filename)
+
+ trace = {}
+ done = False
+ while not done:
+ try:
+ (seq, ts) = file.readline().split()
+ sequence = int(seq)
+ timestamp = long(ts)
+ except StopIteration:
+ done = True
+ except:
+ break
+
+ trace[sequence] = timestamp
+
+ files.append(trace)
+
+ sequences = []
+ sequences.append(sorted(files[0].keys()))
+ sequences.append(sorted(files[1].keys()))
+
+ if ((min(sequences[0]) > max(sequences[1])) or
+ (min(sequences[1]) > max(sequences[1]))):
+ print "sequences do not overlap"
+ sys.exit(1)
+
+ # Trim the dictionaries of non overlapping elements
+
+ index = 0
+ if ((min(sequences[0]) < min(sequences[1]))):
+ start = min(sequences[0])
+ end = min(sequences[1])
+ index = 0
+ else:
+ start = min(sequences[1])
+ end = min(sequences[0])
+ index = 1
+
+ for i in range(start, end):
+ del files[index][i]
+
+ if ((max(sequences[0]) > max(sequences[1]))):
+ start = max(sequences[1])
+ end = max(sequences[0])
+ index = 0
+ else:
+ start = max(sequences[0])
+ end = max(sequences[1])
+ index = 1
+
+ for i in range(start, end):
+ del files[index][i]
+
+ if options.start == 0:
+ options.start = min(files[0].keys())
+
+ graph = []
+
+ minimum = sys.maxint
+ maximum = -sys.maxint -1
+
+ for i in range(options.start,options.start + len(files[0])):
+ try:
+ delta = abs(files[1][i] - files[0][i])
+ except KeyError:
+ print "9:99:99.000900"
+ print "missing packet %d" % i
+ continue
+
+ if delta > maximum:
+ maximum = delta
+ if delta < minimum:
+ minimum = delta
+
+ if (options.output != None):
+ outfile.write(("%d %d\n" % (delta, (files[0][i] / 1000000000))))
+
+ graph.append(delta)
+
+ if (options.output != None):
+ outfile.close()
+
+ print "min %d, max %d" % (minimum, maximum)
+
+ # if (minimum.seconds > 1):
+ # print "Time difference exceeded one second maximum, " \
+ # "cannot graph differences"
+ # sys.exit(1)
+
+ plotter = Gnuplot.Gnuplot(debug=1)
+
+ if ((options.ymin != 0) or (options.ymax != 10)):
+ plotter.set_range('yrange', [options.ymin, options.ymax])
+
+ plotter.ylabel('Time Difference\\nNanoseconds')
+ plotter.xlabel('Sample Number')
+ plotter.plot(graph)
+
+ if (options.png != None):
+ plotter.hardcopy(options.png + ".png", terminal='png')
+ raw_input('Press return to exit')
+ else:
+ raw_input('Press return to exit')
+
+# The canonical way to make a python module into a script.
+# Remove if unnecessary.
+
+if __name__ == "__main__":
+ main()
|
