From: intel-ethernet Date: Thu, 1 Nov 2012 23:54:25 +0000 (-0700) Subject: Update directory structure, readmes, add gptp X-Git-Tag: submit/tizen/20130820.101009~37 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=669d1b7ba366874e280734f4bb9e81b57f0acb3c;p=profile%2Fivi%2FOpenAVB.git Update directory structure, readmes, add gptp --- diff --git a/README b/README index c4f87bc..b1e720b 100644 --- a/README +++ b/README @@ -1,87 +1,66 @@ -INTRODUCTION +Open AVB +======== +maintainer: eric.mann AT intel.com + +Intel created the Open AVB repository to encourage collaborative source code +development for AVB technology enabling. By publishing the source code, our +intent is to encourage standardization, stability and inter-operability between +multiple vendors. This repository - created by the Intel LAN Access Division - +is open for contributions from other vendors. The repository contains primarily +network building block components - drivers, libraries, example applications +and daemon source code - required to build an AVB system. It is planned to +eventually include the various packet encapsulation types, protocol discovery +daemons, libraries to convert media clocks to AVB clocks (and vice +versa), and drivers. + +This repository does not include all components required to build a full +production AVB system (e.g. a turnkey solution to stream stored or live audio +or video content). Some simple example applications are provided which +illustrate the flow - but a professional AVB system requires a full media stack +- including audio and video inputs and outputs, media processing elements, and +various graphical user interfaces. Various companies provide such integrated +solutions. + +LICENSING AND CONTRIBUTION GUIDELINES +====================================== +To the extent possible, content is licensed under BSD licensing terms. Linux +kernel mode components are provided under a GPLv2 license. The specific license +information is included in the various directories to eliminate confusion. We +encourage you to review the ‘LICENSE’ file included in the head of the +various subdirectories for details. + +Third party submissions are welcomed. Our intent for third party content +contributions is to enable derivative products with minimal licensing +entanglements. Practically speaking, this means we would enforce (a) an +original-source attestation for any contributed content, and (b) rejecting +patches with GPL content into existing “BSD” licensed components. Third +party copyrights can be included provided they do not narrow the licensing +terms of an existing component. + +Prior to accepting a commit, Intel may perform scans using third-party tools +to identify suspected hits of GPL code. Intel may also perform vulnerability +scans of patches in an attempt to find various coding errors such as memory +leaks, buffer overflows and usage of uninitialized variables. The submitter +will be asked to correct any detected issues prior to a commit. Owners +of submitted third-party content are free to apply changes without supervision +by Intel. + +RELATED OPEN SOURCE PROJECTS +============================ + +AVDECC +------ +Jeff Koftinoff maintains a repository of AVDECC example open +source code. AVDECC is a management layer, similar to SNMP MIB formats, +which enables remote devices to detect, enumerate and configure AVB-related +devices based on their standardized management properties. + ++ https://github.com/jdkoftinoff/avdecc ++ https://github.com/jdkoftinoff/avdecc-examples + +XMOS +---- +XMOS is a semiconductor company providing a reference design for AVB +endpoints in pro audio and automotive. Our source code is open source +and available on Github - https://github.com/xcore/sw_avb -This component demonstrates various features of the Intel I210 Ethernet controller. -These features can be used for developing Audio/Video Bridging applications, -Industrial Ethernet applications which require precise timing control over frame -transmission, or test harnesses for measuring system latencies and sampling events. - -This component - igb_avb - is limited to the Intel I210 Ethernet controller. The kernel -module can be loaded in parallel to existing in-kernel igb modules which may be -used on other supported Intel LAN controllers. Modifications are required to -the in-kernel drivers if the existing in-kernel igb driver has support for the Intel I210. - -BUILDING - -There are four primary components - kmod (for the kernel-mode igb_avb driver), -lib (for the user-mode driver library), examples (for test applications), and -daemons (at present an MRP daemon required for establishing AVB streams). - -To build, 'cd' into each of the respective directories, and execute 'make'. - -The kernel igb module can be built which supports the latest Linux kernel -3.x PTP clock support - to enable, modify kmod/Makefile and enable -DCONFIG_PTP -as a build option (e.g. EXTRA_CFLAGS += -DCONFIG_PTP). - -The example application uses the pciutils library - the latest version -can be downloaded from < ftp://ftp.kernel.org/pub/software/utils/pciutils/ >. -Download and extract the library, and run 'make;make install;make install-lib'. - -RUNNING - -To install the kernel mode driver, you must have root permissions. Typically, -the driver is loaded by: - sudo modprobe dca - sudo modprobe ptp - sudo insmod ./igb_avb.ko - -As 3.4 and later kernels include support for the I210, you may need to 'rmmod igb' -before loading the igb_avb module. - -Note that packets generated from the 'user-mode' libraries are not counted in -ifconfig output, and likewise, if generating multicast traffic, the receiving -node must be registered to receive the traffic (or run the interface in promiscious -mode). - -TIME SYNC - -This package relies on using the linuxptp daemon to establish time -synchronization. The latest source for this is available here: - - git clone git://git.code.sf.net/p/linuxptp/code linuxptp-code - -Type 'make' to build. This version has been tested with kernel 3.5.1. -Assuming kernel support is enabled, simply 'modprobe ptp' to load the -required kernel mode components. Example command line to the daemon is: - - ptp4l -f gPTP.cfg -2 -P -i p11p1 - -Note the default gPTP.cfg file queries and times out relatively fast while -awaiting the transmit timestamps to complete. To adjust this, modify the -'tx_timestamp_retries' parameter to 400 (which roughly corresponds to 400 usec). - -EXAMPLE APPLICATIONS - -The test application - which simply streams timed packets - requires root permissions -as well to execute and attach to the driver. - sudo ./test - -To exit the test app, hit Ctrl-C. The application gracefully tears down -the connection to the driver. If the application unexpectedly aborts the -kernel-mode driver also reclaims the various buffers and attempts to clean up. -The application should be able to re-initialize and use the transmit queues -without restarting the driver. - -The 'simple_talker' application illustrates the various steps to publish a stream -and being streaming after a listener connects. - -MRPD DAEMON - -The MRP daemon is required to establish stream reservations with compatible AVB -infrastructure devices. The command line selectively enables MMRP (via the -m option), -MVRP (via the -v option), and MSRP (via the -s option). You must also specify the -interface on which you want to bind the daemon to (e.g. -i eth2). The full command line -typically appears as follows: - sudo ./mrpd -mvs -i eth2 - -Sample client applications - mrpctl, mrpq, mrpl - illustrates how to connect, query -and add attributes to the MRP daemon. diff --git a/daemons/gptp/common/CVS/Entries b/daemons/gptp/common/CVS/Entries new file mode 100644 index 0000000..fb8a7b1 --- /dev/null +++ b/daemons/gptp/common/CVS/Entries @@ -0,0 +1,16 @@ +/avbts_clock.hpp/1.1/Fri Sep 21 15:48:06 2012// +/avbts_message.hpp/1.1/Fri Sep 7 19:02:51 2012// +/avbts_oscondition.hpp/1.1/Fri Sep 21 20:14:21 2012// +/avbts_osipc.hpp/1.1/Fri Sep 7 19:03:47 2012// +/avbts_oslock.hpp/1.1/Fri Sep 7 19:03:59 2012// +/avbts_osnet.cpp/1.1/Fri Sep 7 19:02:51 2012// +/avbts_osnet.hpp/1.1/Fri Sep 21 20:12:53 2012// +/avbts_osthread.hpp/1.1/Fri Sep 7 19:04:20 2012// +/avbts_ostimer.hpp/1.1/Fri Sep 7 19:04:50 2012// +/avbts_ostimerq.hpp/1.1/Fri Sep 7 19:02:51 2012// +/avbts_port.hpp/1.1/Fri Sep 21 20:11:27 2012// +/ieee1588.hpp/1.1/Fri Sep 21 15:56:15 2012// +/ieee1588clock.cpp/1.1/Fri Sep 21 15:57:08 2012// +/ieee1588port.cpp/1.1/Fri Sep 21 20:05:48 2012// +/ptp_message.cpp/1.1/Fri Sep 21 18:27:54 2012// +D diff --git a/daemons/gptp/common/CVS/Repository b/daemons/gptp/common/CVS/Repository new file mode 100644 index 0000000..95ecafe --- /dev/null +++ b/daemons/gptp/common/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/common diff --git a/daemons/gptp/common/CVS/Root b/daemons/gptp/common/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/common/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/common/avbts_clock.hpp b/daemons/gptp/common/avbts_clock.hpp new file mode 100644 index 0000000..b02fd55 --- /dev/null +++ b/daemons/gptp/common/avbts_clock.hpp @@ -0,0 +1,208 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_CLOCK_HPP +#define AVBTS_CLOCK_HPP + +#include +#include +#include +#include +#include + +#define EVENT_TIMER_GRANULARITY 5000000 + +struct ClockQuality { + unsigned char cq_class; + unsigned char clockAccuracy; + int16_t offsetScaledLogVariance; +}; + +class IEEE1588Clock { + private: + ClockIdentity clock_identity; + ClockQuality clock_quality; + unsigned char priority1; + unsigned char priority2; + bool initializable; + bool is_boundary_clock; + bool two_step_clock; + unsigned char domain_number; + uint16_t number_ports; + uint16_t number_foreign_records; + bool slave_only; + int16_t current_utc_offset; + bool leap_59; + bool leap_61; + uint16_t epoch_number; + uint16_t steps_removed; + int64_t offset_from_master; + Timestamp one_way_delay; + PortIdentity parent_identity; + PortIdentity grandmaster_port_identity; + ClockQuality grandmaster_clock_quality; + unsigned char grandmaster_priority1; + unsigned char grandmaster_priority2; + bool grandmaster_is_boundary_clock; + uint8_t time_source; + + int32_t master_local_offset_125us_offset; + uint64_t master_local_offset_nrst125us_initial; + bool master_local_offset_nrst125us_initialized; + + ClockIdentity LastEBestIdentity; + + IEEE1588Port *port_list[MAX_PORTS]; + + static Timestamp start_time; + Timestamp last_sync_time; + + OS_IPC *ipc; + + OSTimerQueue *timerq; + + bool forceOrdinarySlave; + public: + IEEE1588Clock(bool forceOrdinarySlave, + OSTimerQueueFactory * timerq_factory, OS_IPC * ipc); + ~IEEE1588Clock(void); + + Timestamp getTime(void); + Timestamp getPreciseTime(void); + + bool isBetterThan(PTPMessageAnnounce * msg); + + ClockIdentity getLastEBestIdentity( void ) { + return LastEBestIdentity; + } + void setLastEBestIdentity( ClockIdentity id ) { + LastEBestIdentity = id; + return; + } + + void setClockIdentity(char *id) { + clock_identity.set((uint8_t *) id); + } + void setClockIdentity(LinkLayerAddress * addr) { + clock_identity.set(addr); + } + + unsigned char getDomain(void) { + return domain_number; + } + + PortIdentity getGrandmasterPortIdentity(void) { + return grandmaster_port_identity; + } + void setGrandmasterPortIdentity(PortIdentity id) { + grandmaster_port_identity = id; + } + + ClockQuality getGrandmasterClockQuality(void) { + return grandmaster_clock_quality; + } + + ClockQuality getClockQuality(void) { + return clock_quality; + } + + unsigned char getGrandmasterPriority1(void) { + return grandmaster_priority1; + } + + unsigned char getGrandmasterPriority2(void) { + return grandmaster_priority2; + } + + uint16_t getMasterStepsRemoved(void) { + return steps_removed; + } + + uint16_t getCurrentUtcOffset(void) { + return current_utc_offset; + } + + uint8_t getTimeSource(void) { + return time_source; + } + + void getGrandmasterIdentity(char *id); + + unsigned char getPriority1(void) { + return priority1; + } + + unsigned char getPriority2(void) { + return priority2; + } + uint16_t getNextPortId(void) { + return (number_ports++ % (MAX_PORTS + 1)) + 1; + } + void registerPort(IEEE1588Port * port, uint16_t index) { + if (index < MAX_PORTS) { + port_list[index - 1] = port; + } + ++number_ports; + } + void getPortList(int &count, IEEE1588Port ** &ports) { + ports = this->port_list; + count = number_ports; + return; + } + + static Timestamp getSystemTime(void); + + void addEventTimer(IEEE1588Port * target, Event e, + unsigned long long time_ns); + void deleteEventTimer(IEEE1588Port * target, Event e); + +#define SHM_SIZE 2*sizeof( int64_t ) \ + + 2*(sizeof( last_sync_time.seconds_ms ) + sizeof( last_sync_time.seconds_ls ) + sizeof( last_sync_time.nanoseconds )) \ + + 4*sizeof(uint32_t) + sizeof( uint16_t ) + + void setMasterOffset(int64_t master_local_offset, Timestamp local_time, + int32_t master_local_freq_offset, + int64_t local_system_offset, Timestamp system_time, + int32_t local_system_freq_offset, + uint32_t nominal_clock_rate, uint32_t local_clock); + + ClockIdentity getClockIdentity() { + return clock_identity; + } + + friend void tick_handler(int sig); +}; + +void tick_handler(int sig); + +#endif diff --git a/daemons/gptp/common/avbts_message.hpp b/daemons/gptp/common/avbts_message.hpp new file mode 100644 index 0000000..fa8eff8 --- /dev/null +++ b/daemons/gptp/common/avbts_message.hpp @@ -0,0 +1,462 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_MESSAGE_HPP +#define AVBTS_MESSAGE_HPP + +#include +#include +#include + +#define PTP_CODE_STRING_LENGTH 4 +#define PTP_SUBDOMAIN_NAME_LENGTH 16 +#define PTP_FLAGS_LENGTH 2 + +#define GPTP_VERSION 2 +#define PTP_NETWORK_VERSION 1 + +#define PTP_ETHER 1 +#define PTP_DEFAULT 255 + +#define PTP_COMMON_HDR_OFFSET 0 +#define PTP_COMMON_HDR_LENGTH 34 +#define PTP_COMMON_HDR_TRANSSPEC_MSGTYPE(x) x +#define PTP_COMMON_HDR_PTP_VERSION(x) x+1 +#define PTP_COMMON_HDR_MSG_LENGTH(x) x+2 +#define PTP_COMMON_HDR_DOMAIN_NUMBER(x) x+4 +#define PTP_COMMON_HDR_FLAGS(x) x+6 +#define PTP_COMMON_HDR_CORRECTION(x) x+8 +#define PTP_COMMON_HDR_SOURCE_CLOCK_ID(x) x+20 +#define PTP_COMMON_HDR_SOURCE_PORT_ID(x) x+28 +#define PTP_COMMON_HDR_SEQUENCE_ID(x) x+30 +#define PTP_COMMON_HDR_CONTROL(x) x+32 +#define PTP_COMMON_HDR_LOG_MSG_INTRVL(x) x+33 + +#define PTP_ANNOUNCE_OFFSET 34 +#define PTP_ANNOUNCE_LENGTH 30 +#define PTP_ANNOUNCE_CURRENT_UTC_OFFSET(x) x+10 +#define PTP_ANNOUNCE_GRANDMASTER_PRIORITY1(x) x+13 +#define PTP_ANNOUNCE_GRANDMASTER_CLOCK_QUALITY(x) x+14 +#define PTP_ANNOUNCE_GRANDMASTER_PRIORITY2(x) x+18 +#define PTP_ANNOUNCE_GRANDMASTER_IDENTITY(x) x+19 +#define PTP_ANNOUNCE_STEPS_REMOVED(x) x+27 +#define PTP_ANNOUNCE_TIME_SOURCE(x) x+29 + +#define PTP_SYNC_OFFSET 34 +#define PTP_SYNC_LENGTH 10 +#define PTP_SYNC_SEC_MS(x) x +#define PTP_SYNC_SEC_LS(x) x+2 +#define PTP_SYNC_NSEC(x) x+6 + +#define PTP_FOLLOWUP_OFFSET 34 +#define PTP_FOLLOWUP_LENGTH 10 +#define PTP_FOLLOWUP_SEC_MS(x) x +#define PTP_FOLLOWUP_SEC_LS(x) x+2 +#define PTP_FOLLOWUP_NSEC(x) x+6 + +#define PTP_PDELAY_REQ_OFFSET 34 +#define PTP_PDELAY_REQ_LENGTH 20 +#define PTP_PDELAY_REQ_SEC_MS(x) x +#define PTP_PDELAY_REQ_SEC_LS(x) x+2 +#define PTP_PDELAY_REQ_NSEC(x) x+6 + +#define PTP_PDELAY_RESP_OFFSET 34 +#define PTP_PDELAY_RESP_LENGTH 20 +#define PTP_PDELAY_RESP_SEC_MS(x) x +#define PTP_PDELAY_RESP_SEC_LS(x) x+2 +#define PTP_PDELAY_RESP_NSEC(x) x+6 +#define PTP_PDELAY_RESP_REQ_CLOCK_ID(x) x+10 +#define PTP_PDELAY_RESP_REQ_PORT_ID(x) x+18 + +#define PTP_PDELAY_FOLLOWUP_OFFSET 34 +#define PTP_PDELAY_FOLLOWUP_LENGTH 20 +#define PTP_PDELAY_FOLLOWUP_SEC_MS(x) x +#define PTP_PDELAY_FOLLOWUP_SEC_LS(x) x+2 +#define PTP_PDELAY_FOLLOWUP_NSEC(x) x+6 +#define PTP_PDELAY_FOLLOWUP_REQ_CLOCK_ID(x) x+10 +#define PTP_PDELAY_FOLLOWUP_REQ_PORT_ID(x) x+18 + +#define PTP_LI_61_BYTE 0 +#define PTP_LI_61_BIT 0 +#define PTP_LI_59_BYTE 0 +#define PTP_LI_59_BIT 1 +#define PTP_ASSIST_BYTE 0 +#define PTP_ASSIST_BIT 1 + +enum MessageType { + SYNC_MESSAGE = 0, + DELAY_REQ_MESSAGE = 1, + PATH_DELAY_REQ_MESSAGE = 2, + PATH_DELAY_RESP_MESSAGE = 3, + FOLLOWUP_MESSAGE = 8, + DELAY_RESP_MESSAGE = 9, + PATH_DELAY_FOLLOWUP_MESSAGE = 0xA, + ANNOUNCE_MESSAGE = 0xB, + SIGNALLING_MESSAGE = 0xC, + MANAGEMENT_MESSAGE = 0xD, +}; + +enum LegacyMessageType { + SYNC, + DELAY_REQ, + FOLLOWUP, + DELAY_RESP, + MANAGEMENT, + MESSAGE_OTHER +}; + +enum MulticastType { + MCAST_NONE, + MCAST_PDELAY, + MCAST_OTHER +}; + +class PTPMessageCommon { + protected: + unsigned char versionPTP; + uint16_t versionNetwork; + MessageType messageType; + + PortIdentity *sourcePortIdentity; + + uint16_t sequenceId; + LegacyMessageType control; + unsigned char flags[2]; + + uint16_t messageLength; + char logMeanMessageInterval; + long long correctionField; + unsigned char domainNumber; + + Timestamp _timestamp; + unsigned _timestamp_counter_value; + bool _gc; + + PTPMessageCommon(void) { + }; + public: + PTPMessageCommon(IEEE1588Port * port); + virtual ~ PTPMessageCommon(void); + + unsigned char *getFlags(void) { + return flags; + } + + uint16_t getSequenceId(void) { + return sequenceId; + } + void setSequenceId(uint16_t seq) { + sequenceId = seq; + } + + MessageType getMessageType(void) { + return messageType; + } + + long long getCorrectionField(void) { + return correctionField; + } + void setCorrectionField(long long correctionAmount) { + correctionField = correctionAmount; + } + + void getPortIdentity(PortIdentity * identity); + void setPortIdentity(PortIdentity * identity); + + Timestamp getTimestamp(void) { + return _timestamp; + } + uint32_t getTimestampCounterValue(void) { + return _timestamp_counter_value;; + } + void setTimestamp(Timestamp & timestamp) { + _timestamp = timestamp; + } + + bool garbage() { + return _gc; + } + + bool isSenderEqual(PortIdentity portIdentity); + + virtual void processMessage(IEEE1588Port * port); + + void buildCommonHeader(uint8_t * buf); + + friend PTPMessageCommon *buildPTPMessage(char *buf, int size, + LinkLayerAddress * remote, + IEEE1588Port * port); +}; + +#pragma pack(push,1) + +class PathTraceTLV { + private: + uint16_t tlvType; + uint16_t lengthField; + ClockIdentity identity; + public: + PathTraceTLV() { + tlvType = PLAT_htons(0x8); + lengthField = PLAT_htons(sizeof(identity)); + } + void setClockIdentity(ClockIdentity * id) { + identity = *id; + } + void toByteString(uint8_t * byte_str) { + memcpy(byte_str, this, sizeof(*this)); + } +}; + +#pragma pack(pop) + +class PTPMessageAnnounce:public PTPMessageCommon { + private: + char grandmasterIdentity[PTP_CLOCK_IDENTITY_LENGTH]; + + PathTraceTLV tlv; + + uint16_t currentUtcOffset; + unsigned char grandmasterPriority1; + unsigned char grandmasterPriority2; + ClockQuality *clockQuality; + uint16_t stepsRemoved; + unsigned char timeSource; + + PTPMessageAnnounce(void); + public: + PTPMessageAnnounce(IEEE1588Port * port); + ~PTPMessageAnnounce(); + + bool isBetterThan(PTPMessageAnnounce * msg); + + unsigned char getGrandmasterPriority1(void) { + return grandmasterPriority1; + } + unsigned char getGrandmasterPriority2(void) { + return grandmasterPriority2; + } + + ClockQuality *getGrandmasterClockQuality(void) { + return clockQuality; + } + + uint16_t getStepsRemoved(void) { + return stepsRemoved; + } + + void getGrandmasterIdentity(char *identity) { + memcpy(identity, grandmasterIdentity, + PTP_CLOCK_IDENTITY_LENGTH); + } + + void processMessage(IEEE1588Port * port); + + void sendPort(IEEE1588Port * port, PortIdentity * destIdentity); + + friend PTPMessageCommon *buildPTPMessage(char *buf, int size, + LinkLayerAddress * remote, + IEEE1588Port * port); +}; + +class PTPMessageSync:public PTPMessageCommon { + private: + Timestamp originTimestamp; + + PTPMessageSync() { + return; + } + public: + PTPMessageSync(IEEE1588Port * port); + void processMessage(IEEE1588Port * port); + + Timestamp getOriginTimestamp(void) { + return originTimestamp; + } + + void sendPort(IEEE1588Port * port, PortIdentity * destIdentity); + + friend PTPMessageCommon *buildPTPMessage(char *buf, int size, + LinkLayerAddress * remote, + IEEE1588Port * port); +}; + +#pragma pack(push,1) + +class scaledNs { + private: + int32_t ms; + uint64_t ls; + public: + scaledNs() { + ms = 0; + ls = 0; + } void toByteString(uint8_t * byte_str) { + memcpy(byte_str, this, sizeof(*this)); + } +}; + +class FollowUpTLV { + private: + uint16_t tlvType; + uint16_t lengthField; + uint8_t organizationId[3]; + uint8_t organizationSubType_ms; + uint16_t organizationSubType_ls; + int32_t cumulativeScaledRateOffset; + uint16_t gmTimeBaseIndicator; + scaledNs scaledLastGmPhaseChange; + int32_t scaledLastGmFreqChange; + public: + FollowUpTLV() { + tlvType = PLAT_htons(0x3); + lengthField = PLAT_htons(28); + organizationId[0] = '\x00'; + organizationId[1] = '\x80'; + organizationId[2] = '\xC2'; + organizationSubType_ms = 0; + organizationSubType_ls = PLAT_htons(1); + cumulativeScaledRateOffset = PLAT_htonl(0); + gmTimeBaseIndicator = PLAT_htons(0); + scaledLastGmFreqChange = PLAT_htonl(0); + } + void toByteString(uint8_t * byte_str) { + memcpy(byte_str, this, sizeof(*this)); + } +}; + +#pragma pack(pop) + +class PTPMessageFollowUp:public PTPMessageCommon { + private: + Timestamp preciseOriginTimestamp; + + FollowUpTLV tlv; + + PTPMessageFollowUp(void) { + } public: + PTPMessageFollowUp(IEEE1588Port * port); + void sendPort(IEEE1588Port * port, PortIdentity * destIdentity); + void processMessage(IEEE1588Port * port); + + Timestamp getPreciseOriginTimestamp(void) { + return preciseOriginTimestamp; + } + void setPreciseOriginTimestamp(Timestamp & timestamp) { + preciseOriginTimestamp = timestamp; + } + + friend PTPMessageCommon *buildPTPMessage(char *buf, int size, + LinkLayerAddress * remote, + IEEE1588Port * port); +}; + +class PTPMessagePathDelayReq:public PTPMessageCommon { + private: + Timestamp originTimestamp; + + PTPMessagePathDelayReq() { + return; + } + public: + PTPMessagePathDelayReq(IEEE1588Port * port); + void sendPort(IEEE1588Port * port, PortIdentity * destIdentity); + void processMessage(IEEE1588Port * port); + + Timestamp getOriginTimestamp(void) { + return originTimestamp; + } + + friend PTPMessageCommon *buildPTPMessage(char *buf, int size, + LinkLayerAddress * remote, + IEEE1588Port * port); +}; + +class PTPMessagePathDelayResp:public PTPMessageCommon { + private: + PortIdentity * requestingPortIdentity; + Timestamp requestReceiptTimestamp; + + PTPMessagePathDelayResp(void) { + } public: + ~PTPMessagePathDelayResp(); + PTPMessagePathDelayResp(IEEE1588Port * port); + void sendPort(IEEE1588Port * port, PortIdentity * destIdentity); + void processMessage(IEEE1588Port * port); + + void setRequestReceiptTimestamp(Timestamp timestamp) { + requestReceiptTimestamp = timestamp; + } + + void setRequestingPortIdentity(PortIdentity * identity); + void getRequestingPortIdentity(PortIdentity * identity); + + Timestamp getRequestReceiptTimestamp(void) { + return requestReceiptTimestamp; + } + + friend PTPMessageCommon *buildPTPMessage(char *buf, int size, + LinkLayerAddress * remote, + IEEE1588Port * port); +}; + +class PTPMessagePathDelayRespFollowUp:public PTPMessageCommon { + private: + Timestamp responseOriginTimestamp; + PortIdentity *requestingPortIdentity; + + PTPMessagePathDelayRespFollowUp(void) { + } public: + PTPMessagePathDelayRespFollowUp(IEEE1588Port * port); + ~PTPMessagePathDelayRespFollowUp(); + void sendPort(IEEE1588Port * port, PortIdentity * destIdentity); + void processMessage(IEEE1588Port * port); + + void setResponseOriginTimestamp(Timestamp timestamp) { + responseOriginTimestamp = timestamp; + } + void setRequestingPortIdentity(PortIdentity * identity); + + Timestamp getResponseOriginTimestamp(void) { + return responseOriginTimestamp; + } + PortIdentity *getRequestingPortIdentity(void) { + return requestingPortIdentity; + } + + friend PTPMessageCommon *buildPTPMessage(char *buf, int size, + LinkLayerAddress * remote, + IEEE1588Port * port); +}; + +#endif diff --git a/daemons/gptp/common/avbts_oscondition.hpp b/daemons/gptp/common/avbts_oscondition.hpp new file mode 100644 index 0000000..90232f0 --- /dev/null +++ b/daemons/gptp/common/avbts_oscondition.hpp @@ -0,0 +1,63 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_OSSIGNAL_HPP +#define AVBTS_OSSIGNAL_HPP + class OSCondition { +private: + int wait_count; +public: + virtual bool wait() = 0; + virtual bool wait_prelock() = 0; + virtual bool signal() = 0; +protected: + OSCondition() { + wait_count = 0; + }; + void up() { + ++wait_count; + } + void down() { + --wait_count; + } + bool waiting() { + return wait_count > 0; + } +}; + + class OSConditionFactory { + public:virtual OSCondition * createCondition() = 0; +}; + + +#endif diff --git a/daemons/gptp/common/avbts_osipc.hpp b/daemons/gptp/common/avbts_osipc.hpp new file mode 100644 index 0000000..ce7f576 --- /dev/null +++ b/daemons/gptp/common/avbts_osipc.hpp @@ -0,0 +1,44 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_OSIPC_HPP +#define AVBTS_OSIPC_HPP + class OS_IPC { + public:virtual bool init() = 0; + virtual bool update(int64_t ml_phoffset, int64_t ls_phoffset, + int32_t ml_freqoffset, int32_t ls_freq_offset, + uint64_t local_time) = 0; +}; + + +#endif diff --git a/daemons/gptp/common/avbts_oslock.hpp b/daemons/gptp/common/avbts_oslock.hpp new file mode 100644 index 0000000..8877ada --- /dev/null +++ b/daemons/gptp/common/avbts_oslock.hpp @@ -0,0 +1,54 @@ +/****************************************************************************** + + Copyright (c) 2001-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_OSLOCK_HPP +#define AVBTS_OSLOCK_HPP + typedef enum { oslock_recursive, oslock_nonrecursive } OSLockType; +typedef enum { oslock_ok, oslock_self, oslock_held, oslock_fail } OSLockResult; + class OSLock { + public:virtual OSLockResult lock() = 0; + virtual OSLockResult unlock() = 0; + virtual OSLockResult trylock() = 0; + protected:OSLock() { + }; + bool initialize(OSLockType type) { + return false; + }; +}; + + class OSLockFactory { + public:virtual OSLock * createLock(OSLockType type) = 0; +}; + + +#endif diff --git a/daemons/gptp/common/avbts_osnet.cpp b/daemons/gptp/common/avbts_osnet.cpp new file mode 100644 index 0000000..2039f23 --- /dev/null +++ b/daemons/gptp/common/avbts_osnet.cpp @@ -0,0 +1,37 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#include + +std::map < factory_name_t, + OSNetworkInterfaceFactory * >OSNetworkInterfaceFactory::factoryMap; diff --git a/daemons/gptp/common/avbts_osnet.hpp b/daemons/gptp/common/avbts_osnet.hpp new file mode 100644 index 0000000..5656072 --- /dev/null +++ b/daemons/gptp/common/avbts_osnet.hpp @@ -0,0 +1,176 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_OSNET_HPP +#define AVBTS_OSNET_HPP + +#include +#include +#include +#include + +#define FACTORY_NAME_LENGTH 48 +#define ETHER_ADDR_OCTETS 6 +#define PTP_ETHERTYPE 0x88F7 +#define DEFAULT_TIMEOUT 1 // milliseconds + +class LinkLayerAddress:public InterfaceLabel { + private: + uint8_t addr[ETHER_ADDR_OCTETS]; + public: + LinkLayerAddress() { + }; + LinkLayerAddress(uint64_t address_scalar) { + uint8_t *ptr; + address_scalar <<= 16; + for (ptr = addr; ptr < addr + ETHER_ADDR_OCTETS; ++ptr) { + *ptr = (address_scalar & 0xFF00000000000000ULL) >> 56; + address_scalar <<= 8; + } + } + LinkLayerAddress(uint8_t * address_octet_array) { + uint8_t *ptr; + for (ptr = addr; ptr < addr + ETHER_ADDR_OCTETS; + ++ptr, ++address_octet_array) { + *ptr = *address_octet_array; + } + } + bool operator==(const LinkLayerAddress & cmp) const { + return memcmp(this->addr, cmp.addr, + ETHER_ADDR_OCTETS) == 0 ? true : false; + } + bool operator<(const LinkLayerAddress & cmp)const { + return memcmp(this->addr, cmp.addr, + ETHER_ADDR_OCTETS) < 0 ? true : false; + } + bool operator>(const LinkLayerAddress & cmp)const { + return memcmp(this->addr, cmp.addr, + ETHER_ADDR_OCTETS) < 0 ? true : false; + } + void toOctetArray(uint8_t * address_octet_array) { + uint8_t *ptr; + for (ptr = addr; ptr < addr + ETHER_ADDR_OCTETS; + ++ptr, ++address_octet_array) { + *address_octet_array = *ptr; + } + } +}; + +class InterfaceName:public InterfaceLabel { + private: + char *name; + public: + InterfaceName() { + }; + InterfaceName(char *name, int length) { + this->name = new char[length + 1]; + PLAT_strncpy(this->name, name, length); + } + bool operator==(const InterfaceName & cmp) const { + return strcmp(name, cmp.name) == 0 ? true : false; + } + bool operator<(const InterfaceName & cmp)const { + return strcmp(name, cmp.name) < 0 ? true : false; + } + bool operator>(const InterfaceName & cmp)const { + return strcmp(name, cmp.name) < 0 ? true : false; + } + bool toString(char *string, size_t length) { + if (length >= strlen(name) + 1) { + PLAT_strncpy(string, name, length); + return true; + } + return false; + } +}; + +class factory_name_t { + private: + char name[FACTORY_NAME_LENGTH]; + factory_name_t(); + public: + factory_name_t(const char *name_a) { + PLAT_strncpy(name, name_a, FACTORY_NAME_LENGTH - 1); + } + bool operator==(const factory_name_t & cmp) { + return strcmp(cmp.name, this->name) == 0 ? true : false; + } + bool operator<(const factory_name_t & cmp)const { + return strcmp(cmp.name, this->name) < 0 ? true : false; + } + bool operator>(const factory_name_t & cmp)const { + return strcmp(cmp.name, this->name) > 0 ? true : false; + } +}; + +typedef enum { net_trfail, net_fatal, net_succeed } net_result; + +class OSNetworkInterface { + public: + virtual net_result send(LinkLayerAddress * addr, uint8_t * payload, + size_t length, bool timestamp) = 0; + virtual net_result recv(LinkLayerAddress * addr, uint8_t * payload, + size_t & length) = 0; + virtual void getLinkLayerAddress(LinkLayerAddress * addr) = 0; + virtual unsigned getPayloadOffset() = 0; +}; + +class OSNetworkInterfaceFactory; + +typedef std::map < factory_name_t, OSNetworkInterfaceFactory * >FactoryMap_t; + +class OSNetworkInterfaceFactory { + public: + static bool registerFactory(factory_name_t id, + OSNetworkInterfaceFactory * factory) { + FactoryMap_t::iterator iter = factoryMap.find(id); + if (iter != factoryMap.end()) + return false; + factoryMap[id] = factory; + return true; + } + static bool buildInterface(OSNetworkInterface ** iface, + factory_name_t id, + InterfaceLabel * iflabel, + HWTimestamper * timestamper) { + return factoryMap[id]->createInterface(iface, iflabel, + timestamper); + } + private: + virtual bool createInterface(OSNetworkInterface ** iface, + InterfaceLabel * iflabel, + HWTimestamper * timestamper) = 0; + static FactoryMap_t factoryMap; +}; + +#endif diff --git a/daemons/gptp/common/avbts_osthread.hpp b/daemons/gptp/common/avbts_osthread.hpp new file mode 100644 index 0000000..24520ce --- /dev/null +++ b/daemons/gptp/common/avbts_osthread.hpp @@ -0,0 +1,48 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_OSTHREAD_HPP +#define AVBTS_OSTHREAD_HPP + typedef enum { osthread_ok, osthread_error } OSThreadExitCode; +typedef OSThreadExitCode(*OSThreadFunction) (void *); + class OSThread { + public:virtual bool start(OSThreadFunction function, void *arg) = 0; + virtual bool join(OSThreadExitCode & exit_code) = 0; +}; + + class OSThreadFactory { + public:virtual OSThread * createThread() = 0; +}; + + +#endif diff --git a/daemons/gptp/common/avbts_ostimer.hpp b/daemons/gptp/common/avbts_ostimer.hpp new file mode 100644 index 0000000..8fda4c1 --- /dev/null +++ b/daemons/gptp/common/avbts_ostimer.hpp @@ -0,0 +1,46 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_OSTIMER_HPP +#define AVBTS_OSTIMER_HPP + +class OSTimer { + public:virtual unsigned long sleep(unsigned long micro) = 0; +}; + +class OSTimerFactory { + public:virtual OSTimer * createTimer() = 0; +}; + + +#endif diff --git a/daemons/gptp/common/avbts_ostimerq.hpp b/daemons/gptp/common/avbts_ostimerq.hpp new file mode 100644 index 0000000..a0b1163 --- /dev/null +++ b/daemons/gptp/common/avbts_ostimerq.hpp @@ -0,0 +1,52 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_OSTIMERQ_HPP +#define AVBTS_OSTIMERQ_HPP + +typedef void (*ostimerq_handler) (void *); + +class OSTimerQueue { + public: + virtual bool addEvent(unsigned long micros, int type, + ostimerq_handler func, event_descriptor_t * arg, + bool dynamic, unsigned *event) = 0; + virtual bool cancelEvent(int type, unsigned *event) = 0; +}; + +class OSTimerQueueFactory { + public: + virtual OSTimerQueue * createOSTimerQueue() = 0; +}; + +#endif diff --git a/daemons/gptp/common/avbts_port.hpp b/daemons/gptp/common/avbts_port.hpp new file mode 100644 index 0000000..32d2e29 --- /dev/null +++ b/daemons/gptp/common/avbts_port.hpp @@ -0,0 +1,450 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef AVBTS_PORT_HPP +#define AVBTS_PORT_HPP + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define GPTP_MULTICAST 0x0180C200000EULL +#define PDELAY_MULTICAST GPTP_MULTICAST +#define OTHER_MULTICAST GPTP_MULTICAST + +#define PDELAY_RESP_RECEIPT_TIMEOUT_MULTIPLIER 3 +#define SYNC_RECEIPT_TIMEOUT_MULTIPLIER 10 +#define ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER 10 + +typedef enum { + PTP_MASTER, + PTP_PRE_MASTER, + PTP_SLAVE, + PTP_UNCALIBRATED, + PTP_DISABLED, + PTP_FAULTY, + PTP_INITIALIZING, + PTP_LISTENING +} PortState; + +typedef enum { + V1, + V2_E2E, + V2_P2P +} PortType; + +class PortIdentity { + private: + ClockIdentity clock_id; + uint16_t portNumber; + public: + PortIdentity() { + }; + PortIdentity(uint8_t * clock_id, uint16_t * portNumber) { + this->portNumber = *portNumber; + this->portNumber = PLAT_ntohs(this->portNumber); + this->clock_id.set(clock_id); + } + bool operator!=(const PortIdentity & cmp) const { + return !(this->clock_id == cmp.clock_id) + || this->portNumber != cmp.portNumber ? true : false; + } + bool operator==(const PortIdentity & cmp)const { + return this->clock_id == cmp.clock_id + && this->portNumber == cmp.portNumber ? true : false; + } + bool operator<(const PortIdentity & cmp)const { + return this->clock_id < cmp.clock_id ? true : + this->clock_id == cmp.clock_id + && this->portNumber < cmp.portNumber ? true : false; + } + bool operator>(const PortIdentity & cmp)const { + return this->clock_id > cmp.clock_id ? true : + this->clock_id == cmp.clock_id + && this->portNumber > cmp.portNumber ? true : false; + } + void getClockIdentityString(char *id) { + clock_id.getIdentityString(id); + } + void setClockIdentity(ClockIdentity clock_id) { + this->clock_id = clock_id; + } + ClockIdentity getClockIdentity( void ) { + return this->clock_id; + } + void getPortNumberNO(uint16_t * id) { // Network byte order + uint16_t portNumberNO = PLAT_htons(portNumber); + *id = portNumberNO; + } + void getPortNumber(uint16_t * id) { // Host byte order + *id = portNumber; + } + void setPortNumber(uint16_t * id) { + portNumber = *id; + } +}; + +typedef std::map < PortIdentity, LinkLayerAddress > IdentityMap_t; + +typedef std::list < PTPMessageAnnounce * >AnnounceList_t; + +class IEEE1588Port { + static LinkLayerAddress other_multicast; + static LinkLayerAddress pdelay_multicast; + + PortIdentity port_identity; + // directly connected node + PortIdentity peer_identity; + + OSNetworkInterface *net_iface; + LinkLayerAddress local_addr; + + // Port Configuration + unsigned char delay_mechanism; + PortState port_state; + char log_mean_unicast_sync_interval; + char log_mean_sync_interval; + char log_mean_announce_interval; + char log_min_mean_delay_req_interval; + char log_min_mean_pdelay_req_interval; + bool burst_enabled; + int64_t one_way_delay; // Allow this to be negative result of a large clock skew + // Implementation Specific data/methods + IEEE1588Clock *clock; // Pointer to clock object with which the port is associated + + bool _syntonize; + + bool asCapable; + + int32_t *rate_offset_array; + uint32_t rate_offset_array_size; + uint32_t rate_offset_count; + uint32_t rate_offset_index; + + int32_t _peer_rate_offset; + Timestamp _peer_offset_ts_theirs; + Timestamp _peer_offset_ts_mine; + bool _peer_offset_init; + + int32_t _master_rate_offset; + + int32_t _initial_clock_offset; + int32_t _current_clock_offset; + + bool _master_local_freq_offset_init; + int64_t _prev_master_local_offset; + Timestamp _prev_sync_time; + + bool _local_system_freq_offset_init; + int64_t _prev_local_system_offset; + Timestamp _prev_system_time; + + AnnounceList_t qualified_announce; + + uint16_t announce_sequence_id; + uint16_t sync_sequence_id; + + uint16_t pdelay_sequence_id; + PTPMessagePathDelayReq *last_pdelay_req; + PTPMessagePathDelayResp *last_pdelay_resp; + PTPMessagePathDelayRespFollowUp *last_pdelay_resp_fwup; + + // Network socket description + uint16_t ifindex; // physical interface number that object represents + + IdentityMap_t identity_map; + + PTPMessageSync *last_sync; + + OSThread *listening_thread; + + OSCondition *port_ready_condition; + + OSLock *pdelay_rx_lock; + OSLock *port_tx_lock; + + OSThreadFactory *thread_factory; + OSTimerFactory *timer_factory; + + HWTimestamper *_hw_timestamper; + + net_result port_send(uint8_t * buf, int size, MulticastType mcast_type, + PortIdentity * destIdentity, bool timestamp); + + InterfaceLabel *net_label; + + OSLockFactory *lock_factory; + OSConditionFactory *condition_factory; + public: + // Added for testing + bool forceSlave; + + OSTimerFactory *getTimerFactory() { + return timer_factory; + } + void setAsCapable(bool ascap) { + if (ascap != asCapable) { + fprintf(stderr, "AsCapable: %s\n", + ascap == true ? "Enabled" : "Disabled"); + } + asCapable = ascap; + } + + ~IEEE1588Port(); + IEEE1588Port(IEEE1588Clock * clock, uint16_t index, bool forceSlave, + HWTimestamper * timestamper, bool syntonize, + int32_t offset, InterfaceLabel * net_label, + OSConditionFactory * condition_factory, + OSThreadFactory * thread_factory, + OSTimerFactory * timer_factory, + OSLockFactory * lock_factory); + bool init_port(); + + void recoverPort(void); + void *openPort(void); + unsigned getPayloadOffset(); + void sendEventPort(uint8_t * buf, int len, MulticastType mcast_type, + PortIdentity * destIdentity); + void sendGeneralPort(uint8_t * buf, int len, MulticastType mcast_type, + PortIdentity * destIdentity); + void processEvent(Event e); + + PTPMessageAnnounce *calculateERBest(void); + + void addForeignMaster(PTPMessageAnnounce * msg); + void removeForeignMaster(PTPMessageAnnounce * msg); + void removeForeignMasterAll(void); + + void addQualifiedAnnounce(PTPMessageAnnounce * msg) { + qualified_announce.push_front(msg); + } + + void removeQualifiedAnnounce(PTPMessageAnnounce * msg) { + qualified_announce.remove(msg); + } + + char getSyncInterval(void) { + return log_mean_sync_interval; + } + char getAnnounceInterval(void) { + return log_mean_announce_interval; + } + char getPDelayInterval(void) { + return log_min_mean_pdelay_req_interval; + } + PortState getPortState(void) { + return port_state; + } + void getPortIdentity(PortIdentity & identity) { + identity = this->port_identity; + } + bool burstEnabled(void) { + return burst_enabled; + } + uint16_t getNextAnnounceSequenceId(void) { + return announce_sequence_id++; + } + uint16_t getNextSyncSequenceId(void) { + return sync_sequence_id++; + } + uint16_t getNextPDelaySequenceId(void) { + return pdelay_sequence_id++; + } + + uint16_t getParentLastSyncSequenceNumber(void); + void setParentLastSyncSequenceNumber(uint16_t num); + + IEEE1588Clock *getClock(void); + + void setLastSync(PTPMessageSync * msg) { + last_sync = msg; + } + PTPMessageSync *getLastSync(void) { + return last_sync; + } + + bool getPDelayRxLock() { + return pdelay_rx_lock->lock() == oslock_ok ? true : false; + } + + bool tryPDelayRxLock() { + return pdelay_rx_lock->trylock() == oslock_ok ? true : false; + } + + bool putPDelayRxLock() { + return pdelay_rx_lock->unlock() == oslock_ok ? true : false; + } + + int getTxLock() { + return port_tx_lock->lock() == oslock_ok ? true : false; + } + int putTxLock() { + return port_tx_lock->unlock() == oslock_ok ? true : false; + } + + void setLastPDelayReq(PTPMessagePathDelayReq * msg) { + last_pdelay_req = msg; + } + PTPMessagePathDelayReq *getLastPDelayReq(void) { + return last_pdelay_req; + } + + void setLastPDelayResp(PTPMessagePathDelayResp * msg) { + last_pdelay_resp = msg; + } + PTPMessagePathDelayResp *getLastPDelayResp(void) { + return last_pdelay_resp; + } + + void setLastPDelayRespFollowUp(PTPMessagePathDelayRespFollowUp * msg) { + last_pdelay_resp_fwup = msg; + } + PTPMessagePathDelayRespFollowUp *getLastPDelayRespFollowUp(void) { + return last_pdelay_resp_fwup; + } + + int calcMasterLocalClockRateDifference(signed long long offset, + Timestamp sync_time); + int calcLocalSystemClockRateDifference(signed long long offset, + Timestamp sync_time); + + int32_t getMasterRateOffset(void) { + return _master_rate_offset; + } + void setMasterRateOffset(int32_t offset + /* parts-per-trillion frequency offset */ ) { + _master_rate_offset = offset; + } + int32_t getPeerRateOffset(void) { + return _peer_rate_offset; + } + void setPeerRateOffset(int32_t offset + /* parts-per-trillion frequency offset */ ) { + _peer_rate_offset = offset; + } + void setPeerOffset(Timestamp mine, Timestamp theirs) { + _peer_offset_ts_mine = mine; + _peer_offset_ts_theirs = theirs; + _peer_offset_init = true; + } + bool getPeerOffset(Timestamp & mine, Timestamp & theirs) { + mine = _peer_offset_ts_mine; + theirs = _peer_offset_ts_theirs; + return _peer_offset_init; + } + + bool _adjustClockRate(int32_t freq_offset, unsigned counter_value, + Timestamp master_timestamp, int64_t offset, + bool change_master) { + if (_hw_timestamper) { + return + _hw_timestamper->HWTimestamper_adjclockrate + (freq_offset, counter_value, master_timestamp, + offset, change_master); + } + return false; + } + bool adjustClockRate(int32_t freq_offset, unsigned counter_value, + Timestamp master_timestamp, int64_t offset, + bool change_master) { + return _adjustClockRate(freq_offset, counter_value, + master_timestamp, offset, + change_master); + } + + bool doSyntonization(void) { + return _syntonize; + } + + void getExtendedError(char *msg) { + if (_hw_timestamper) { + _hw_timestamper->HWTimestamper_get_extderror(msg); + } else { + *msg = '\0'; + } + } + + bool getExternalClockRate(Timestamp & local_time, + int64_t & external_local_offset, + int32_t & external_local_freq_offset) { + bool s = false; + if (_hw_timestamper) { + s = _hw_timestamper->HWTimestamper_get_extclk_offset + (&local_time, &external_local_offset, + &external_local_freq_offset); + } + return s; + } + + int getRxTimestamp(PortIdentity * sourcePortIdentity, + uint16_t sequenceId, Timestamp & timestamp, + unsigned &counter_value, bool last); + int getTxTimestamp(PortIdentity * sourcePortIdentity, + uint16_t sequenceId, Timestamp & timestamp, + unsigned &counter_value, bool last); + + int getTxTimestamp(PTPMessageCommon * msg, Timestamp & timestamp, + unsigned &counter_value, bool last); + int getRxTimestamp(PTPMessageCommon * msg, Timestamp & timestamp, + unsigned &counter_value, bool last); + + void getDeviceTime(Timestamp & system_time, Timestamp & device_time, + uint32_t & local_clock, + uint32_t & nominal_clock_rate); + + int64_t getLinkDelay(void) { + return one_way_delay; + } + void setLinkDelay(int64_t delay) { + one_way_delay = delay; + } + + void recommendState(PortState state, bool changed_master); + + void mapSocketAddr(PortIdentity * destIdentity, + LinkLayerAddress * remote); + void addSockAddrMap(PortIdentity * destIdentity, + LinkLayerAddress * remote); +}; + +#endif diff --git a/daemons/gptp/common/ieee1588.hpp b/daemons/gptp/common/ieee1588.hpp new file mode 100644 index 0000000..bffd555 --- /dev/null +++ b/daemons/gptp/common/ieee1588.hpp @@ -0,0 +1,231 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef IEEE1588_HPP +#define IEEE1588_HPP + +#include + +#include + +#include + +#include + +#include + +#define MAX_PORTS 32 + +#define PTP_CLOCK_IDENTITY_LENGTH 8 + +class LinkLayerAddress; +struct ClockQuality; +class PortIdentity; +class IEEE1588Clock; +class PTPMessageCommon; +class PTPMessageSync; +class PTPMessageAnnounce; +class PTPMessagePathDelayReq; +class PTPMessagePathDelayResp; +class PTPMessagePathDelayRespFollowUp; +class IEEE1588Port; + +typedef enum { + NULL_EVENT = 0, + POWERUP = 5, + INITIALIZE, + STATE_CHANGE_EVENT, + SYNC_INTERVAL_TIMEOUT_EXPIRES, + PDELAY_INTERVAL_TIMEOUT_EXPIRES, + SYNC_RECEIPT_TIMEOUT_EXPIRES, + QUALIFICATION_TIMEOUT_EXPIRES, + ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES, + ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES, + FAULT_DETECTED, + PDELAY_DEFERRED_PROCESSING, + PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES, +} Event; + +typedef struct { + IEEE1588Port *port; + Event event; +} event_descriptor_t; + +class InterfaceLabel { + public: + virtual ~ InterfaceLabel() { + }; +}; + +class ClockIdentity { + private: + uint8_t id[PTP_CLOCK_IDENTITY_LENGTH]; + public: + bool operator==(const ClockIdentity & cmp) const { + return memcmp(this->id, cmp.id, + PTP_CLOCK_IDENTITY_LENGTH) == 0 ? true : false; + } + bool operator!=( const ClockIdentity &cmp ) const { + return memcmp( this->id, cmp.id, PTP_CLOCK_IDENTITY_LENGTH ) != 0 ? true : false; + } + bool operator<(const ClockIdentity & cmp)const { + return memcmp(this->id, cmp.id, + PTP_CLOCK_IDENTITY_LENGTH) < 0 ? true : false; + } + bool operator>(const ClockIdentity & cmp)const { + return memcmp(this->id, cmp.id, + PTP_CLOCK_IDENTITY_LENGTH) < 0 ? true : false; + } + void getIdentityString(char *id) { + memcpy(id, this->id, PTP_CLOCK_IDENTITY_LENGTH); + } + void set(uint8_t * id) { + memcpy(this->id, id, PTP_CLOCK_IDENTITY_LENGTH); + } + void set(LinkLayerAddress * address); +}; + +class Timestamp { + public: + Timestamp(uint32_t ns, uint32_t s_l, uint16_t s_m) { + nanoseconds = ns; + seconds_ls = s_l; + seconds_ms = s_m; + } + Timestamp() { + }; + uint32_t nanoseconds; + uint32_t seconds_ls; + uint16_t seconds_ms; +}; + +#define INVALID_TIMESTAMP (Timestamp( 0xC0000000, 0, 0 )) +#define PDELAY_PENDING_TIMESTAMP (Timestamp( 0xC0000001, 0, 0 )) + +#define TIMESTAMP_TO_NS(ts) (((static_cast(ts.seconds_ms) << sizeof(ts.seconds_ls)*8) + ts.seconds_ls)*1000000000LL + \ + ts.nanoseconds) + +static inline uint64_t bswap_64(uint64_t in) +{ + uint8_t *s = (uint8_t *) & in; + uint8_t *e = s + 7; + while (e > s) { + uint8_t t; + t = *s; + *s = *e; + *e = t; + ++s; + --e; + } + return in; +} + +static inline void TIMESTAMP_SUB_NS(Timestamp & ts, uint64_t ns) +{ + while (ns >= 1000000000) { + if (ts.seconds_ls != 0) { + --ts.seconds_ls; + } else { + --ts.seconds_ms; + ts.seconds_ls = 0xFFFFFFFF; + } + ns -= 1000000000; + } + ts.nanoseconds -= (uint32_t) ns; +} + +#define XPTPD_ERROR(fmt,...) fprintf( stderr, "ERROR at %u in %s: " fmt "\n", __LINE__, __FILE__ ,## __VA_ARGS__) +#ifdef PTP_DEBUG +#define XPTPD_INFO(fmt,...) fprintf( stderr, "DEBUG at %u in %s: " fmt "\n", __LINE__, __FILE__ ,## __VA_ARGS__) +#else +#define XPTPD_INFO(fmt,...) +#endif + +#define HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE 4096 + +class HWTimestamper { + public: + virtual bool HWTimestamper_init(InterfaceLabel * iface_label) { + return true; + } + virtual void HWTimestamper_final(void) { + } + + virtual bool HWTimestamper_adjclockrate(int32_t frequency_offset, + unsigned counter_value, + Timestamp master_timestamp, + int64_t offset, + bool changed_master) { + return false; + } + virtual bool HWTimestamper_adjclockrate2(int32_t ppt_adjustment) { + return false; + } + + virtual bool HWTimestamper_gettime(Timestamp * system_time, + Timestamp * device_time, + uint32_t * local_clock, + uint32_t * nominal_clock_rate) = 0; + + virtual int HWTimestamper_txtimestamp(PortIdentity * identity, + uint16_t sequenceId, + Timestamp & timestamp, + unsigned &clock_value, + bool last) = 0; + + virtual int HWTimestamper_rxtimestamp(PortIdentity * identity, + uint16_t sequenceId, + Timestamp & timestamp, + unsigned &clock_value, + bool last) = 0; + + virtual bool HWTimestamper_get_extclk_offset(Timestamp * local_time, + int64_t * clk_offset, + int32_t * + ppt_freq_offset) { + return false; + } + + virtual void HWTimestamper_get_extderror(char *msg) { + *msg = '\0'; + } + + virtual ~ HWTimestamper() { + } +}; + +PTPMessageCommon *buildPTPMessage(char *buf, int size, + LinkLayerAddress * remote, + IEEE1588Port * port); + +#endif diff --git a/daemons/gptp/common/ieee1588clock.cpp b/daemons/gptp/common/ieee1588clock.cpp new file mode 100644 index 0000000..6f289fc --- /dev/null +++ b/daemons/gptp/common/ieee1588clock.cpp @@ -0,0 +1,197 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include + +#include + +#include + +void ClockIdentity::set(LinkLayerAddress * addr) +{ + uint64_t tmp1 = 0; + uint32_t tmp2; + addr->toOctetArray((uint8_t *) & tmp1); + tmp2 = tmp1 & 0xFFFFFF; + tmp1 >>= 24; + tmp1 <<= 16; + tmp1 |= 0xFEFF; + tmp1 <<= 24; + tmp1 |= tmp2; + memcpy(id, &tmp1, PTP_CLOCK_IDENTITY_LENGTH); +} + +IEEE1588Clock::IEEE1588Clock(bool forceOrdinarySlave, + OSTimerQueueFactory * timerq_factory, OS_IPC * ipc) +{ + timerq = timerq_factory->createOSTimerQueue(); + + priority1 = 248; + priority2 = 248; + + master_local_offset_nrst125us_initialized = false; + + number_ports = 0; + + this->forceOrdinarySlave = forceOrdinarySlave; + + clock_quality.clockAccuracy = 0xfe; + clock_quality.cq_class = 248; + clock_quality.offsetScaledLogVariance = 16640; + + time_source = 160; + + domain_number = 0; + + this->ipc = ipc; + + memset( &LastEBestIdentity, 0xFF, sizeof( LastEBestIdentity )); + return; +} + +Timestamp IEEE1588Clock::getSystemTime(void) +{ + return (Timestamp(0, 0, 0)); +} + +void timerq_handler(void *arg) +{ + event_descriptor_t *event_descriptor = (event_descriptor_t *) arg; + event_descriptor->port->processEvent(event_descriptor->event); +} + +void IEEE1588Clock::addEventTimer(IEEE1588Port * target, Event e, + unsigned long long time_ns) +{ + event_descriptor_t *event_descriptor = new event_descriptor_t(); + event_descriptor->event = e; + event_descriptor->port = target; + timerq->addEvent((unsigned)time_ns / 1000, (int)e, timerq_handler, + event_descriptor, true, NULL); +} + +void IEEE1588Clock::deleteEventTimer(IEEE1588Port * target, Event event) +{ + timerq->cancelEvent((int)event, NULL); +} + +// Sync clock to argument time +void IEEE1588Clock::setMasterOffset(int64_t master_local_offset, + Timestamp local_time, + int32_t master_local_freq_offset, + int64_t local_system_offset, + Timestamp system_time, + int32_t local_system_freq_offset, + uint32_t nominal_clock_rate, + uint32_t local_clock) +{ + + if (ipc != NULL) + ipc->update(master_local_offset, local_system_offset, + master_local_freq_offset, local_system_freq_offset, + TIMESTAMP_TO_NS(local_time)); + return; +} + +void IEEE1588Clock::getGrandmasterIdentity(char *id) +{ + grandmaster_port_identity.getClockIdentityString(id); +} + +// Get current time from system clock +Timestamp IEEE1588Clock::getTime(void) +{ + return getSystemTime(); +} + +// Get timestamp from hardware +Timestamp IEEE1588Clock::getPreciseTime(void) +{ + return getSystemTime(); +} + +bool IEEE1588Clock::isBetterThan(PTPMessageAnnounce * msg) +{ + unsigned char this1[14]; + unsigned char that1[14]; + uint16_t tmp; + + this1[0] = priority1; + that1[0] = msg->getGrandmasterPriority1(); + + this1[1] = clock_quality.cq_class; + that1[1] = msg->getGrandmasterClockQuality()->cq_class; + + this1[2] = clock_quality.clockAccuracy; + that1[2] = msg->getGrandmasterClockQuality()->clockAccuracy; + + tmp = clock_quality.offsetScaledLogVariance; + tmp = PLAT_htons(tmp); + memcpy(this1 + 3, &tmp, sizeof(tmp)); + tmp = msg->getGrandmasterClockQuality()->offsetScaledLogVariance; + tmp = PLAT_htons(tmp); + memcpy(that1 + 3, &tmp, sizeof(tmp)); + + this1[5] = priority2; + that1[5] = msg->getGrandmasterPriority2(); + + clock_identity.getIdentityString((char *)this1 + 6); + //memcpy( this1+6, clock_identity, PTP_CLOCK_IDENTITY_LENGTH ); + msg->getGrandmasterIdentity((char *)that1 + 6); + +#if 0 + fprintf(stderr, "(Clk)Us: "); + for (int i = 0; i < 14; ++i) + fprintf(stderr, "%hhx ", this1[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "(Clk)Them: "); + for (int i = 0; i < 14; ++i) + fprintf(stderr, "%hhx ", that1[i]); + fprintf(stderr, "\n"); +#endif + + return (memcmp(this1, that1, 14) < 0) ? true : false; +} + +IEEE1588Clock::~IEEE1588Clock(void) +{ + // Unmap shared memory +} diff --git a/daemons/gptp/common/ieee1588port.cpp b/daemons/gptp/common/ieee1588port.cpp new file mode 100644 index 0000000..cf62fd2 --- /dev/null +++ b/daemons/gptp/common/ieee1588port.cpp @@ -0,0 +1,1031 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +LinkLayerAddress IEEE1588Port::other_multicast(OTHER_MULTICAST); +LinkLayerAddress IEEE1588Port::pdelay_multicast(PDELAY_MULTICAST); + +OSThreadExitCode openPortWrapper(void *arg) +{ + IEEE1588Port *port; + + port = (IEEE1588Port *) arg; + if (port->openPort() == NULL) + return osthread_ok; + else + return osthread_error; +} + +IEEE1588Port::~IEEE1588Port() +{ + delete port_ready_condition; + delete [] rate_offset_array; +} + +IEEE1588Port::IEEE1588Port(IEEE1588Clock * clock, uint16_t index, + bool forceSlave, HWTimestamper * timestamper, + bool syntonize, int32_t offset, + InterfaceLabel * net_label, + OSConditionFactory * condition_factory, + OSThreadFactory * thread_factory, + OSTimerFactory * timer_factory, + OSLockFactory * lock_factory) +{ + sync_sequence_id = 0; + last_pdelay_req = NULL; + + clock->registerPort(this, index); + this->clock = clock; + ifindex = index; + + this->forceSlave = forceSlave; + + asCapable = false; + + announce_sequence_id = 0; + sync_sequence_id = 0; + pdelay_sequence_id = 0; + + sync_sequence_id = 0; + + log_mean_sync_interval = -3; + log_mean_announce_interval = 0; + log_min_mean_pdelay_req_interval = 0; + + _current_clock_offset = _initial_clock_offset = offset; + + rate_offset_array = NULL; + + _hw_timestamper = timestamper; + + if (_hw_timestamper != NULL) { + if (!_hw_timestamper->HWTimestamper_init(net_label)) { + XPTPD_ERROR + ("Failed to initialize hardware timestamper, falling back to software timestamping"); + _hw_timestamper = NULL; + } + } + + _syntonize = syntonize; + _master_local_freq_offset_init = false; + _local_system_freq_offset_init = false; + + one_way_delay = 3600000000000; + + _peer_rate_offset = 0; + _master_rate_offset = 0; + + last_sync = NULL; + last_pdelay_req = NULL; + last_pdelay_resp = NULL; + last_pdelay_resp_fwup = NULL; + + this->net_label = net_label; + + this->timer_factory = timer_factory; + this->thread_factory = thread_factory; + + this->condition_factory = condition_factory; + this->lock_factory = lock_factory; +} + +bool IEEE1588Port::init_port() +{ + if (!OSNetworkInterfaceFactory::buildInterface + (&net_iface, factory_name_t("default"), net_label, _hw_timestamper)) + return false; + + this->net_iface = net_iface; + this->net_iface->getLinkLayerAddress(&local_addr); + clock->setClockIdentity(&local_addr); + + pdelay_rx_lock = lock_factory->createLock(oslock_recursive); + port_tx_lock = lock_factory->createLock(oslock_recursive); + + port_identity.setClockIdentity(clock->getClockIdentity()); + port_identity.setPortNumber(&ifindex); + + port_ready_condition = condition_factory->createCondition(); + + return true; +} + +void *IEEE1588Port::openPort(void) +{ + fprintf(stderr, "openPort: thread started\n"); + + port_ready_condition->signal(); + + while (1) { + PTPMessageCommon *msg; + uint8_t buf[128]; + LinkLayerAddress remote; + net_result rrecv; + size_t length = sizeof(buf); + + if ((rrecv = net_iface->recv(&remote, buf, length)) == net_succeed) { + XPTPD_INFO("Processing network buffer"); + msg = buildPTPMessage((char *)buf, (int)length, &remote, + this); + if (msg != NULL) { + XPTPD_INFO("Processing message"); + msg->processMessage(this); + if (msg->garbage()) { + delete msg; + } + } else { + XPTPD_ERROR("Discarding invalid message"); + } + } else if (rrecv == net_fatal) { + XPTPD_ERROR("read from network interface failed"); + this->processEvent(FAULT_DETECTED); + break; + } + } + + return NULL; +} + +net_result IEEE1588Port::port_send(uint8_t * buf, int size, + MulticastType mcast_type, + PortIdentity * destIdentity, bool timestamp) +{ + LinkLayerAddress dest; + + if (mcast_type != MCAST_NONE) { + if (mcast_type == MCAST_PDELAY) { + dest = pdelay_multicast; + } else { + dest = other_multicast; + } + } else { + mapSocketAddr(destIdentity, &dest); + } + + return net_iface->send(&dest, (uint8_t *) buf, size, timestamp); +} + +unsigned IEEE1588Port::getPayloadOffset() +{ + return net_iface->getPayloadOffset(); +} + +void IEEE1588Port::sendEventPort(uint8_t * buf, int size, + MulticastType mcast_type, + PortIdentity * destIdentity) +{ + net_result rtx = port_send(buf, size, mcast_type, destIdentity, true); + if (rtx != net_succeed) { + XPTPD_ERROR("sendEventPort(): failure"); + } + + return; +} + +void IEEE1588Port::sendGeneralPort(uint8_t * buf, int size, + MulticastType mcast_type, + PortIdentity * destIdentity) +{ + net_result rtx = port_send(buf, size, mcast_type, destIdentity, false); + if (rtx != net_succeed) { + XPTPD_ERROR("sendEventPort(): failure"); + } + + return; +} + +void IEEE1588Port::processEvent(Event e) +{ + bool changed_master; + OSTimer *timer = timer_factory->createTimer(); + + switch (e) { + case POWERUP: + case INITIALIZE: + XPTPD_INFO("Received POWERUP/INITIALIZE event"); + { + unsigned long long interval1; + unsigned long long interval3; + unsigned long long interval4; + Event e1 = NULL_EVENT; + Event e3 = NULL_EVENT; + Event e4 = NULL_EVENT; + + if (forceSlave) { + port_state = PTP_SLAVE; + e1 = PDELAY_INTERVAL_TIMEOUT_EXPIRES; + interval1 = + (unsigned long + long)(pow((double)2, + getPDelayInterval()) * + 1000000000.0); + } else { + port_state = PTP_LISTENING; + e1 = PDELAY_INTERVAL_TIMEOUT_EXPIRES; + e3 = SYNC_RECEIPT_TIMEOUT_EXPIRES; + e4 = ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES; + interval1 = + (unsigned long + long)(pow((double)2, + getPDelayInterval()) * + 1000000000.0); + interval3 = + (unsigned long + long)(SYNC_RECEIPT_TIMEOUT_MULTIPLIER * + pow((double)2, + getSyncInterval()) * + 1000000000.0); + interval4 = + (unsigned long + long)(ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * + pow((double)2, + getAnnounceInterval()) * + 1000000000.0); + } + + fprintf(stderr, "Starting port thread\n"); + port_ready_condition->wait_prelock(); + listening_thread = thread_factory->createThread(); + if (!listening_thread->start + (openPortWrapper, (void *)this)) { + XPTPD_ERROR("Error creating port thread\n"); + return; + } + port_ready_condition->wait(); + + if (e1 != NULL_EVENT) + clock->addEventTimer(this, e1, interval1); + if (e3 != NULL_EVENT) + clock->addEventTimer(this, e3, interval3); + if (e4 != NULL_EVENT) + clock->addEventTimer(this, e4, interval4); + } + break; + case STATE_CHANGE_EVENT: + if (!forceSlave) { + int number_ports, j; + PTPMessageAnnounce *EBest = NULL; + PortIdentity EBestPortIdentity; + + IEEE1588Port **ports; + clock->getPortList(number_ports, ports); + // If ANY ports are in PTP_INTIALIZING state, STATE_CHANGE_EVENT cannot be processed +#if 0 + for (int i = 0; i < number_ports; ++i) { + if (ports[i]->port_state == PTP_INITIALIZING) { + break; + } + } +#endif + //fprintf( stderr, "State Change Event\n" ); + + // Find EBest for all ports + j = 0; + for (int i = 0; i < number_ports; ++i) { + while (ports[j] == NULL) + ++j; + if (ports[j]->port_state == PTP_DISABLED + || ports[j]->port_state == PTP_FAULTY) { + continue; + } + if (EBest == NULL) { + EBest = ports[j]->calculateERBest(); + } else { + if (ports[j]->calculateERBest()->isBetterThan(EBest)) { + EBest = ports[j]->calculateERBest(); + } + } + } + + // Check if we've changed + EBest->getPortIdentity( &EBestPortIdentity ); + if( EBestPortIdentity.getClockIdentity() != clock->getLastEBestIdentity() ) { + fprintf( stderr, "Changed master!\n" ); + changed_master = true; + } else { + changed_master = false; + } + + j = 0; + for (int i = 0; i < number_ports; ++i) { + while (ports[j] == NULL) + ++j; + if (ports[j]->port_state == PTP_DISABLED + || ports[j]->port_state == PTP_FAULTY) { + continue; + } + if (clock->isBetterThan(EBest)) { + // We are the GrandMaster, all ports are master + fprintf(stderr, "\n"); + EBest = NULL; // EBest == NULL : we were grandmaster + ports[j]->recommendState(PTP_MASTER, + changed_master); + } else { + if (EBest == calculateERBest()) { + // The "best" sync was recieved on this port + ports[j]->recommendState + (PTP_SLAVE, changed_master); + } else { + // Otherwise we are the master because we have sync'd to a better clock + ports[j]->recommendState + (PTP_MASTER, + changed_master); + } + } + } + clock->setLastEBestIdentity( EBestPortIdentity.getClockIdentity() ); + } + break; + case ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + case SYNC_RECEIPT_TIMEOUT_EXPIRES: + { + if (forceSlave) { + break; + } + if (port_state == PTP_LISTENING + || port_state == PTP_UNCALIBRATED + || port_state == PTP_SLAVE + || port_state == PTP_PRE_MASTER) { + fprintf(stderr, + "***Sync Timeout Expired - Becoming Master: %d\n", + e); + port_state = PTP_MASTER; + Timestamp system_time; + Timestamp device_time; + int64_t local_system_offset; + +#if 0 + Timestamp crstamp_device_time; + int64_t external_local_offset; + int32_t external_local_freq_offset; +#endif + uint32_t local_clock, nominal_clock_rate; + + getDeviceTime(system_time, device_time, + local_clock, nominal_clock_rate); + + local_system_offset = + TIMESTAMP_TO_NS(system_time) - + TIMESTAMP_TO_NS(device_time); +#if 0 + local_system_offset = device_time.nanoseconds + + (((unsigned long long)device_time.seconds_ms + << sizeof(device_time.seconds_ls) * 8) + + device_time.seconds_ls) * 1000000000LL; + local_system_offset -= + system_time.nanoseconds + + (((unsigned long long)system_time.seconds_ms + << sizeof(system_time.seconds_ls) * 8) + + system_time.seconds_ls) * 1000000000LL; +#endif + + (void) + calcLocalSystemClockRateDifference + (local_system_offset, system_time); + + //getExternalClockRate( crstamp_device_time, external_local_offset, external_local_freq_offset ); + +#if 0 + clock->setMasterOffset(0, device_time, 0, + local_system_offset, + system_time, + local_system_freq_offset, + nominal_clock_rate, + local_clock); +#endif + if (this->doSyntonization()) { + this->adjustClockRate(0, local_clock, + device_time, 0, + false); + } + // "Expire" all previously received announce messages on this port + while (!qualified_announce.empty()) { + delete qualified_announce.back(); + qualified_announce.pop_back(); + } + + // Add timers for Announce and Sync, this is as close to immediately as we get + clock->addEventTimer(this, + ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES, + 8000000); + clock->addEventTimer(this, + SYNC_INTERVAL_TIMEOUT_EXPIRES, + 8000000); + } + break; + case PDELAY_INTERVAL_TIMEOUT_EXPIRES: + XPTPD_INFO("PDELAY_INTERVAL_TIMEOUT_EXPIRES occured"); + { + int ts_good; + int iter = 2; + Timestamp req_timestamp; + long req = 1000; // = 1 ms + unsigned req_timestamp_counter_value; + + PTPMessagePathDelayReq *pdelay_req = + new PTPMessagePathDelayReq(this); + PortIdentity dest_id; + getPortIdentity(dest_id); + pdelay_req->setPortIdentity(&dest_id); + + { + Timestamp pending = + PDELAY_PENDING_TIMESTAMP; + pdelay_req->setTimestamp(pending); + } + + if (last_pdelay_req != NULL) { + delete last_pdelay_req; + } + setLastPDelayReq(pdelay_req); + + XPTPD_INFO("Preparing to send PDelay Request"); + getTxLock(); + pdelay_req->sendPort(this, NULL); + XPTPD_INFO("Sent PDelay Request"); + + ts_good = + getTxTimestamp(pdelay_req, req_timestamp, + req_timestamp_counter_value, + false); + while (ts_good != 0 && iter-- != 0) { + timer->sleep(req); + if (ts_good != -72 && iter < 1) + fprintf(stderr, + "Error (TX) timestamping PDelay request (Retrying-%d), error=%d\n", + iter, ts_good); + ts_good = + getTxTimestamp(pdelay_req, + req_timestamp, + req_timestamp_counter_value, + iter == 0); + req *= 2; + } + putTxLock(); + + //fprintf( stderr, "Sequence = %hu\n", pdelay_req->getSequenceId() ); + + if (pdelay_req == NULL) { + fprintf(stderr, + "PDelay request is NULL!\n"); + abort(); + } + + if (ts_good == 0) { + pdelay_req->setTimestamp(req_timestamp); + } else { + Timestamp failed = INVALID_TIMESTAMP; + pdelay_req->setTimestamp(failed); + } + + if (ts_good != 0) { + char msg + [HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE]; + getExtendedError(msg); + fprintf(stderr, + "Error (TX) timestamping PDelay request, error=%d\n%s", + ts_good, msg); + //_exit(-1); + } +#ifdef DEBUG + if (ts_good == 0) { + XPTPD_INFO + ("Successful PDelay Req timestamp, %u,%u", + req_timestamp.seconds_ls, + req_timestamp.nanoseconds); + } else { + XPTPD_INFO + ("*** Unsuccessful PDelay Req timestamp"); + } +#endif + + } + clock->addEventTimer(this, + PDELAY_INTERVAL_TIMEOUT_EXPIRES, + (unsigned long + long)(pow((double)2, + getPDelayInterval()) * + 1000000000.0)); + break; + case SYNC_INTERVAL_TIMEOUT_EXPIRES: + XPTPD_INFO("SYNC_INTERVAL_TIMEOUT_EXPIRES occured"); + // Set offset from master to zero, update device vs system time offset + Timestamp system_time; + Timestamp device_time; + int32_t local_system_freq_offset; + int64_t local_system_offset; + static bool adj_up = true; + +#if 0 + Timestamp crstamp_device_time; + int64_t external_local_offset; + int32_t external_local_freq_offset; +#endif + uint32_t local_clock, nominal_clock_rate; + + getDeviceTime(system_time, device_time, local_clock, + nominal_clock_rate); + //fprintf( stderr, "Device Time = %llu,System Time = %llu\n", TIMESTAMP_TO_NS(device_time), TIMESTAMP_TO_NS(system_time)); + + XPTPD_INFO + ("port::processEvent(): System time: %u,%u Device Time: %u,%u", + system_time.seconds_ls, system_time.nanoseconds, + device_time.seconds_ls, device_time.nanoseconds); + + local_system_offset = + TIMESTAMP_TO_NS(system_time) - + TIMESTAMP_TO_NS(device_time); +#if 0 + local_system_offset = device_time.nanoseconds + + (((unsigned long long)device_time.seconds_ms << + sizeof(device_time.seconds_ls) * 8) + + device_time.seconds_ls) * 1000000000LL; + local_system_offset -= + system_time.nanoseconds + + (((unsigned long long)system_time.seconds_ms << + sizeof(system_time.seconds_ls) * 8) + + system_time.seconds_ls) * 1000000000LL; +#endif + + local_system_freq_offset = + calcLocalSystemClockRateDifference + (local_system_offset, system_time); + + //getExternalClockRate( crstamp_device_time, external_local_offset, external_local_freq_offset ); + + clock->setMasterOffset(0, device_time, 0, + local_system_offset, system_time, + local_system_freq_offset, + nominal_clock_rate, local_clock); + if (this->doSyntonization()) { + this->adjustClockRate(0, local_clock, + device_time, 0, false); + } + + if (_hw_timestamper != NULL + && _initial_clock_offset != 0) { + if (adj_up) { + _hw_timestamper->HWTimestamper_adjclockrate2 + (_current_clock_offset += 2500); + } else { + _hw_timestamper->HWTimestamper_adjclockrate2 + (_current_clock_offset -= 2500); + } + XPTPD_INFO("Adjust clock rate current: %d", + _current_clock_offset); + } + if (_current_clock_offset > + _initial_clock_offset + 5000000 + || _current_clock_offset < + _initial_clock_offset - 5000000) { + adj_up = !adj_up; + } + // Send a sync message and then a followup to broadcast + if (asCapable) { + PTPMessageSync *sync = new PTPMessageSync(this); + PortIdentity dest_id; + getPortIdentity(dest_id); + sync->setPortIdentity(&dest_id); + getTxLock(); + sync->sendPort(this, NULL); + XPTPD_INFO("Sent SYNC message"); + + int ts_good; + int iter = 2; + Timestamp sync_timestamp; + unsigned sync_timestamp_counter_value; + long req = 1000; // = 1 ms + XPTPD_INFO("Start TS Read"); + ts_good = + getTxTimestamp(sync, sync_timestamp, + sync_timestamp_counter_value, + false); + XPTPD_INFO("Done TS Read"); + while (ts_good != 0 && iter-- != 0) { + timer->sleep(req); + if (ts_good != -72 && iter < 1) + fprintf(stderr, + "Error (TX) timestamping Sync (Retrying), error=%d\n", + ts_good); + ts_good = + getTxTimestamp(sync, sync_timestamp, + sync_timestamp_counter_value, + iter == 0); + req *= 2; + } + putTxLock(); + + if (ts_good != 0) { + char msg + [HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE]; + getExtendedError(msg); + fprintf(stderr, + "Error (TX) timestamping Sync, error=%d\n%s", + ts_good, msg); + //_exit(-1); + } + + if (ts_good == 0) { + XPTPD_INFO("Successful Sync timestamp"); + XPTPD_INFO("Seconds: %u", + sync_timestamp.seconds_ls); + XPTPD_INFO("Nanoseconds: %u", + sync_timestamp.nanoseconds); + } else { + XPTPD_INFO + ("*** Unsuccessful Sync timestamp"); + } + + PTPMessageFollowUp *follow_up; + if (ts_good == 0) { + follow_up = + new PTPMessageFollowUp(this); + PortIdentity dest_id; + getPortIdentity(dest_id); + follow_up->setPortIdentity(&dest_id); + follow_up->setSequenceId(sync->getSequenceId()); + follow_up->setPreciseOriginTimestamp(sync_timestamp); + follow_up->sendPort(this, NULL); + delete follow_up; + } else { + // Re-add the timer, since we failed re-send sooner? + //clock->addEventTimer( this, SYNC_INTERVAL_TIMEOUT_EXPIRES, (unsigned long long) (pow(2,getSyncInterval())*1000000000.0)); + } + delete sync; + } + } + clock->addEventTimer(this, SYNC_INTERVAL_TIMEOUT_EXPIRES, + (unsigned long + long)(pow((double)2, + getSyncInterval()) * + 1000000000.0)); + break; + case ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES: + if (asCapable) { + // Send an announce message + PTPMessageAnnounce *annc = new PTPMessageAnnounce(this); + PortIdentity dest_id; + PortIdentity gmId; + ClockIdentity clock_id = clock->getClockIdentity(); + gmId.setClockIdentity(clock_id); + clock->setGrandmasterPortIdentity(gmId); + getPortIdentity(dest_id); + annc->setPortIdentity(&dest_id); + annc->sendPort(this, NULL); + delete annc; + } + clock->addEventTimer(this, ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES, + (unsigned)(pow + ((double)2, + getAnnounceInterval()) * + 1000000000.0)); + break; + case FAULT_DETECTED: + XPTPD_INFO("Received FAULT_DETECTED event"); + break; + case PDELAY_DEFERRED_PROCESSING: + pdelay_rx_lock->lock(); + if (last_pdelay_resp_fwup == NULL) { + fprintf(stderr, "PDelay Response Followup is NULL!\n"); + abort(); + } + last_pdelay_resp_fwup->processMessage(this); + if (last_pdelay_resp_fwup->garbage()) { + delete last_pdelay_resp_fwup; + this->setLastPDelayRespFollowUp(NULL); + } + pdelay_rx_lock->unlock(); + break; + case PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES: + setAsCapable(false); + break; + default: + XPTPD_INFO + ("Unhandled event type in IEEE1588Port::processEvent(), %d", + e); + break; + } + return; +} + +PTPMessageAnnounce *IEEE1588Port::calculateERBest(void) +{ + if (qualified_announce.empty()) { + return NULL; + } + if (qualified_announce.size() == 1) { + return qualified_announce.front(); + } + + AnnounceList_t::iterator iter_l = qualified_announce.begin(); + PTPMessageAnnounce *best = *iter_l; + ++iter_l; + while (iter_l != qualified_announce.end()) { + if ((*iter_l)->isBetterThan(best)) + best = *iter_l; + iter_l = qualified_announce.erase(iter_l); + } + + return best; +} + +void IEEE1588Port::recoverPort(void) +{ + return; +} + +IEEE1588Clock *IEEE1588Port::getClock(void) +{ + return clock; +} + +void IEEE1588Port::getDeviceTime(Timestamp & system_time, + Timestamp & device_time, + uint32_t & local_clock, + uint32_t & nominal_clock_rate) +{ + if (_hw_timestamper) { + _hw_timestamper->HWTimestamper_gettime(&system_time, + &device_time, + &local_clock, + &nominal_clock_rate); + } else { + device_time = system_time = clock->getSystemTime(); + local_clock = nominal_clock_rate = 0; + } + return; +} + +void IEEE1588Port::recommendState(PortState state, bool changed_master) +{ + switch (state) { + case PTP_MASTER: + if (port_state != PTP_MASTER) { + port_state = PTP_MASTER; + // Start announce receipt timeout timer + // Start sync receipt timeout timer + clock->addEventTimer(this, + ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES, + 8000000); + clock->addEventTimer(this, + SYNC_INTERVAL_TIMEOUT_EXPIRES, + 8000000); + fprintf(stderr, "Switching to Master\n"); + } else { + port_state = PTP_MASTER; + } + break; + case PTP_SLAVE: + // Stop sending announce messages + // Stop sending sync messages + if (port_state != PTP_SLAVE) { + port_state = PTP_SLAVE; + clock->deleteEventTimer(this, + ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES); + clock->deleteEventTimer(this, + SYNC_INTERVAL_TIMEOUT_EXPIRES); + clock->addEventTimer(this, SYNC_RECEIPT_TIMEOUT_EXPIRES, + (SYNC_RECEIPT_TIMEOUT_MULTIPLIER * + (unsigned long + long)(pow((double)2, + getSyncInterval()) * + 1000000000.0))); + clock->addEventTimer(this, + ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES, + (ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER + * + (unsigned long + long)(pow((double)2, + getAnnounceInterval()) + * 1000000000.0))); + fprintf(stderr, "Switching to Slave\n"); + } else { + if (changed_master) { + port_state = PTP_SLAVE; + } else { + port_state = PTP_SLAVE; + } + } + break; + default: + XPTPD_INFO + ("Invalid state change requested by call to 1588Port::recommendState()"); + break; + } + return; +} + +#define FIR_SAMPLE_TIME 1 // Seconds + +int IEEE1588Port::calcMasterLocalClockRateDifference(signed long long offset, + Timestamp sync_time) +{ + long long inter_sync_time; + signed long long offset_delta; + int ppt_offset; + + XPTPD_INFO("Calculated master to local PTP clock rate difference"); + + if (!_master_local_freq_offset_init) { + _prev_sync_time = sync_time; + _prev_master_local_offset = offset; + + _master_local_freq_offset_init = true; + + return 0; + } + + inter_sync_time = + TIMESTAMP_TO_NS(sync_time) - TIMESTAMP_TO_NS(_prev_sync_time); + offset_delta = offset - _prev_master_local_offset; + + if (rate_offset_array == NULL) { + rate_offset_array_size = 4; + ++rate_offset_array_size; + rate_offset_array = new int32_t[rate_offset_array_size]; + rate_offset_count = 0; + rate_offset_index = 0; + } + //fprintf( stderr, "Calculated master to local PTP clock rate difference, offset=%lld,sync_time = %lld\n", offset_delta, inter_sync_time ); + + if (inter_sync_time != 0) { + //fprintf( stderr, "Offset Delta: %lld, IST: %llu(%llu,%llu)\n", offset_delta, inter_sync_time, TIMESTAMP_TO_NS(sync_time),TIMESTAMP_TO_NS(_prev_sync_time) ); + ppt_offset = + int (((offset_delta * 1000000000000LL) / inter_sync_time)); + } else { + ppt_offset = 0; + } + + _prev_sync_time = sync_time; + _prev_master_local_offset = offset; + + return ppt_offset; +} + +int IEEE1588Port::calcLocalSystemClockRateDifference(signed long long offset, + Timestamp system_time) +{ + unsigned long long inter_system_time; + signed long long offset_delta; + int ppt_offset; + + XPTPD_INFO("Calculated local to system clock rate difference"); + + if (!_local_system_freq_offset_init) { + _prev_system_time = system_time; + _prev_local_system_offset = offset; + + _local_system_freq_offset_init = true; + + return 0; + } + + inter_system_time = + TIMESTAMP_TO_NS(system_time) - TIMESTAMP_TO_NS(_prev_system_time); + offset_delta = offset - _prev_local_system_offset; + + if (inter_system_time != 0) { + ppt_offset = + int (((offset_delta * 1000000000000LL) / + (int64_t) inter_system_time)); + XPTPD_INFO + ("IEEE1588Port::calcLocalSystemClockRateDifference() offset delta: %Ld", + offset_delta); + } else { + ppt_offset = 0; + offset_delta = 0; + } + + if (inter_system_time != 0) { + XPTPD_INFO("Calculation Step: %Ld", + ((offset_delta * 1000000000000LL) / + (int64_t) inter_system_time)); + } + XPTPD_INFO + ("IEEE1588Port::calcLocalSystemClockRateDifference() offset: %Ld", + offset); + XPTPD_INFO + ("IEEE1588Port::calcLocalSystemClockRateDifference() prev offset: %ld", + _prev_local_system_offset); + XPTPD_INFO + ("IEEE1588Port::calcLocalSystemClockRateDifference() system time: %u,%u", + system_time.seconds_ls, system_time.nanoseconds); + XPTPD_INFO + ("IEEE1588Port::calcLocalSystemClockRateDifference() prev system time: %u,%u", + _prev_system_time.seconds_ls, _prev_system_time.nanoseconds); + XPTPD_INFO + ("IEEE1588Port::calcLocalSystemClockRateDifference() inter-system time: %Lu", + inter_system_time); + XPTPD_INFO("IEEE1588Port::calcLocalSystemClockRateDifference() PPT: %d", + ppt_offset); + + _prev_system_time = system_time; + _prev_local_system_offset = offset; + + return ppt_offset; +} + +void IEEE1588Port::mapSocketAddr(PortIdentity * destIdentity, + LinkLayerAddress * remote) +{ + *remote = identity_map[*destIdentity]; + return; +} + +void IEEE1588Port::addSockAddrMap(PortIdentity * destIdentity, + LinkLayerAddress * remote) +{ + identity_map[*destIdentity] = *remote; + return; +} + +int IEEE1588Port::getTxTimestamp(PTPMessageCommon * msg, Timestamp & timestamp, + unsigned &counter_value, bool last) +{ + PortIdentity identity; + msg->getPortIdentity(&identity); + return getTxTimestamp(&identity, msg->getSequenceId(), timestamp, + counter_value, last); +} + +int IEEE1588Port::getRxTimestamp(PTPMessageCommon * msg, Timestamp & timestamp, + unsigned &counter_value, bool last) +{ + PortIdentity identity; + msg->getPortIdentity(&identity); + return getRxTimestamp(&identity, msg->getSequenceId(), timestamp, + counter_value, last); +} + +int IEEE1588Port::getTxTimestamp(PortIdentity * sourcePortIdentity, + uint16_t sequenceId, Timestamp & timestamp, + unsigned &counter_value, bool last) +{ + if (_hw_timestamper) { + return + _hw_timestamper->HWTimestamper_txtimestamp + (sourcePortIdentity, sequenceId, timestamp, counter_value, + last); + } + timestamp = clock->getSystemTime(); + return true; +} + +int IEEE1588Port::getRxTimestamp(PortIdentity * sourcePortIdentity, + uint16_t sequenceId, Timestamp & timestamp, + unsigned &counter_value, bool last) +{ + if (_hw_timestamper) { + return + _hw_timestamper->HWTimestamper_rxtimestamp + (sourcePortIdentity, sequenceId, timestamp, counter_value, + last); + } + timestamp = clock->getSystemTime(); + return true; +} diff --git a/daemons/gptp/common/ptp_message.cpp b/daemons/gptp/common/ptp_message.cpp new file mode 100644 index 0000000..86ee0ce --- /dev/null +++ b/daemons/gptp/common/ptp_message.cpp @@ -0,0 +1,1718 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +PTPMessageCommon::PTPMessageCommon(IEEE1588Port * port) +{ + // Fill in fields using port/clock dataset as a template + versionPTP = GPTP_VERSION; + versionNetwork = PTP_NETWORK_VERSION; + domainNumber = port->getClock()->getDomain(); + // Set flags as necessary + memset(flags, 0, PTP_FLAGS_LENGTH); + correctionField = 0; + _gc = false; + sourcePortIdentity = new PortIdentity(); + + return; +} + +// Determine whether the message was sent by given communication technology, uuid, and port id fields +bool PTPMessageCommon::isSenderEqual(PortIdentity portIdentity) +{ + return portIdentity == *sourcePortIdentity; +} + +PTPMessageCommon *buildPTPMessage(char *buf, int size, + LinkLayerAddress * remote, + IEEE1588Port * port) +{ + OSTimer *timer = port->getTimerFactory()->createTimer(); + PTPMessageCommon *msg = NULL; + MessageType messageType; + unsigned char tspec_msg_t = 0; + + uint16_t sequenceId; + PortIdentity *sourcePortIdentity; + Timestamp timestamp(0, 0, 0); + unsigned counter_value = 0; + +#if PTP_DEBUG + { + int i; + XPTPD_INFO("Packet Dump:\n"); + for (i = 0; i < size; ++i) { + fprintf(stderr, "%hhx\t", buf[i]); + if (i % 8 == 7) + fprintf(stderr, "\n"); + } + if (i % 8 != 0) + fprintf(stderr, "\n"); + } +#endif + + memcpy(&tspec_msg_t, + buf + PTP_COMMON_HDR_TRANSSPEC_MSGTYPE(PTP_COMMON_HDR_OFFSET), + sizeof(tspec_msg_t)); + messageType = (MessageType) (tspec_msg_t & 0xF); + + sourcePortIdentity = new PortIdentity((uint8_t *) (buf + + PTP_COMMON_HDR_SOURCE_CLOCK_ID + (PTP_COMMON_HDR_OFFSET)), + (uint16_t *) (buf + + PTP_COMMON_HDR_SOURCE_PORT_ID + (PTP_COMMON_HDR_OFFSET))); + + memcpy(&(sequenceId), + buf + PTP_COMMON_HDR_SEQUENCE_ID(PTP_COMMON_HDR_OFFSET), + sizeof(sequenceId)); + sequenceId = PLAT_ntohs(sequenceId); + + //fprintf( stderr, "Captured Sequence Id: %u\n", sequenceId ); + XPTPD_INFO("Captured Sequence Id: %u", sequenceId); + + if (!(messageType >> 3)) { + int iter = 2; + long req = 1000; // = 1 ms + int ts_good = + port->getRxTimestamp(sourcePortIdentity, sequenceId, + timestamp, counter_value, false); + while (ts_good != 0 && iter-- != 0) { + // Waits at least 1 time slice regardless of size of 'req' + timer->sleep(req); + if (ts_good != 72) + fprintf(stderr, + "Error (RX) timestamping RX event packet (Retrying), error=%d\n", + ts_good); + ts_good = + port->getRxTimestamp(sourcePortIdentity, sequenceId, + timestamp, counter_value, + iter == 0); + req *= 2; + } + if (ts_good != 0) { + char msg[HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE]; + port->getExtendedError(msg); + XPTPD_ERROR + ("*** Received an event packet but cannot retrieve timestamp, discarding. messageType=%u,error=%d\n%s", + messageType, ts_good, msg); + //_exit(-1); + return NULL; + } + + else { + XPTPD_INFO("Timestamping event packet"); + } + + } + + switch (messageType) { + case SYNC_MESSAGE: + + //fprintf( stderr, "*** Received Sync message\n" ); + //printf( "Sync RX timestamp = %hu,%u,%u\n", timestamp.seconds_ms, timestamp.seconds_ls, timestamp.nanoseconds ); + XPTPD_INFO("*** Received Sync message"); + + // Be sure buffer is the correction size + if (size < PTP_COMMON_HDR_LENGTH + PTP_SYNC_LENGTH) { + goto done; + } + { + PTPMessageSync *sync_msg = new PTPMessageSync(); + sync_msg->messageType = messageType; + // Copy in v2 sync specific fields + memcpy(&(sync_msg->originTimestamp.seconds_ms), + buf + PTP_SYNC_SEC_MS(PTP_SYNC_OFFSET), + sizeof(sync_msg->originTimestamp.seconds_ms)); + memcpy(&(sync_msg->originTimestamp.seconds_ls), + buf + PTP_SYNC_SEC_LS(PTP_SYNC_OFFSET), + sizeof(sync_msg->originTimestamp.seconds_ls)); + memcpy(&(sync_msg->originTimestamp.nanoseconds), + buf + PTP_SYNC_NSEC(PTP_SYNC_OFFSET), + sizeof(sync_msg->originTimestamp.nanoseconds)); + msg = sync_msg; + } + break; + case FOLLOWUP_MESSAGE: + + XPTPD_INFO("*** Received Follow Up message"); + + // Be sure buffer is the correction size + if (size < PTP_COMMON_HDR_LENGTH + PTP_FOLLOWUP_LENGTH) { + goto done; + } + { + PTPMessageFollowUp *followup_msg = + new PTPMessageFollowUp(); + followup_msg->messageType = messageType; + // Copy in v2 sync specific fields + memcpy(& + (followup_msg-> + preciseOriginTimestamp.seconds_ms), + buf + PTP_FOLLOWUP_SEC_MS(PTP_FOLLOWUP_OFFSET), + sizeof(followup_msg-> + preciseOriginTimestamp.seconds_ms)); + memcpy(& + (followup_msg-> + preciseOriginTimestamp.seconds_ls), + buf + PTP_FOLLOWUP_SEC_LS(PTP_FOLLOWUP_OFFSET), + sizeof(followup_msg-> + preciseOriginTimestamp.seconds_ls)); + memcpy(& + (followup_msg-> + preciseOriginTimestamp.nanoseconds), + buf + PTP_FOLLOWUP_NSEC(PTP_FOLLOWUP_OFFSET), + sizeof(followup_msg-> + preciseOriginTimestamp.nanoseconds)); + + followup_msg->preciseOriginTimestamp.seconds_ms = + PLAT_ntohs(followup_msg-> + preciseOriginTimestamp.seconds_ms); + followup_msg->preciseOriginTimestamp.seconds_ls = + PLAT_ntohl(followup_msg-> + preciseOriginTimestamp.seconds_ls); + followup_msg->preciseOriginTimestamp.nanoseconds = + PLAT_ntohl(followup_msg-> + preciseOriginTimestamp.nanoseconds); + + msg = followup_msg; + } + break; + case PATH_DELAY_REQ_MESSAGE: + + XPTPD_INFO("*** Received PDelay Request message"); + + // Be sure buffer is the correction size + if (size < PTP_COMMON_HDR_LENGTH + PTP_PDELAY_REQ_LENGTH + && /* For Broadcom compatibility */ size != 46) { + goto done; + } + { + PTPMessagePathDelayReq *pdelay_req_msg = + new PTPMessagePathDelayReq(); + pdelay_req_msg->messageType = messageType; + +#if 0 + // The origin timestamp for PDelay Request packets has been eliminated since it is unused + // Copy in v2 PDelay Request specific fields + memcpy(&(pdelay_req_msg->originTimestamp.seconds_ms), + buf + + PTP_PDELAY_REQ_SEC_MS(PTP_PDELAY_REQ_OFFSET), + sizeof(pdelay_req_msg-> + originTimestamp.seconds_ms)); + memcpy(&(pdelay_req_msg->originTimestamp.seconds_ls), + buf + + PTP_PDELAY_REQ_SEC_LS(PTP_PDELAY_REQ_OFFSET), + sizeof(pdelay_req_msg-> + originTimestamp.seconds_ls)); + memcpy(&(pdelay_req_msg->originTimestamp.nanoseconds), + buf + PTP_PDELAY_REQ_NSEC(PTP_PDELAY_REQ_OFFSET), + sizeof(pdelay_req_msg-> + originTimestamp.nanoseconds)); + + pdelay_req_msg->originTimestamp.seconds_ms = + PLAT_ntohs(pdelay_req_msg-> + originTimestamp.seconds_ms); + pdelay_req_msg->originTimestamp.seconds_ls = + PLAT_ntohl(pdelay_req_msg-> + originTimestamp.seconds_ls); + pdelay_req_msg->originTimestamp.nanoseconds = + PLAT_ntohl(pdelay_req_msg-> + originTimestamp.nanoseconds); +#endif + + msg = pdelay_req_msg; + } + break; + case PATH_DELAY_RESP_MESSAGE: + + XPTPD_INFO("*** Received PDelay Response message, %u, %u, %u", + timestamp.seconds_ls, timestamp.nanoseconds, + sequenceId); + + // Be sure buffer is the correction size + if (size < PTP_COMMON_HDR_LENGTH + PTP_PDELAY_RESP_LENGTH) { + goto done; + } + { + PTPMessagePathDelayResp *pdelay_resp_msg = + new PTPMessagePathDelayResp(); + pdelay_resp_msg->messageType = messageType; + // Copy in v2 PDelay Response specific fields + pdelay_resp_msg->requestingPortIdentity = + new PortIdentity((uint8_t *) buf + + PTP_PDELAY_RESP_REQ_CLOCK_ID + (PTP_PDELAY_RESP_OFFSET), + (uint16_t *) (buf + + PTP_PDELAY_RESP_REQ_PORT_ID + (PTP_PDELAY_RESP_OFFSET))); + +#ifdef DEBUG + for (int n = 0; n < PTP_CLOCK_IDENTITY_LENGTH; ++n) { // MMM + fprintf(stderr, "%c", + pdelay_resp_msg-> + requestingPortIdentity.clockIdentity + [n]); + } +#endif + + memcpy(& + (pdelay_resp_msg-> + requestReceiptTimestamp.seconds_ms), + buf + + PTP_PDELAY_RESP_SEC_MS(PTP_PDELAY_RESP_OFFSET), + sizeof(pdelay_resp_msg-> + requestReceiptTimestamp.seconds_ms)); + memcpy(& + (pdelay_resp_msg-> + requestReceiptTimestamp.seconds_ls), + buf + + PTP_PDELAY_RESP_SEC_LS(PTP_PDELAY_RESP_OFFSET), + sizeof(pdelay_resp_msg-> + requestReceiptTimestamp.seconds_ls)); + memcpy(& + (pdelay_resp_msg-> + requestReceiptTimestamp.nanoseconds), + buf + + PTP_PDELAY_RESP_NSEC(PTP_PDELAY_RESP_OFFSET), + sizeof(pdelay_resp_msg-> + requestReceiptTimestamp.nanoseconds)); + + pdelay_resp_msg->requestReceiptTimestamp.seconds_ms = + PLAT_ntohs(pdelay_resp_msg->requestReceiptTimestamp.seconds_ms); + pdelay_resp_msg->requestReceiptTimestamp.seconds_ls = + PLAT_ntohl(pdelay_resp_msg->requestReceiptTimestamp.seconds_ls); + pdelay_resp_msg->requestReceiptTimestamp.nanoseconds = + PLAT_ntohl(pdelay_resp_msg->requestReceiptTimestamp.nanoseconds); + + msg = pdelay_resp_msg; + } + break; + case PATH_DELAY_FOLLOWUP_MESSAGE: + + XPTPD_INFO("*** Received PDelay Response FollowUp message"); + + // Be sure buffer is the correction size +// if( size < PTP_COMMON_HDR_LENGTH + PTP_PDELAY_FOLLOWUP_LENGTH ) { +// goto done; +// } + { + PTPMessagePathDelayRespFollowUp *pdelay_resp_fwup_msg = + new PTPMessagePathDelayRespFollowUp(); + pdelay_resp_fwup_msg->messageType = messageType; + // Copy in v2 PDelay Response specific fields + pdelay_resp_fwup_msg->requestingPortIdentity = + new PortIdentity((uint8_t *) buf + + PTP_PDELAY_FOLLOWUP_REQ_CLOCK_ID + (PTP_PDELAY_RESP_OFFSET), + (uint16_t *) (buf + + PTP_PDELAY_FOLLOWUP_REQ_PORT_ID + (PTP_PDELAY_FOLLOWUP_OFFSET))); + + memcpy(& + (pdelay_resp_fwup_msg-> + responseOriginTimestamp.seconds_ms), + buf + + PTP_PDELAY_FOLLOWUP_SEC_MS + (PTP_PDELAY_FOLLOWUP_OFFSET), + sizeof + (pdelay_resp_fwup_msg->responseOriginTimestamp. + seconds_ms)); + memcpy(& + (pdelay_resp_fwup_msg-> + responseOriginTimestamp.seconds_ls), + buf + + PTP_PDELAY_FOLLOWUP_SEC_LS + (PTP_PDELAY_FOLLOWUP_OFFSET), + sizeof + (pdelay_resp_fwup_msg->responseOriginTimestamp. + seconds_ls)); + memcpy(& + (pdelay_resp_fwup_msg-> + responseOriginTimestamp.nanoseconds), + buf + + PTP_PDELAY_FOLLOWUP_NSEC + (PTP_PDELAY_FOLLOWUP_OFFSET), + sizeof + (pdelay_resp_fwup_msg->responseOriginTimestamp. + nanoseconds)); + + pdelay_resp_fwup_msg-> + responseOriginTimestamp.seconds_ms = + PLAT_ntohs + (pdelay_resp_fwup_msg->responseOriginTimestamp. + seconds_ms); + pdelay_resp_fwup_msg-> + responseOriginTimestamp.seconds_ls = + PLAT_ntohl + (pdelay_resp_fwup_msg->responseOriginTimestamp. + seconds_ls); + pdelay_resp_fwup_msg-> + responseOriginTimestamp.nanoseconds = + PLAT_ntohl + (pdelay_resp_fwup_msg->responseOriginTimestamp. + nanoseconds); + + msg = pdelay_resp_fwup_msg; + } + break; + case ANNOUNCE_MESSAGE: + { + PTPMessageAnnounce *annc = new PTPMessageAnnounce(); + annc->messageType = messageType; + + memcpy(&(annc->currentUtcOffset), + buf + + PTP_ANNOUNCE_CURRENT_UTC_OFFSET + (PTP_ANNOUNCE_OFFSET), + sizeof(annc->currentUtcOffset)); + annc->currentUtcOffset = + PLAT_ntohs(annc->currentUtcOffset); + memcpy(&(annc->grandmasterPriority1), + buf + + PTP_ANNOUNCE_GRANDMASTER_PRIORITY1 + (PTP_ANNOUNCE_OFFSET), + sizeof(annc->grandmasterPriority1)); + memcpy(annc->clockQuality, + buf + + PTP_ANNOUNCE_GRANDMASTER_CLOCK_QUALITY + (PTP_ANNOUNCE_OFFSET), + sizeof(annc->clockQuality)); + annc->clockQuality->offsetScaledLogVariance = + PLAT_ntohs(annc-> + clockQuality->offsetScaledLogVariance); + memcpy(&(annc->grandmasterPriority2), + buf + + PTP_ANNOUNCE_GRANDMASTER_PRIORITY2 + (PTP_ANNOUNCE_OFFSET), + sizeof(annc->grandmasterPriority2)); + memcpy(&(annc->grandmasterIdentity), + buf + + PTP_ANNOUNCE_GRANDMASTER_IDENTITY + (PTP_ANNOUNCE_OFFSET), + PTP_CLOCK_IDENTITY_LENGTH); + memcpy(&(annc->stepsRemoved), + buf + + PTP_ANNOUNCE_STEPS_REMOVED(PTP_ANNOUNCE_OFFSET), + sizeof(annc->stepsRemoved)); + annc->stepsRemoved = PLAT_ntohs(annc->stepsRemoved); + memcpy(&(annc->timeSource), + buf + + PTP_ANNOUNCE_TIME_SOURCE(PTP_ANNOUNCE_OFFSET), + sizeof(annc->timeSource)); + + msg = annc; + } + break; + default: + + XPTPD_ERROR("Received unsupported message type, %d", + (int)messageType); + + goto done; + } + + msg->_gc = false; + + // Copy in common header fields + memcpy(&(msg->versionPTP), + buf + PTP_COMMON_HDR_PTP_VERSION(PTP_COMMON_HDR_OFFSET), + sizeof(msg->versionPTP)); + memcpy(&(msg->messageLength), + buf + PTP_COMMON_HDR_MSG_LENGTH(PTP_COMMON_HDR_OFFSET), + sizeof(msg->messageLength)); + msg->messageLength = PLAT_ntohs(msg->messageLength); + memcpy(&(msg->domainNumber), + buf + PTP_COMMON_HDR_DOMAIN_NUMBER(PTP_COMMON_HDR_OFFSET), + sizeof(msg->domainNumber)); + memcpy(&(msg->flags), buf + PTP_COMMON_HDR_FLAGS(PTP_COMMON_HDR_OFFSET), + PTP_FLAGS_LENGTH); + memcpy(&(msg->correctionField), + buf + PTP_COMMON_HDR_CORRECTION(PTP_COMMON_HDR_OFFSET), + sizeof(msg->correctionField)); + msg->correctionField = bswap_64(msg->correctionField); // Assume LE machine + msg->sourcePortIdentity = sourcePortIdentity; + msg->sequenceId = sequenceId; + memcpy(&(msg->control), + buf + PTP_COMMON_HDR_CONTROL(PTP_COMMON_HDR_OFFSET), + sizeof(msg->control)); + memcpy(&(msg->logMeanMessageInterval), + buf + PTP_COMMON_HDR_LOG_MSG_INTRVL(PTP_COMMON_HDR_OFFSET), + sizeof(msg->logMeanMessageInterval)); + + port->addSockAddrMap(msg->sourcePortIdentity, remote); + + msg->_timestamp = timestamp; + msg->_timestamp_counter_value = counter_value; + + done: + return msg; +} + +void PTPMessageCommon::processMessage(IEEE1588Port * port) +{ + _gc = true; + return; +} + +void PTPMessageCommon::buildCommonHeader(uint8_t * buf) +{ + unsigned char tspec_msg_t; + tspec_msg_t = messageType | 0x10; + //tspec_msg_t = messageType; + long long correctionField_BE = bswap_64(correctionField); // Assume LE machine + uint16_t messageLength_NO = PLAT_htons(messageLength); + + memcpy(buf + PTP_COMMON_HDR_TRANSSPEC_MSGTYPE(PTP_COMMON_HDR_OFFSET), + &tspec_msg_t, sizeof(tspec_msg_t)); + memcpy(buf + PTP_COMMON_HDR_PTP_VERSION(PTP_COMMON_HDR_OFFSET), + &versionPTP, sizeof(versionPTP)); + memcpy(buf + PTP_COMMON_HDR_MSG_LENGTH(PTP_COMMON_HDR_OFFSET), + &messageLength_NO, sizeof(messageLength_NO)); + memcpy(buf + PTP_COMMON_HDR_DOMAIN_NUMBER(PTP_COMMON_HDR_OFFSET), + &domainNumber, sizeof(domainNumber)); + memcpy(buf + PTP_COMMON_HDR_FLAGS(PTP_COMMON_HDR_OFFSET), &flags, + PTP_FLAGS_LENGTH); + memcpy(buf + PTP_COMMON_HDR_CORRECTION(PTP_COMMON_HDR_OFFSET), + &correctionField_BE, sizeof(correctionField)); + + sourcePortIdentity->getClockIdentityString((char *)buf + + PTP_COMMON_HDR_SOURCE_CLOCK_ID + (PTP_COMMON_HDR_OFFSET)); + sourcePortIdentity->getPortNumberNO((uint16_t *) (buf + + PTP_COMMON_HDR_SOURCE_PORT_ID + (PTP_COMMON_HDR_OFFSET))); + + XPTPD_INFO("Sending Sequence Id: %u", sequenceId); + sequenceId = PLAT_htons(sequenceId); + memcpy(buf + PTP_COMMON_HDR_SEQUENCE_ID(PTP_COMMON_HDR_OFFSET), + &sequenceId, sizeof(sequenceId)); + sequenceId = PLAT_ntohs(sequenceId); + memcpy(buf + PTP_COMMON_HDR_CONTROL(PTP_COMMON_HDR_OFFSET), &control, + sizeof(control)); + memcpy(buf + PTP_COMMON_HDR_LOG_MSG_INTRVL(PTP_COMMON_HDR_OFFSET), + &logMeanMessageInterval, sizeof(logMeanMessageInterval)); + + return; +} + +void PTPMessageCommon::getPortIdentity(PortIdentity * identity) +{ + *identity = *sourcePortIdentity; +} + +void PTPMessageCommon::setPortIdentity(PortIdentity * identity) +{ + *sourcePortIdentity = *identity; +} + +PTPMessageCommon::~PTPMessageCommon(void) +{ + delete sourcePortIdentity; + return; +} + +PTPMessageAnnounce::PTPMessageAnnounce(void) +{ + clockQuality = new ClockQuality(); +} + +PTPMessageAnnounce::~PTPMessageAnnounce(void) +{ + delete clockQuality; +} + +bool PTPMessageAnnounce::isBetterThan(PTPMessageAnnounce * msg) +{ + unsigned char this1[14]; + unsigned char that1[14]; + uint16_t tmp; + + this1[0] = grandmasterPriority1; + that1[0] = msg->getGrandmasterPriority1(); + + this1[1] = clockQuality->cq_class; + that1[1] = msg->getGrandmasterClockQuality()->cq_class; + + this1[2] = clockQuality->clockAccuracy; + that1[2] = msg->getGrandmasterClockQuality()->clockAccuracy; + + tmp = clockQuality->offsetScaledLogVariance; + tmp = PLAT_htons(tmp); + memcpy(this1 + 3, &tmp, sizeof(tmp)); + tmp = msg->getGrandmasterClockQuality()->offsetScaledLogVariance; + tmp = PLAT_htons(tmp); + memcpy(that1 + 3, &tmp, sizeof(tmp)); + + this1[5] = grandmasterPriority2; + that1[5] = msg->getGrandmasterPriority2(); + + this->getGrandmasterIdentity((char *)this1 + 6); + msg->getGrandmasterIdentity((char *)that1 + 6); + +#if 0 + fprintf(stderr, "Us: "); + for (int i = 0; i < 14; ++i) + fprintf(stderr, "%hhx", this1[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "Them: "); + for (int i = 0; i < 14; ++i) + fprintf(stderr, "%hhx", that1[i]); + fprintf(stderr, "\n"); +#endif + + return (memcmp(this1, that1, 14) < 0) ? true : false; +} + + PTPMessageSync::PTPMessageSync(IEEE1588Port * port):PTPMessageCommon(port) +{ + messageType = SYNC_MESSAGE; // This is an event message + sequenceId = port->getNextSyncSequenceId(); + control = SYNC; + + flags[PTP_ASSIST_BYTE] |= (0x1 << PTP_ASSIST_BIT); + + originTimestamp = port->getClock()->getTime(); + + logMeanMessageInterval = port->getSyncInterval(); + return; +} + +void PTPMessageSync::sendPort(IEEE1588Port * port, PortIdentity * destIdentity) +{ + uint8_t buf_t[256]; + uint8_t *buf_ptr = buf_t + port->getPayloadOffset(); + unsigned char tspec_msg_t = 0x0; + Timestamp originTimestamp_BE; + memset(buf_t, 0, 256); + // Create packet in buf + // Copy in common header + messageLength = PTP_COMMON_HDR_LENGTH + PTP_SYNC_LENGTH; + tspec_msg_t |= messageType & 0xF; + buildCommonHeader(buf_ptr); + // Get timestamp + originTimestamp = port->getClock()->getTime(); + originTimestamp_BE.seconds_ms = PLAT_htons(originTimestamp.seconds_ms); + originTimestamp_BE.seconds_ls = PLAT_htonl(originTimestamp.seconds_ls); + originTimestamp_BE.nanoseconds = + PLAT_htonl(originTimestamp.nanoseconds); + // Copy in v2 sync specific fields + memcpy(buf_ptr + PTP_SYNC_SEC_MS(PTP_SYNC_OFFSET), + &(originTimestamp_BE.seconds_ms), + sizeof(originTimestamp.seconds_ms)); + memcpy(buf_ptr + PTP_SYNC_SEC_LS(PTP_SYNC_OFFSET), + &(originTimestamp_BE.seconds_ls), + sizeof(originTimestamp.seconds_ls)); + memcpy(buf_ptr + PTP_SYNC_NSEC(PTP_SYNC_OFFSET), + &(originTimestamp_BE.nanoseconds), + sizeof(originTimestamp.nanoseconds)); + + port->sendEventPort(buf_t, messageLength, MCAST_OTHER, destIdentity); + + return; +} + + PTPMessageAnnounce::PTPMessageAnnounce(IEEE1588Port * port):PTPMessageCommon + (port) +{ + messageType = ANNOUNCE_MESSAGE; // This is an event message + sequenceId = port->getNextAnnounceSequenceId(); + ClockIdentity id; + control = MESSAGE_OTHER; + + id = port->getClock()->getClockIdentity(); + tlv.setClockIdentity(&id); + + currentUtcOffset = port->getClock()->getCurrentUtcOffset(); + grandmasterPriority1 = port->getClock()->getPriority1(); + grandmasterPriority2 = port->getClock()->getPriority2(); + clockQuality = new ClockQuality(); + *clockQuality = port->getClock()->getClockQuality(); + stepsRemoved = 0; + timeSource = port->getClock()->getTimeSource(); + ClockIdentity clock_identity; + clock_identity = port->getClock()->getClockIdentity(); + clock_identity.getIdentityString(grandmasterIdentity); + + logMeanMessageInterval = port->getAnnounceInterval(); + return; +} + +void PTPMessageAnnounce::sendPort(IEEE1588Port * port, + PortIdentity * destIdentity) +{ + uint8_t buf_t[256]; + uint8_t *buf_ptr = buf_t + port->getPayloadOffset(); + unsigned char tspec_msg_t = 0x0; + + uint16_t currentUtcOffset_l = PLAT_htons(currentUtcOffset); + uint16_t stepsRemoved_l = PLAT_htons(stepsRemoved); + ClockQuality clockQuality_l = *clockQuality; + clockQuality_l.offsetScaledLogVariance = + PLAT_htons(clockQuality_l.offsetScaledLogVariance); + + memset(buf_t, 0, 256); + // Create packet in buf + // Copy in common header + messageLength = + PTP_COMMON_HDR_LENGTH + PTP_ANNOUNCE_LENGTH + sizeof(tlv); + tspec_msg_t |= messageType & 0xF; + buildCommonHeader(buf_ptr); + memcpy(buf_ptr + PTP_ANNOUNCE_CURRENT_UTC_OFFSET(PTP_ANNOUNCE_OFFSET), + ¤tUtcOffset_l, sizeof(currentUtcOffset)); + memcpy(buf_ptr + + PTP_ANNOUNCE_GRANDMASTER_PRIORITY1(PTP_ANNOUNCE_OFFSET), + &grandmasterPriority1, sizeof(grandmasterPriority1)); + memcpy(buf_ptr + + PTP_ANNOUNCE_GRANDMASTER_CLOCK_QUALITY(PTP_ANNOUNCE_OFFSET), + &clockQuality_l, sizeof(clockQuality)); + memcpy(buf_ptr + + PTP_ANNOUNCE_GRANDMASTER_PRIORITY2(PTP_ANNOUNCE_OFFSET), + &grandmasterPriority2, sizeof(grandmasterPriority2)); + port->getClock()->getGrandmasterIdentity((char *)buf_ptr + + PTP_ANNOUNCE_GRANDMASTER_IDENTITY + (PTP_ANNOUNCE_OFFSET)); + memcpy(buf_ptr + PTP_ANNOUNCE_STEPS_REMOVED(PTP_ANNOUNCE_OFFSET), + &stepsRemoved_l, sizeof(stepsRemoved)); + memcpy(buf_ptr + PTP_ANNOUNCE_TIME_SOURCE(PTP_ANNOUNCE_OFFSET), + &timeSource, sizeof(timeSource)); + tlv.toByteString(buf_ptr + PTP_COMMON_HDR_LENGTH + PTP_ANNOUNCE_LENGTH); + + port->sendGeneralPort(buf_t, messageLength, MCAST_OTHER, destIdentity); + + return; +} + +void PTPMessageAnnounce::processMessage(IEEE1588Port * port) +{ + // Delete announce receipt timeout + port->getClock()->deleteEventTimer(port, + ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES); + + // Add message to the list + port->addQualifiedAnnounce(this); + + port->getClock()->addEventTimer(port, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES, + (unsigned long long) + (ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * + (pow + ((double)2, + port->getAnnounceInterval()) * + 1000000000.0))); + port->getClock()->addEventTimer(port, STATE_CHANGE_EVENT, 16000000); +} + +void PTPMessageSync::processMessage(IEEE1588Port * port) +{ + Timestamp system_time; + Timestamp device_time; + int64_t delay; + + signed long long local_system_offset; + signed long long scalar_offset; + + int32_t local_clock_adjustment; + int32_t local_system_freq_offset; + + // Expire any SYNC_RECEIPT timers that exist + port->getClock()->deleteEventTimer(port, SYNC_RECEIPT_TIMEOUT_EXPIRES); + if (port->getPortState() == PTP_INITIALIZING + || port->getPortState() == PTP_DISABLED) { + // Do nothing Sync messages should be ignored when in this state + return; + } + if (port->getPortState() == PTP_FAULTY) { + // According to spec recovery is implementation specific + port->recoverPort(); + return; + } + + XPTPD_INFO("PTP assist flag is not set, FLAGS[0,1] = %u,%u", flags[0], + flags[1]); + +// if( flags[PTP_ASSIST_BYTE] & (0x1<getLastSync(); + if (old_sync != NULL) { + delete old_sync; + } + port->setLastSync(this); + _gc = false; + goto done; + } else { + _gc = true; + } + + // Indicates invalid link delay, wait until link delay had been calculated + if ((delay = port->getLinkDelay()) == 3600000000000) { + printf + ("Got Sync/Follow-Up but Link Delay has not been computed\n"); + goto done; + } +#if 0 + scalar_offset = _timestamp.nanoseconds + + (((unsigned long long)_timestamp.seconds_ms << + sizeof(_timestamp.seconds_ls) * 8) + + _timestamp.seconds_ls) * 1000000000LL; + scalar_offset -= + originTimestamp.nanoseconds + + (((unsigned long long)originTimestamp.seconds_ms << + sizeof(originTimestamp.seconds_ls) * 8) + + originTimestamp.seconds_ls) * 1000000000LL; +#endif + scalar_offset = + TIMESTAMP_TO_NS(_timestamp) - TIMESTAMP_TO_NS(originTimestamp); + scalar_offset -= delay; +#if 0 + scalar_offset -= delay.nanoseconds + + (((unsigned long long)delay.seconds_ms << sizeof(delay.seconds_ls) * + 8) + delay.seconds_ls) * 1000000000LL; +#endif + scalar_offset -= correctionField >> 16; // Fractional nanoseconds are dropped + + // Otherwise synchronize clock with approximate time from Sync message + uint32_t local_clock; + uint32_t nominal_clock_rate; + uint32_t device_sync_time_offset; + +#if 0 + Timestamp crstamp_device_time; + int64_t external_local_offset; + int32_t external_local_freq_offset; +#endif + + port->getDeviceTime(system_time, device_time, local_clock, + nominal_clock_rate); + + // Adjust local_clock to correspond to _timestamp + device_sync_time_offset = + TIMESTAMP_TO_NS(device_time) - TIMESTAMP_TO_NS(_timestamp); + local_clock -= + device_sync_time_offset / (1000000000 / nominal_clock_rate); + + XPTPD_INFO + ("ptp_message::sync::processMessage System time: %u,%u Device Time: %u,%u", + system_time.seconds_ls, system_time.nanoseconds, + device_time.seconds_ls, device_time.nanoseconds); + + local_clock_adjustment = + port->calcMasterLocalClockRateDifference(scalar_offset, _timestamp); + port->setMasterRateOffset(local_clock_adjustment); + + local_system_offset = + TIMESTAMP_TO_NS(system_time) - TIMESTAMP_TO_NS(device_time); +#if 0 + local_system_offset = system_time.nanoseconds + + (((unsigned long long)system_time.seconds_ms << + sizeof(system_time.seconds_ls) * 8) + + system_time.seconds_ls) * 1000000000LL; + local_system_offset -= + device_time.nanoseconds + + (((unsigned long long)device_time.seconds_ms << + sizeof(device_time.seconds_ls) * 8) + + device_time.seconds_ls) * 1000000000LL; +#endif + + local_system_freq_offset = + port->calcLocalSystemClockRateDifference(local_system_offset, + system_time); + + TIMESTAMP_SUB_NS(system_time, + (device_sync_time_offset * + (1000000000000ULL + + local_system_freq_offset)) / 1000000000000ULL); + + //port->getExternalClockRate( crstamp_device_time, external_local_offset, external_local_freq_offset ); + +#if 0 + port->getClock()->setMasterOffset(scalar_offset, _timestamp, + local_clock_adjustment, + local_system_offset, system_time, + local_system_freq_offset, + external_local_offset, + crstamp_device_time, + external_local_freq_offset); +#endif + port->getClock()->setMasterOffset(scalar_offset, _timestamp, + local_clock_adjustment, + local_system_offset, system_time, + local_system_freq_offset, + nominal_clock_rate, local_clock); + //fprintf( stderr, "Master-Local Offset=%d\n", local_clock_adjustment ); + + if (port->doSyntonization()) { + port->adjustClockRate(local_clock_adjustment, + _timestamp_counter_value, originTimestamp, + scalar_offset, false); + } + + done: + // Restart the SYNC_RECEIPT timer + port->getClock()->addEventTimer(port, SYNC_RECEIPT_TIMEOUT_EXPIRES, + (unsigned long long) + (SYNC_RECEIPT_TIMEOUT_MULTIPLIER * + ((double) + pow((double)2, + port->getSyncInterval()) * + 1000000000.0))); + + return; +} + + PTPMessageFollowUp::PTPMessageFollowUp(IEEE1588Port * port):PTPMessageCommon + (port) +{ + messageType = FOLLOWUP_MESSAGE; // This is an event message + control = FOLLOWUP; + + logMeanMessageInterval = port->getSyncInterval(); + + return; +} + +void PTPMessageFollowUp::sendPort(IEEE1588Port * port, + PortIdentity * destIdentity) +{ + uint8_t buf_t[256]; + uint8_t *buf_ptr = buf_t + port->getPayloadOffset(); + unsigned char tspec_msg_t = 0x0; + Timestamp preciseOriginTimestamp_BE; + memset(buf_t, 0, 256); + // Create packet in buf + // Copy in common header + messageLength = + PTP_COMMON_HDR_LENGTH + PTP_FOLLOWUP_LENGTH + sizeof(tlv); + tspec_msg_t |= messageType & 0xF; + buildCommonHeader(buf_ptr); + preciseOriginTimestamp_BE.seconds_ms = + PLAT_htons(preciseOriginTimestamp.seconds_ms); + preciseOriginTimestamp_BE.seconds_ls = + PLAT_htonl(preciseOriginTimestamp.seconds_ls); + preciseOriginTimestamp_BE.nanoseconds = + PLAT_htonl(preciseOriginTimestamp.nanoseconds); + // Copy in v2 sync specific fields + memcpy(buf_ptr + PTP_FOLLOWUP_SEC_MS(PTP_FOLLOWUP_OFFSET), + &(preciseOriginTimestamp_BE.seconds_ms), + sizeof(preciseOriginTimestamp.seconds_ms)); + memcpy(buf_ptr + PTP_FOLLOWUP_SEC_LS(PTP_FOLLOWUP_OFFSET), + &(preciseOriginTimestamp_BE.seconds_ls), + sizeof(preciseOriginTimestamp.seconds_ls)); + memcpy(buf_ptr + PTP_FOLLOWUP_NSEC(PTP_FOLLOWUP_OFFSET), + &(preciseOriginTimestamp_BE.nanoseconds), + sizeof(preciseOriginTimestamp.nanoseconds)); + tlv.toByteString(buf_ptr + PTP_COMMON_HDR_LENGTH + PTP_FOLLOWUP_LENGTH); + + XPTPD_INFO("Follow-Up Time: %u seconds(hi)", + preciseOriginTimestamp.seconds_ms); + XPTPD_INFO("Follow-Up Time: %u seconds", + preciseOriginTimestamp.seconds_ls); + XPTPD_INFO("F-UP Time: %u nanoseconds", + preciseOriginTimestamp.nanoseconds); + XPTPD_INFO("F-UP Time: %x seconds", preciseOriginTimestamp.seconds_ls); + XPTPD_INFO("F-UP Time: %x nanoseconds", + preciseOriginTimestamp.nanoseconds); +#if 0 + XPTPD_INFO("Follow-up Dump:\n"); +#ifdef DEBUG + for (int i = 0; i < messageLength; ++i) { + fprintf(stderr, "%d:%02x ", i, (unsigned char)buf[i]); + } + fprintf(stderr, "\n"); +#endif +#endif + + port->sendGeneralPort(buf_t, messageLength, MCAST_OTHER, destIdentity); + + return; +} + +void PTPMessageFollowUp::processMessage(IEEE1588Port * port) +{ + int64_t delay; + Timestamp sync_arrival; + Timestamp system_time(0, 0, 0); + Timestamp device_time(0, 0, 0); + + signed long long local_system_offset; + signed long long scalar_offset; + + int32_t local_clock_adjustment; + int32_t local_system_freq_offset; + + XPTPD_INFO("Processing a follow-up message"); + + if (port->getPortState() == PTP_INITIALIZING + || port->getPortState() == PTP_DISABLED) { + // Do nothing Sync messages should be ignored when in this state + return; + } + if (port->getPortState() == PTP_FAULTY) { + // According to spec recovery is implementation specific + port->recoverPort(); + return; + } + + PortIdentity sync_id; + PTPMessageSync *sync = port->getLastSync(); + if (sync == NULL) { + + XPTPD_ERROR("Received Follow Up but there is no sync message"); + + return; + } + sync->getPortIdentity(&sync_id); + + if (sync->getSequenceId() != sequenceId + || sync_id != *sourcePortIdentity) { + + XPTPD_ERROR + ("Received Follow Up but cannot find corresponding Sync"); + + goto done; + } + + sync_arrival = sync->getTimestamp(); + + XPTPD_INFO("Sync Arrival: %u seconds", sync_arrival.seconds_ls); + XPTPD_INFO("Sync Arrival: %u nanoseconds", sync_arrival.nanoseconds); + XPTPD_INFO("Sync Depart: %u seconds", + preciseOriginTimestamp.seconds_ls); + XPTPD_INFO("Sync Depart: %u nanoseconds", + preciseOriginTimestamp.nanoseconds); + XPTPD_INFO("Sync Depart: %x seconds", + preciseOriginTimestamp.seconds_ls); + XPTPD_INFO("Sync Depart: %x nanoseconds", + preciseOriginTimestamp.nanoseconds); + + delay = port->getLinkDelay(); + if ((delay = port->getLinkDelay()) == 3600000000000) { + goto done; + } + //fprintf( stderr, "Local Time = %llu,Master Time = %llu\n", TIMESTAMP_TO_NS(sync_arrival)-delay, TIMESTAMP_TO_NS( preciseOriginTimestamp)); + + scalar_offset = + TIMESTAMP_TO_NS(sync_arrival) - + TIMESTAMP_TO_NS(preciseOriginTimestamp); + + //printf( "Followup timestamp: %u,%u,%u\n", preciseOriginTimestamp.seconds_ms, preciseOriginTimestamp.seconds_ls, preciseOriginTimestamp.nanoseconds ); + //printf( "Sync Arrival timestamp: %u,%u,%u\n", sync_arrival.seconds_ms, sync_arrival.seconds_ls, sync_arrival.nanoseconds ); + //printf( "FollowUp Scalar = %Ld\n", scalar_offset ); + + scalar_offset -= delay; + scalar_offset -= correctionField >> 16; // Fractional nanoseconds are dropped + //fprintf( stderr, "Scalar offset = %lld\n", scalar_offset ); + //scalar_offset -= sync->getCorrectionField() >> 16; // Fractional nanoseconds are dropped + //fprintf( stderr, "Correction Field (ns): %lld\n", correctionField >> 16 ); + //fprintf( stderr, "Link Delay (ns): %lld(%llu,%llu)\n", delay, TIMESTAMP_TO_NS( sync_arrival), TIMESTAMP_TO_NS(preciseOriginTimestamp) ); + + XPTPD_INFO("Followup Correction Field: %Ld,%lu", correctionField >> 16, + delay); + XPTPD_INFO("FollowUp Scalar = %lld", scalar_offset); + + // Otherwise synchronize clock with approximate time from Sync message + uint32_t local_clock, nominal_clock_rate; + uint32_t device_sync_time_offset; + +#if 0 + Timestamp crstamp_device_time; + int64_t external_local_offset; + int32_t external_local_freq_offset; +#endif + + port->getDeviceTime(system_time, device_time, local_clock, + nominal_clock_rate); + //fprintf( stderr, "Device Time = %llu,System Time = %llu\n", TIMESTAMP_TO_NS(device_time), TIMESTAMP_TO_NS(system_time)); + + // Adjust local_clock to correspond to sync_arrival + device_sync_time_offset = + TIMESTAMP_TO_NS(device_time) - TIMESTAMP_TO_NS(sync_arrival); + //local_clock -= device_sync_time_offset/(1000000000/nominal_clock_rate); + + XPTPD_INFO + ("ptp_message::FollowUp::processMessage System time: %u,%u Device Time: %u,%u", + system_time.seconds_ls, system_time.nanoseconds, + device_time.seconds_ls, device_time.nanoseconds); + + local_system_offset = + TIMESTAMP_TO_NS(system_time) - TIMESTAMP_TO_NS(device_time); + +#if 0 + local_system_offset = system_time.nanoseconds + + (((unsigned long long)system_time.seconds_ms << + sizeof(system_time.seconds_ls) * 8) + + system_time.seconds_ls) * 1000000000LL; + local_system_offset -= + device_time.nanoseconds + + (((unsigned long long)device_time.seconds_ms << + sizeof(device_time.seconds_ls) * 8) + + device_time.seconds_ls) * 1000000000LL; +#endif + + local_clock_adjustment = + port->calcMasterLocalClockRateDifference(scalar_offset, + sync_arrival); + port->setMasterRateOffset(local_clock_adjustment); + + local_system_freq_offset = + port->calcLocalSystemClockRateDifference(local_system_offset, + system_time); + //fprintf( stderr, "Master-Local Freq Offset = %d\n", local_clock_adjustment ); + //fprintf( stderr, "Local-System Freq Offset = %d\n", local_system_freq_offset ); + + TIMESTAMP_SUB_NS(system_time, + (device_sync_time_offset * + (1000000000000ULL + + local_system_freq_offset)) / 1000000000000ULL); + + //port->getExternalClockRate( crstamp_device_time, external_local_offset, external_local_freq_offset ); + +#if 0 + port->getClock()->setMasterOffset(scalar_offset, sync_arrival, + local_clock_adjustment, + local_system_offset, system_time, + local_system_freq_offset, + external_local_offset, + crstamp_device_time, + external_local_freq_offset); +#endif + port->getClock()->setMasterOffset(scalar_offset, sync_arrival, + local_clock_adjustment, + local_system_offset, system_time, + local_system_freq_offset, + nominal_clock_rate, local_clock); + //fprintf( stderr, "Master-Local Offset=%lld,%d,%llu\n", scalar_offset, local_clock_adjustment, TIMESTAMP_TO_NS(sync_arrival) ); + + if (port->doSyntonization()) { + port->adjustClockRate(local_clock_adjustment, + sync->getTimestampCounterValue(), + preciseOriginTimestamp, scalar_offset, + false); + } + + done: + _gc = true; + delete sync; + port->setLastSync(NULL); + + return; +} + + PTPMessagePathDelayReq::PTPMessagePathDelayReq(IEEE1588Port * port):PTPMessageCommon + (port) +{ + logMeanMessageInterval = 0; + control = MESSAGE_OTHER; + messageType = PATH_DELAY_REQ_MESSAGE; + sequenceId = port->getNextPDelaySequenceId(); + return; +} + +void PTPMessagePathDelayReq::processMessage(IEEE1588Port * port) +{ + OSTimer *timer = port->getTimerFactory()->createTimer(); + + if (port->getPortState() == PTP_INITIALIZING + || port->getPortState() == PTP_DISABLED) { + // Do nothing all messages should be ignored when in this state + return; + } + + if (port->getPortState() == PTP_FAULTY) { + // According to spec recovery is implementation specific + port->recoverPort(); + return; + } + + port->getClock()->deleteEventTimer(port, + PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES); + port->getClock()->addEventTimer(port, + PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES, + (unsigned long long) + (PDELAY_RESP_RECEIPT_TIMEOUT_MULTIPLIER + * + (pow + ((double)2, + port->getPDelayInterval()) * + 1000000000.0))); + // Generate and send message + PTPMessagePathDelayResp *resp = new PTPMessagePathDelayResp(port); + PortIdentity resp_id; + port->getPortIdentity(resp_id); + resp->setPortIdentity(&resp_id); + resp->setSequenceId(sequenceId); + + XPTPD_INFO("Process PDelay Request SeqId: %u\t", sequenceId); + //XPTPD_INFO( "Process PDelay Request Port: %u\t", ); + //XPTPD_INFO( "Process PDelay Request Identity: \"" ); + +#ifdef DEBUG + for (int n = 0; n < PTP_CLOCK_IDENTITY_LENGTH; ++n) { + fprintf(stderr, "%c", resp_id.clockIdentity[n]); + } + fprintf(stderr, "\"\n"); +#endif + + PortIdentity requestingPortIdentity_p; + this->getPortIdentity(&requestingPortIdentity_p); + resp->setRequestingPortIdentity(&requestingPortIdentity_p); + resp->setRequestReceiptTimestamp(_timestamp); + port->getTxLock(); + resp->sendPort(port, sourcePortIdentity); + + XPTPD_INFO("Sent path delay response"); + + int ts_good; + int iter = 2; + Timestamp resp_timestamp; + unsigned resp_timestamp_counter_value; + unsigned req = 1000; // = 1 ms + + XPTPD_INFO("Start TS Read"); + ts_good = + port->getTxTimestamp(resp, resp_timestamp, + resp_timestamp_counter_value, false); + + XPTPD_INFO("Done TS Read"); + + while (ts_good != 0 && iter-- != 0) { + timer->sleep(req); + if (ts_good == -72 && iter < 1) + fprintf(stderr, + "Error (TX) timestamping PDelay Response (Retrying-%d), error=%d\n", + iter, ts_good); + ts_good = + port->getTxTimestamp(resp, resp_timestamp, + resp_timestamp_counter_value, + iter == 0); + req *= 2; + } + port->putTxLock(); + + if (ts_good != 0) { + char msg[HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE]; + port->getExtendedError(msg); + fprintf(stderr, + "Error (TX) timestamping PDelay Response, error=%d\n%s", + ts_good, msg); + delete resp; + return; + } + + PTPMessagePathDelayRespFollowUp *resp_fwup = + new PTPMessagePathDelayRespFollowUp(port); + PortIdentity resp_fwup_id; + port->getPortIdentity(resp_fwup_id); + resp_fwup->setPortIdentity(&resp_fwup_id); + resp_fwup->setSequenceId(sequenceId); + resp_fwup->setRequestingPortIdentity(sourcePortIdentity); + resp_fwup->setResponseOriginTimestamp(resp_timestamp); + long long turnaround; + turnaround = + (resp_timestamp.seconds_ls - _timestamp.seconds_ls) * 1000000000LL; + + XPTPD_INFO("Response Depart(sec): %u", resp_timestamp.seconds_ls); + XPTPD_INFO("Request Arrival(sec): %u", _timestamp.seconds_ls); + XPTPD_INFO("#1 Correction Field: %Ld", turnaround); + + turnaround += resp_timestamp.nanoseconds; + + XPTPD_INFO("#2 Correction Field: %Ld", turnaround); + + turnaround -= _timestamp.nanoseconds; + + XPTPD_INFO("#3 Correction Field: %Ld", turnaround); + + //resp_fwup->setCorrectionField( turnaround << 16 ); + resp_fwup->setCorrectionField(0); // MMM + resp_fwup->sendPort(port, sourcePortIdentity); + + XPTPD_INFO("Sent path delay response fwup"); + + delete resp; + delete resp_fwup; + + _gc = true; +} + +void PTPMessagePathDelayReq::sendPort(IEEE1588Port * port, + PortIdentity * destIdentity) +{ + uint8_t buf_t[256]; + uint8_t *buf_ptr = buf_t + port->getPayloadOffset(); + unsigned char tspec_msg_t = 0; + memset(buf_t, 0, 256); + // Create packet in buf + // Copy in common header + messageLength = PTP_COMMON_HDR_LENGTH + PTP_PDELAY_REQ_LENGTH; + tspec_msg_t |= messageType & 0xF; + buildCommonHeader(buf_ptr); + // Get timestamp + //originTimestamp = port->getClock()->getTime(); + // These fields are not used +// memcpy( buf+PTP_PDELAY_REQ_SEC_MS(PTP_PDELAY_REQ_OFFSET), &(originTimestamp.seconds_ms), sizeof(originTimestamp.seconds_ms)); +// memcpy( buf+PTP_PDELAY_REQ_SEC_LS(PTP_PDELAY_REQ_OFFSET), &(originTimestamp.seconds_ls), sizeof(originTimestamp.seconds_ls)); +// memcpy( buf+PTP_PDELAY_REQ_NSEC(PTP_PDELAY_REQ_OFFSET), &(originTimestamp.nanoseconds), sizeof(originTimestamp.nanoseconds)); +// memcpy( buf+PTP_PDELAY_REQ_TS_OFFSET(PTP_PDELAY_REQ_OFFSET), &(originTimestamp.timescaleOffset), sizeof(originTimestamp.timescaleOffset)); + + port->sendEventPort(buf_t, messageLength, MCAST_PDELAY, destIdentity); + return; +} + + PTPMessagePathDelayResp::PTPMessagePathDelayResp(IEEE1588Port * port): +PTPMessageCommon(port) +{ + logMeanMessageInterval = 0; + control = MESSAGE_OTHER; + messageType = PATH_DELAY_RESP_MESSAGE; + versionPTP = GPTP_VERSION; + requestingPortIdentity = new PortIdentity(); + + flags[PTP_ASSIST_BYTE] |= (0x1 << PTP_ASSIST_BIT); + + return; +} + +PTPMessagePathDelayResp::~PTPMessagePathDelayResp() +{ + delete requestingPortIdentity; +} + +void PTPMessagePathDelayResp::processMessage(IEEE1588Port * port) +{ + if (port->getPortState() == PTP_INITIALIZING + || port->getPortState() == PTP_DISABLED) { + // Do nothing all messages should be ignored when in this state + return; + } + if (port->getPortState() == PTP_FAULTY) { + // According to spec recovery is implementation specific + port->recoverPort(); + return; + } + + if (port->tryPDelayRxLock() != true) { + fprintf(stderr, "Failed to get PDelay RX Lock\n"); + return; + } + + port->getClock()->deleteEventTimer(port, + PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES); + port->getClock()->addEventTimer(port, + PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES, + (unsigned long long) + (PDELAY_RESP_RECEIPT_TIMEOUT_MULTIPLIER + * + (pow + ((double)2, + port->getPDelayInterval()) * + 1000000000.0))); + PTPMessagePathDelayResp *old_pdelay_resp = port->getLastPDelayResp(); + if (old_pdelay_resp != NULL) { + delete old_pdelay_resp; + } + port->setLastPDelayResp(this); + + port->putPDelayRxLock(); + _gc = false; + + return; +} + +void PTPMessagePathDelayResp::sendPort(IEEE1588Port * port, + PortIdentity * destIdentity) +{ + uint8_t buf_t[256]; + uint8_t *buf_ptr = buf_t + port->getPayloadOffset(); + unsigned char tspec_msg_t = 0; + Timestamp requestReceiptTimestamp_BE; + memset(buf_t, 0, 256); + // Create packet in buf + // Copy in common header + messageLength = PTP_COMMON_HDR_LENGTH + PTP_PDELAY_RESP_LENGTH; + tspec_msg_t |= messageType & 0xF; + buildCommonHeader(buf_ptr); + requestReceiptTimestamp_BE.seconds_ms = + PLAT_htons(requestReceiptTimestamp.seconds_ms); + requestReceiptTimestamp_BE.seconds_ls = + PLAT_htonl(requestReceiptTimestamp.seconds_ls); + requestReceiptTimestamp_BE.nanoseconds = + PLAT_htonl(requestReceiptTimestamp.nanoseconds); + + // Copy in v2 PDelay_Req specific fields + requestingPortIdentity->getClockIdentityString((char *)buf_ptr + + PTP_PDELAY_RESP_REQ_CLOCK_ID + (PTP_PDELAY_RESP_OFFSET)); + requestingPortIdentity->getPortNumberNO((uint16_t *) (buf_ptr + + PTP_PDELAY_RESP_REQ_PORT_ID + (PTP_PDELAY_RESP_OFFSET))); + memcpy(buf_ptr + PTP_PDELAY_RESP_SEC_MS(PTP_PDELAY_RESP_OFFSET), + &(requestReceiptTimestamp_BE.seconds_ms), + sizeof(requestReceiptTimestamp.seconds_ms)); + memcpy(buf_ptr + PTP_PDELAY_RESP_SEC_LS(PTP_PDELAY_RESP_OFFSET), + &(requestReceiptTimestamp_BE.seconds_ls), + sizeof(requestReceiptTimestamp.seconds_ls)); + memcpy(buf_ptr + PTP_PDELAY_RESP_NSEC(PTP_PDELAY_RESP_OFFSET), + &(requestReceiptTimestamp_BE.nanoseconds), + sizeof(requestReceiptTimestamp.nanoseconds)); + + XPTPD_INFO("PDelay Resp Timestamp: %u,%u", + requestReceiptTimestamp.seconds_ls, + requestReceiptTimestamp.nanoseconds); + + port->sendEventPort(buf_t, messageLength, MCAST_PDELAY, destIdentity); + return; +} + +void PTPMessagePathDelayResp::setRequestingPortIdentity(PortIdentity * identity) +{ + *requestingPortIdentity = *identity; +} + +void PTPMessagePathDelayResp::getRequestingPortIdentity(PortIdentity * identity) +{ + *identity = *requestingPortIdentity; +} + + PTPMessagePathDelayRespFollowUp::PTPMessagePathDelayRespFollowUp(IEEE1588Port * port): +PTPMessageCommon + (port) +{ + logMeanMessageInterval = 0; + control = MESSAGE_OTHER; + messageType = PATH_DELAY_FOLLOWUP_MESSAGE; + versionPTP = GPTP_VERSION; + requestingPortIdentity = new PortIdentity(); + + return; +} + +PTPMessagePathDelayRespFollowUp::~PTPMessagePathDelayRespFollowUp() +{ + delete requestingPortIdentity; +} + +void PTPMessagePathDelayRespFollowUp::processMessage(IEEE1588Port * port) +{ + Timestamp remote_resp_tx_timestamp(0, 0, 0); + Timestamp request_tx_timestamp(0, 0, 0); + Timestamp remote_req_rx_timestamp(0, 0, 0); + Timestamp response_rx_timestamp(0, 0, 0); + + if (port->getPortState() == PTP_INITIALIZING + || port->getPortState() == PTP_DISABLED) { + // Do nothing all messages should be ignored when in this state + return; + } + if (port->getPortState() == PTP_FAULTY) { + // According to spec recovery is implementation specific + port->recoverPort(); + return; + } + + if (port->tryPDelayRxLock() != true) + return; + + PTPMessagePathDelayReq *req = port->getLastPDelayReq(); + PTPMessagePathDelayResp *resp = port->getLastPDelayResp(); + + PortIdentity req_id; + PortIdentity resp_id; + + if (req == NULL) { + // Shouldn't happen + XPTPD_ERROR + (">>> Received PDelay followup but no REQUEST exists"); + goto abort; + } + + if (resp == NULL) { + // Probably shouldn't happen either + XPTPD_ERROR + (">>> Received PDelay followup but no RESPONSE exists"); + goto abort; + } + + req->getPortIdentity(&req_id); + resp->getRequestingPortIdentity(&resp_id); + + // Check if we have sent a request +// if( req->getSequenceId() != sequenceId || req_id.portNumber != requestingPortIdentity.portNumber || +// memcmp( req_id.clockIdentity, requestingPortIdentity.clockIdentity, PTP_CLOCK_IDENTITY_LENGTH ) != 0 ) { + if (req->getSequenceId() != sequenceId) { + + XPTPD_ERROR + ("Received PDelay Response Follow Up but cannot find corresponding request"); + // XPTPD_INFO( "Requesting SeqId: %u ", req->getSequenceId() ); + // XPTPD_INFO( "Requesting SeqId: %u ", sequenceId ); + XPTPD_ERROR("My SeqId: %u ", req->getSequenceId()); + XPTPD_ERROR("Their SeqId: %u ", sequenceId); + //XPTPD_INFO( "Requesting Port: %u ", requestingPortIdentity.portNumber ); + XPTPD_INFO("Requesting Identity: \""); + +#ifdef DEBUG + for (int n = 0; n < PTP_CLOCK_IDENTITY_LENGTH; ++n) { + fprintf(stderr, "%u: %x ", n, + requestingPortIdentity.clockIdentity[n]); + } + fprintf(stderr, " \"\n"); +#endif + + //XPTPD_INFO( "Requesting SeqId: %u ", req->getSequenceId() ); + //XPTPD_INFO( "Requesting Port: %u ", req_id.portNumber ); + XPTPD_INFO("Requesting Identity: \""); + +#ifdef DEBUG + for (int n = 0; n < PTP_CLOCK_IDENTITY_LENGTH; ++n) { + fprintf(stderr, "%u:%x ", n, req_id.clockIdentity[n]); + } + fprintf(stderr, " \"\n"); +#endif + + goto abort; + } + //fprintf( stderr, "PDelay Follow-Up OK\n" ); + + // Check if we have received a response + if (resp->getSequenceId() != sequenceId + || resp_id != *requestingPortIdentity) { + uint16_t resp_port_number; + uint16_t req_port_number; + resp_id.getPortNumber(&resp_port_number); + requestingPortIdentity->getPortNumber(&req_port_number); + XPTPD_ERROR + ("Received PDelay Response Follow Up but cannot find corresponding response"); + XPTPD_ERROR("%hu, %hu, %hu, %hu", resp->getSequenceId(), + sequenceId, resp_port_number, req_port_number); + + goto abort; + } + + XPTPD_INFO("Request Sequence Id: %u", req->getSequenceId()); + XPTPD_INFO("Response Sequence Id: %u", resp->getSequenceId()); + XPTPD_INFO("Follow-Up Sequence Id: %u", req->getSequenceId()); + + port->setAsCapable(true); + + int64_t link_delay; + unsigned long long turn_around; + + // Assume that we are a two step clock, otherwise originTimestamp may be used + request_tx_timestamp = req->getTimestamp(); + if (request_tx_timestamp.nanoseconds == + PDELAY_PENDING_TIMESTAMP.nanoseconds) { + // Defer processing + if (port->getLastPDelayRespFollowUp() != NULL) { + delete port->getLastPDelayRespFollowUp(); + } + port->setLastPDelayRespFollowUp(this); + port->getClock()->addEventTimer(port, + PDELAY_DEFERRED_PROCESSING, + 1000000); + goto defer; + } + if (request_tx_timestamp.nanoseconds == INVALID_TIMESTAMP.nanoseconds) { + // Stop processing the packet + goto abort; + } + remote_req_rx_timestamp = resp->getRequestReceiptTimestamp(); + response_rx_timestamp = resp->getTimestamp(); + remote_resp_tx_timestamp = responseOriginTimestamp; + +#if 0 + fprintf(stderr, "@REQT,%u,%u,%u,%hu\n", request_tx_timestamp.seconds_ms, + request_tx_timestamp.seconds_ls, + request_tx_timestamp.nanoseconds, req->getSequenceId()); + fprintf(stderr, "@REQR,%u,%u,%u,%hu\n", + remote_req_rx_timestamp.seconds_ms, + remote_req_rx_timestamp.seconds_ls, + remote_req_rx_timestamp.nanoseconds, resp->getSequenceId()); + fprintf(stderr, "@RESR,%u,%u,%u,%hu\n", + response_rx_timestamp.seconds_ms, + response_rx_timestamp.seconds_ls, + response_rx_timestamp.nanoseconds, resp->getSequenceId()); + fprintf(stderr, "@REST,%u,%u,%u,%hu\n", + remote_resp_tx_timestamp.seconds_ms, + remote_resp_tx_timestamp.seconds_ls, + remote_resp_tx_timestamp.nanoseconds, sequenceId); +#endif + + link_delay = + ((response_rx_timestamp.seconds_ms * 1LL - + request_tx_timestamp.seconds_ms) << 32) * 1000000000; + link_delay += + (response_rx_timestamp.seconds_ls * 1LL - + request_tx_timestamp.seconds_ls) * 1000000000; + link_delay += + (response_rx_timestamp.nanoseconds * 1LL - + request_tx_timestamp.nanoseconds); + //fprintf( stderr, "Send/Recv Delay is %lld\n", link_delay ); + + turn_around = + ((remote_resp_tx_timestamp.seconds_ms * 1LL - + remote_req_rx_timestamp.seconds_ms) << 32) * 1000000000; + turn_around += + (remote_resp_tx_timestamp.seconds_ls * 1LL - + remote_req_rx_timestamp.seconds_ls) * 1000000000; + turn_around += + (remote_resp_tx_timestamp.nanoseconds * 1LL - + remote_req_rx_timestamp.nanoseconds); + //fprintf( stderr, "Unadjusted Turn Around is %llu\n", turn_around ); + //fprintf( stderr, "Unadjusted Link Delay *2 %lld\n", link_delay - turn_around ); + + //fprintf( stderr, "Peer Rate Offset: %d", port->getPeerRateOffset() ); + + // Adjust turn-around time for peer to local clock rate difference + turn_around += + (((long long)turn_around) * port->getPeerRateOffset()) / + 1000000000000LL; + + XPTPD_INFO("Turn Around Adjustment %Ld", + ((long long)turn_around * port->getPeerRateOffset()) / + 1000000000000LL); + XPTPD_INFO("Step #1: Turn Around Adjustment %Ld", + ((long long)turn_around * port->getPeerRateOffset())); + XPTPD_INFO("Adjusted Peer turn around is %Lu", turn_around); + + // Subtract turn-around time from link delay after rate adjustment + link_delay -= turn_around; + + link_delay /= 2; + + { + uint64_t mine_elapsed; + uint64_t theirs_elapsed; + Timestamp prev_peer_ts_mine; + Timestamp prev_peer_ts_theirs; + int32_t rate_offset; + if (port->getPeerOffset(prev_peer_ts_mine, prev_peer_ts_theirs)) { + mine_elapsed = + TIMESTAMP_TO_NS(request_tx_timestamp) - + TIMESTAMP_TO_NS(prev_peer_ts_mine); + theirs_elapsed = + TIMESTAMP_TO_NS(remote_req_rx_timestamp) - + TIMESTAMP_TO_NS(prev_peer_ts_theirs); +#if 0 + rate_offset = + (int32_t) ((mine_elapsed * 1000000000ULL) / + theirs_elapsed); + rate_offset -= 1000000000; +#endif + theirs_elapsed -= port->getLinkDelay() - link_delay; + rate_offset = + (int32_t) ((mine_elapsed * 1000000000ULL) / + theirs_elapsed); + rate_offset -= 1000000000; + rate_offset *= 1000; + port->setPeerRateOffset(rate_offset); + //fprintf( stderr, "(2)PDelay rate offset: %d\n", rate_offset ); + } + } + port->setLinkDelay(link_delay); + port->setPeerOffset(request_tx_timestamp, remote_req_rx_timestamp); + + abort: + delete req; + port->setLastPDelayReq(NULL); + delete resp; + port->setLastPDelayResp(NULL); + + _gc = true; + + defer: + port->putPDelayRxLock(); + + return; +} + +void PTPMessagePathDelayRespFollowUp::sendPort(IEEE1588Port * port, + PortIdentity * destIdentity) +{ + uint8_t buf_t[256]; + uint8_t *buf_ptr = buf_t + port->getPayloadOffset(); + unsigned char tspec_msg_t = 0; + Timestamp responseOriginTimestamp_BE; + memset(buf_t, 0, 256); + // Create packet in buf + // Copy in common header + messageLength = PTP_COMMON_HDR_LENGTH + PTP_PDELAY_RESP_LENGTH; + tspec_msg_t |= messageType & 0xF; + buildCommonHeader(buf_ptr); + responseOriginTimestamp_BE.seconds_ms = + PLAT_htons(responseOriginTimestamp.seconds_ms); + responseOriginTimestamp_BE.seconds_ls = + PLAT_htonl(responseOriginTimestamp.seconds_ls); + responseOriginTimestamp_BE.nanoseconds = + PLAT_htonl(responseOriginTimestamp.nanoseconds); + + // Copy in v2 PDelay_Req specific fields + requestingPortIdentity->getClockIdentityString((char *)buf_ptr + + PTP_PDELAY_FOLLOWUP_REQ_CLOCK_ID + (PTP_PDELAY_FOLLOWUP_OFFSET)); + requestingPortIdentity->getPortNumberNO((uint16_t *) (buf_ptr + + PTP_PDELAY_FOLLOWUP_REQ_PORT_ID + (PTP_PDELAY_FOLLOWUP_OFFSET))); + memcpy(buf_ptr + PTP_PDELAY_FOLLOWUP_SEC_MS(PTP_PDELAY_FOLLOWUP_OFFSET), + &(responseOriginTimestamp_BE.seconds_ms), + sizeof(responseOriginTimestamp.seconds_ms)); + memcpy(buf_ptr + PTP_PDELAY_FOLLOWUP_SEC_LS(PTP_PDELAY_FOLLOWUP_OFFSET), + &(responseOriginTimestamp_BE.seconds_ls), + sizeof(responseOriginTimestamp.seconds_ls)); + memcpy(buf_ptr + PTP_PDELAY_FOLLOWUP_NSEC(PTP_PDELAY_FOLLOWUP_OFFSET), + &(responseOriginTimestamp_BE.nanoseconds), + sizeof(responseOriginTimestamp.nanoseconds)); + + XPTPD_INFO("PDelay Resp Timestamp: %u,%u", + responseOriginTimestamp.seconds_ls, + responseOriginTimestamp.nanoseconds); + + port->sendGeneralPort(buf_t, messageLength, MCAST_PDELAY, destIdentity); + return; +} + +void PTPMessagePathDelayRespFollowUp::setRequestingPortIdentity(PortIdentity * + identity) +{ + *requestingPortIdentity = *identity; +} diff --git a/daemons/gptp/linux/CVS/Entries b/daemons/gptp/linux/CVS/Entries new file mode 100644 index 0000000..b44d45c --- /dev/null +++ b/daemons/gptp/linux/CVS/Entries @@ -0,0 +1,2 @@ +D/src//// +D/build//// diff --git a/daemons/gptp/linux/CVS/Repository b/daemons/gptp/linux/CVS/Repository new file mode 100644 index 0000000..34ff17b --- /dev/null +++ b/daemons/gptp/linux/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/linux diff --git a/daemons/gptp/linux/CVS/Root b/daemons/gptp/linux/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/linux/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/linux/build/CVS/Entries b/daemons/gptp/linux/build/CVS/Entries new file mode 100644 index 0000000..8933c8a --- /dev/null +++ b/daemons/gptp/linux/build/CVS/Entries @@ -0,0 +1,2 @@ +D/obj//// +/Makefile/1.1/Fri Sep 7 18:53:45 2012// diff --git a/daemons/gptp/linux/build/CVS/Repository b/daemons/gptp/linux/build/CVS/Repository new file mode 100644 index 0000000..8599377 --- /dev/null +++ b/daemons/gptp/linux/build/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/linux/build diff --git a/daemons/gptp/linux/build/CVS/Root b/daemons/gptp/linux/build/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/linux/build/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/linux/build/Makefile b/daemons/gptp/linux/build/Makefile new file mode 100644 index 0000000..8d13174 --- /dev/null +++ b/daemons/gptp/linux/build/Makefile @@ -0,0 +1,84 @@ +# +# Copyright (c) 2012 Intel Corporation +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. 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. +# +# 3. Neither the name of the Intel Corporation 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. + +CXX = g++ + +CFLAGS_G = -Wall -g -I. -I../../common -I../src +LDFLAGS_G = -lpthread -lrt + +CFLAGS = $(CFLAGS_G) +LDFLAGS = $(LDFLAGS_G) + +CXXFLAGS = +COMMON_DIR = ../../common +SRC_DIR = ../src +OBJ_DIR = obj + +OBJ_FILES = $(OBJ_DIR)/ptp_message.o\ + $(OBJ_DIR)/avbts_osnet.o\ + $(OBJ_DIR)/ieee1588port.o\ + $(OBJ_DIR)/ieee1588clock.o + +HEADER_FILES = $(COMMON_DIR)/avbts_port.hpp\ + $(COMMON_DIR)/avbts_ostimerq.hpp\ + $(COMMON_DIR)/avbts_ostimer.hpp\ + $(COMMON_DIR)/avbts_osthread.hpp\ + $(COMMON_DIR)/avbts_osnet.hpp\ + $(COMMON_DIR)/avbts_oslock.hpp\ + $(COMMON_DIR)/avbts_osipc.hpp\ + $(COMMON_DIR)/avbts_oscondition.hpp\ + $(COMMON_DIR)/avbts_message.hpp\ + $(COMMON_DIR)/avbts_clock.hpp\ + $(COMMON_DIR)/ieee1588.hpp\ + $(SRC_DIR)/linux_hal.hpp\ + $(SRC_DIR)/platform.hpp + +all: daemon_cl + +rebuild: clean all + +daemon_cl: $(SRC_DIR)/daemon_cl.cpp $(OBJ_FILES) + $(CXX) $(CFLAGS) $(CXXFLAGS) $(OBJ_FILES) $(SRC_DIR)/daemon_cl.cpp -o $(OBJ_DIR)/daemon_cl $(LDFLAGS) + +$(OBJ_DIR)/ieee1588port.o: $(COMMON_DIR)/ieee1588port.cpp $(HEADER_FILES) + $(CXX) $(CFLAGS) $(CXXFLAGS) -c $(COMMON_DIR)/ieee1588port.cpp -o $(OBJ_DIR)/ieee1588port.o + +$(OBJ_DIR)/ieee1588clock.o: $(COMMON_DIR)/ieee1588clock.cpp $(HEADER_FILES) + $(CXX) $(CFLAGS) $(CXXFLAGS) -c $(COMMON_DIR)/ieee1588clock.cpp -o $(OBJ_DIR)/ieee1588clock.o + +$(OBJ_DIR)/ptp_message.o: $(COMMON_DIR)/ptp_message.cpp $(HEADER_FILES) + $(CXX) $(CFLAGS) $(CXXFLAGS) -c $(COMMON_DIR)/ptp_message.cpp -o $(OBJ_DIR)/ptp_message.o + +$(OBJ_DIR)/avbts_osnet.o: $(COMMON_DIR)/avbts_osnet.cpp $(HEADER_FILES) + $(CXX) $(CFLAGS) $(CXXFLAGS) -c $(COMMON_DIR)/avbts_osnet.cpp -o $(OBJ_DIR)/avbts_osnet.o + +clean: + /bin/rm -f *~ $(OBJ_DIR)/*.o $(OBJ_DIR)/daemon_cl + diff --git a/daemons/gptp/linux/build/obj/.dir b/daemons/gptp/linux/build/obj/.dir new file mode 100644 index 0000000..e69de29 diff --git a/daemons/gptp/linux/build/obj/CVS/Entries b/daemons/gptp/linux/build/obj/CVS/Entries new file mode 100644 index 0000000..508243e --- /dev/null +++ b/daemons/gptp/linux/build/obj/CVS/Entries @@ -0,0 +1,2 @@ +/.dir/1.1/Fri Sep 21 21:13:03 2012// +D diff --git a/daemons/gptp/linux/build/obj/CVS/Repository b/daemons/gptp/linux/build/obj/CVS/Repository new file mode 100644 index 0000000..1b22db8 --- /dev/null +++ b/daemons/gptp/linux/build/obj/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/linux/build/obj diff --git a/daemons/gptp/linux/build/obj/CVS/Root b/daemons/gptp/linux/build/obj/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/linux/build/obj/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/linux/build/obj/avbts_osnet.o b/daemons/gptp/linux/build/obj/avbts_osnet.o new file mode 100644 index 0000000..5aab873 Binary files /dev/null and b/daemons/gptp/linux/build/obj/avbts_osnet.o differ diff --git a/daemons/gptp/linux/build/obj/daemon_cl b/daemons/gptp/linux/build/obj/daemon_cl new file mode 100755 index 0000000..3bbe40a Binary files /dev/null and b/daemons/gptp/linux/build/obj/daemon_cl differ diff --git a/daemons/gptp/linux/build/obj/ieee1588clock.o b/daemons/gptp/linux/build/obj/ieee1588clock.o new file mode 100644 index 0000000..e9471a7 Binary files /dev/null and b/daemons/gptp/linux/build/obj/ieee1588clock.o differ diff --git a/daemons/gptp/linux/build/obj/ieee1588port.o b/daemons/gptp/linux/build/obj/ieee1588port.o new file mode 100644 index 0000000..87e0cc3 Binary files /dev/null and b/daemons/gptp/linux/build/obj/ieee1588port.o differ diff --git a/daemons/gptp/linux/build/obj/ptp_message.o b/daemons/gptp/linux/build/obj/ptp_message.o new file mode 100644 index 0000000..203bc8a Binary files /dev/null and b/daemons/gptp/linux/build/obj/ptp_message.o differ diff --git a/daemons/gptp/linux/src/CVS/Entries b/daemons/gptp/linux/src/CVS/Entries new file mode 100644 index 0000000..1c3e6b1 --- /dev/null +++ b/daemons/gptp/linux/src/CVS/Entries @@ -0,0 +1,4 @@ +/daemon_cl.cpp/1.1/Fri Sep 7 18:52:56 2012// +/linux_hal.hpp/1.1/Fri Sep 21 17:52:55 2012// +/platform.hpp/1.1/Fri Sep 7 18:52:41 2012// +D diff --git a/daemons/gptp/linux/src/CVS/Repository b/daemons/gptp/linux/src/CVS/Repository new file mode 100644 index 0000000..8a8b350 --- /dev/null +++ b/daemons/gptp/linux/src/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/linux/src diff --git a/daemons/gptp/linux/src/CVS/Root b/daemons/gptp/linux/src/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/linux/src/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/linux/src/daemon_cl.cpp b/daemons/gptp/linux/src/daemon_cl.cpp new file mode 100644 index 0000000..dc3f85a --- /dev/null +++ b/daemons/gptp/linux/src/daemon_cl.cpp @@ -0,0 +1,89 @@ +/****************************************************************************** + + Copyright (c) 2012 Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#include "ieee1588.hpp" +#include "avbts_clock.hpp" +#include "avbts_osnet.hpp" +#include "avbts_oslock.hpp" +#include "linux_hal.hpp" + +int main(int argc, char **argv) +{ + sigset_t set; + InterfaceName *ifname; + int sig; + + LinuxPCAPNetworkInterfaceFactory *default_factory = + new LinuxPCAPNetworkInterfaceFactory; + OSNetworkInterfaceFactory::registerFactory(factory_name_t("default"), + default_factory); + LinuxThreadFactory *thread_factory = new LinuxThreadFactory(); + LinuxTimerQueueFactory *timerq_factory = new LinuxTimerQueueFactory(); + LinuxLockFactory *lock_factory = new LinuxLockFactory(); + LinuxTimerFactory *timer_factory = new LinuxTimerFactory(); + LinuxConditionFactory *condition_factory = new LinuxConditionFactory(); + LinuxSimpleIPC *ipc = new LinuxSimpleIPC(); + + if (argc < 2) + return -1; + ifname = new InterfaceName(argv[1], strlen(argv[1])); + + IEEE1588Clock *clock = new IEEE1588Clock(false, timerq_factory, ipc); + HWTimestamper *timestamper = new LinuxTimestamper(); + IEEE1588Port *port = + new IEEE1588Port(clock, 1, false, timestamper, false, 0, ifname, + condition_factory, thread_factory, timer_factory, + lock_factory); + + if (!port->init_port()) { + printf("failed to initialize port \n"); + return -1; + } + port->processEvent(POWERUP); + + sigemptyset(&set); + sigaddset(&set, SIGINT); + if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) { + perror("pthread_sigmask()"); + return -1; + } + + if (sigwait(&set, &sig) != 0) { + perror("sigwait()"); + return -1; + } + + fprintf(stderr, "Exiting on %d\n", sig); + + return 0; +} diff --git a/daemons/gptp/linux/src/linux_hal.hpp b/daemons/gptp/linux/src/linux_hal.hpp new file mode 100644 index 0000000..1d3d269 --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal.hpp @@ -0,0 +1,875 @@ +/****************************************************************************** + + Copyright (c) 2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef LINUX_HAL_HPP +#define LINUX_HAL_HPP + +#include "avbts_osnet.hpp" +#include "avbts_oslock.hpp" +#include "avbts_oscondition.hpp" +#include "avbts_ostimerq.hpp" +#include "avbts_ostimer.hpp" +#include "ieee1588.hpp" + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define ONE_WAY_PHY_DELAY 400 +#define P8021AS_MULTICAST "\x01\x80\xC2\x00\x00\x0E" + +static inline Timestamp tsToTimestamp(struct timespec *ts) +{ + Timestamp ret; + if (sizeof(ts->tv_sec) > sizeof(ret.seconds_ls)) { + ret.seconds_ms = ts->tv_sec >> (sizeof(ret.seconds_ls) * 8); + ret.seconds_ls = ts->tv_sec & 0xFFFFFFFF; + ret.nanoseconds = ts->tv_nsec; + } else { + ret.seconds_ms = 0; + ret.seconds_ls = ts->tv_sec; + ret.nanoseconds = ts->tv_nsec; + } + return ret; +} + +class LinuxTimestamper:public HWTimestamper { + private: + int sd; + Timestamp crstamp_system; + Timestamp crstamp_device; + pthread_mutex_t cross_stamp_lock; + bool cross_stamp_good; + std::list < Timestamp > rxTimestampList; + public: + virtual bool HWTimestamper_init(InterfaceLabel * iface_label) { + pthread_mutex_init(&cross_stamp_lock, NULL); + sd = -1; + cross_stamp_good = false; + return true; + } + void setSocketDescriptor(int sd) { + this->sd = sd; + }; + void updateCrossStamp(Timestamp * system_time, Timestamp * device_time) { + pthread_mutex_lock(&cross_stamp_lock); + crstamp_system = *system_time; + crstamp_device = *device_time; + cross_stamp_good = true; + pthread_mutex_unlock(&cross_stamp_lock); + } + void pushRXTimestamp(Timestamp * tstamp) { + rxTimestampList.push_front(*tstamp); + } + bool post_init(int ifindex) { + int timestamp_flags = 0; + struct ifreq device; + struct hwtstamp_config hwconfig; + int err; + + memset(&device, 0, sizeof(device)); + device.ifr_ifindex = ifindex; + err = ioctl(sd, SIOCGIFNAME, &device); + if (err == -1) { + XPTPD_ERROR("Failed to get interface name: %s", + strerror(errno)); + return false; + } + + device.ifr_data = (char *)&hwconfig; + memset(&hwconfig, 0, sizeof(hwconfig)); + hwconfig.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + hwconfig.tx_type = HWTSTAMP_TX_ON; + printf("TX type = %u\n", hwconfig.tx_type); + printf("RX filter = %u\n", hwconfig.rx_filter); + err = ioctl(sd, SIOCSHWTSTAMP, &device); + if (err == -1) { + XPTPD_ERROR("Failed to configure timestamping: %s", + strerror(errno)); + return false; + } + + timestamp_flags |= SOF_TIMESTAMPING_TX_HARDWARE; + timestamp_flags |= SOF_TIMESTAMPING_RX_HARDWARE; + timestamp_flags |= SOF_TIMESTAMPING_SYS_HARDWARE; + timestamp_flags |= SOF_TIMESTAMPING_RAW_HARDWARE; + err = + setsockopt(sd, SOL_SOCKET, SO_TIMESTAMPING, + ×tamp_flags, sizeof(timestamp_flags)); + if (err == -1) { + XPTPD_ERROR + ("Failed to configure timestamping on socket: %s", + strerror(errno)); + return false; + } + + return true; + } + + virtual bool HWTimestamper_gettime(Timestamp * system_time, + Timestamp * device_time, + uint32_t * local_clock, + uint32_t * nominal_clock_rate) { + bool ret = false; + pthread_mutex_lock(&cross_stamp_lock); + if (cross_stamp_good) { + *system_time = crstamp_system; + *device_time = crstamp_device; + ret = true; + } + pthread_mutex_unlock(&cross_stamp_lock); + return ret; + } + + virtual int HWTimestamper_txtimestamp(PortIdentity * identity, + uint16_t sequenceId, + Timestamp & timestamp, + unsigned &clock_value, + bool last) { + int err; + int ret = -72; + struct msghdr msg; + struct cmsghdr *cmsg; + struct sockaddr_ll remote; + struct iovec sgentry; + struct { + struct cmsghdr cm; + char control[256]; + } control; + + if (sd == -1) + return -1; + memset(&msg, 0, sizeof(msg)); + + msg.msg_iov = &sgentry; + msg.msg_iovlen = 1; + + sgentry.iov_base = NULL; + sgentry.iov_len = 0; + + memset(&remote, 0, sizeof(remote)); + msg.msg_name = (caddr_t) & remote; + msg.msg_namelen = sizeof(remote); + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + + err = recvmsg(sd, &msg, MSG_ERRQUEUE); + if (err == -1) { + if (errno == EAGAIN) + return -72; + else + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + while (cmsg != NULL) { + if (cmsg->cmsg_level == SOL_SOCKET + && cmsg->cmsg_type == SO_TIMESTAMPING) { + struct timespec *ts_device, *ts_system; + Timestamp device, system; + ts_system = + ((struct timespec *)CMSG_DATA(cmsg)) + 1; + system = tsToTimestamp(ts_system); + ts_device = ts_system + 1; + device = tsToTimestamp(ts_device); + updateCrossStamp(&system, &device); + timestamp = device; + ret = 0; + break; + } + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + + return ret; + } + + virtual int HWTimestamper_rxtimestamp(PortIdentity * identity, + uint16_t sequenceId, + Timestamp & timestamp, + unsigned &clock_value, + bool last) { + if (rxTimestampList.empty()) + return -72; + timestamp = rxTimestampList.back(); + rxTimestampList.pop_back(); + + return 0; + } +}; + +class LinuxLock:public OSLock { + friend class LinuxLockFactory; + private: + OSLockType type; + pthread_t thread_id; + int lock_c; + pthread_mutexattr_t mta; + pthread_mutex_t mutex; + pthread_cond_t port_ready_signal; + protected: + LinuxLock() { + lock_c = NULL; + } + bool initialize(OSLockType type) { + pthread_mutexattr_init(&mta); + if (type == oslock_recursive) + pthread_mutexattr_settype(&mta, + PTHREAD_MUTEX_RECURSIVE); + lock_c = pthread_mutex_init(&mutex, &mta); + if (lock_c != 0) { + XPTPD_ERROR("Mutex initialization faile - %s\n", + strerror(errno)); + return oslock_fail; + } + return oslock_ok; + + } + OSLockResult lock() { + lock_c = pthread_mutex_lock(&mutex); + if (lock_c != 0) + return oslock_fail; + return oslock_ok; + } + OSLockResult trylock() { + lock_c = pthread_mutex_trylock(&mutex); + if (lock_c != 0) + return oslock_fail; + return oslock_ok; + } + OSLockResult unlock() { + lock_c = pthread_mutex_unlock(&mutex); + if (lock_c != 0) + return oslock_fail; + return oslock_ok; + } +}; + +class LinuxLockFactory:public OSLockFactory { + public: + OSLock * createLock(OSLockType type) { + LinuxLock *lock = new LinuxLock(); + if (lock->initialize(type) != oslock_ok) { + delete lock; + lock = NULL; + } + return lock; + } +}; + +class LinuxCondition:public OSCondition { + friend class LinuxConditionFactory; + private: + pthread_cond_t port_ready_signal; + pthread_mutex_t port_lock; + protected: + bool initialize() { + int lock_c; + pthread_cond_init(&port_ready_signal, NULL); + lock_c = pthread_mutex_init(&port_lock, NULL); + if (lock_c != 0) + return false; + return true; + } +public: + bool wait_prelock() { + pthread_mutex_lock(&port_lock); + up(); + return true; + } + bool wait() { + pthread_cond_wait(&port_ready_signal, &port_lock); + down(); + pthread_mutex_unlock(&port_lock); + return true; + } + bool signal() { + pthread_mutex_lock(&port_lock); + if (waiting()) + pthread_cond_broadcast(&port_ready_signal); + pthread_mutex_unlock(&port_lock); + return true; + } +}; + +class LinuxConditionFactory:public OSConditionFactory { + public: + OSCondition * createCondition() { + LinuxCondition *result = new LinuxCondition(); + return result->initialize() ? result : NULL; + } +}; + +class LinuxTimerQueue; + +struct TimerQueue_t; + +struct LinuxTimerQueueHandlerArg { + timer_t timer_handle; + struct sigevent sevp; + event_descriptor_t *inner_arg; + ostimerq_handler func; + int type; + bool rm; + TimerQueue_t *timer_queue; +}; + +typedef std::list < LinuxTimerQueueHandlerArg * >TimerArgList_t; + +struct TimerQueue_t { + TimerArgList_t arg_list; + pthread_mutex_t lock; +}; + +typedef std::map < int, TimerQueue_t > TimerQueueMap_t; + +void LinuxTimerQueueHandler(union sigval arg_in); + +class LinuxTimerQueue:public OSTimerQueue { + friend class LinuxTimerQueueFactory; + friend void LinuxTimerQueueHandler(union sigval arg_in); + private: + TimerQueueMap_t timerQueueMap; + TimerArgList_t retiredTimers; + bool in_callback; + protected: + LinuxTimerQueue() { + int err; + pthread_mutex_t retiredTimersLock; + pthread_mutexattr_t retiredTimersLockAttr; + err = pthread_mutexattr_init(&retiredTimersLockAttr); + if (err != 0) { + XPTPD_ERROR("mutexattr_init()"); + exit(0); + } + err = + pthread_mutexattr_settype(&retiredTimersLockAttr, + PTHREAD_MUTEX_NORMAL); + if (err != 0) { + XPTPD_ERROR("mutexattr_settype()"); + exit(0); + } + err = + pthread_mutex_init(&retiredTimersLock, + &retiredTimersLockAttr); + if (err != 0) { + XPTPD_ERROR("mutex_init()"); + exit(0); + } + }; + public: + bool addEvent(unsigned long micros, int type, ostimerq_handler func, + event_descriptor_t * arg, bool rm, unsigned *event) { + LinuxTimerQueueHandlerArg *outer_arg = + new LinuxTimerQueueHandlerArg(); + if (timerQueueMap.find(type) == timerQueueMap.end()) { + pthread_mutex_init(&timerQueueMap[type].lock, NULL); + } + outer_arg->inner_arg = arg; + outer_arg->func = func; + outer_arg->type = type; + outer_arg->timer_queue = &timerQueueMap[type]; + sigset_t set; + sigset_t oset; + int err; + timer_t timerhandle; + struct sigevent ev; + + sigemptyset(&set); + sigaddset(&set, SIGALRM); + err = pthread_sigmask(SIG_BLOCK, &set, &oset); + if (err != 0) { + XPTPD_ERROR + ("Add timer pthread_sigmask( SIG_BLOCK ... )"); + exit(0); + } + pthread_mutex_lock(&timerQueueMap[type].lock); + { + struct itimerspec its; + memset(&ev, 0, sizeof(ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_value.sival_ptr = outer_arg; + ev.sigev_notify_function = LinuxTimerQueueHandler; + ev.sigev_notify_attributes = new pthread_attr_t; + pthread_attr_init((pthread_attr_t *) ev.sigev_notify_attributes); + pthread_attr_setdetachstate((pthread_attr_t *) ev.sigev_notify_attributes, + PTHREAD_CREATE_DETACHED); + if (timer_create(CLOCK_MONOTONIC, &ev, &timerhandle) == -1) { + XPTPD_ERROR("timer_create failed - %s\n", + strerror(errno)); + exit(0); + } + outer_arg->timer_handle = timerhandle; + outer_arg->sevp = ev; + + memset(&its, 0, sizeof(its)); + its.it_value.tv_sec = micros / 1000000; + its.it_value.tv_nsec = (micros % 1000000) * 1000; + timer_settime(outer_arg->timer_handle, 0, &its, NULL); + } + timerQueueMap[type].arg_list.push_front(outer_arg); + + pthread_mutex_unlock(&timerQueueMap[type].lock); + + err = pthread_sigmask(SIG_SETMASK, &oset, NULL); + if (err != 0) { + XPTPD_ERROR + ("Add timer pthread_sigmask( SIG_SETMASK ... )"); + exit(0); + } + return true; + } + bool cancelEvent(int type, unsigned *event) { + TimerQueueMap_t::iterator iter = timerQueueMap.find(type); + if (iter == timerQueueMap.end()) + return false; + sigset_t set; + sigset_t oset; + int err; + sigemptyset(&set); + sigaddset(&set, SIGALRM); + err = pthread_sigmask(SIG_BLOCK, &set, &oset); + if (err != 0) { + XPTPD_ERROR + ("Add timer pthread_sigmask( SIG_BLOCK ... )"); + exit(0); + } + pthread_mutex_lock(&timerQueueMap[type].lock); + while (!timerQueueMap[type].arg_list.empty()) { + LinuxTimerQueueHandlerArg *del_arg = + timerQueueMap[type].arg_list.front(); + timerQueueMap[type].arg_list.pop_front(); + timer_delete(del_arg->timer_handle); + delete(pthread_attr_t *) del_arg->sevp. + sigev_notify_attributes; + if (del_arg->rm) + delete del_arg->inner_arg; + delete del_arg; + } + pthread_mutex_unlock(&timerQueueMap[type].lock); + err = pthread_sigmask(SIG_SETMASK, &oset, NULL); + if (err != 0) { + XPTPD_ERROR + ("Add timer pthread_sigmask( SIG_SETMASK ... )"); + exit(0); + } + return true; + } +}; + +void LinuxTimerQueueHandler(union sigval arg_in) +{ + LinuxTimerQueueHandlerArg *arg = + (LinuxTimerQueueHandlerArg *) arg_in.sival_ptr; + bool runnable = false; + unsigned size; + + pthread_mutex_lock(&arg->timer_queue->lock); + size = arg->timer_queue->arg_list.size(); + arg->timer_queue->arg_list.remove(arg); + if (arg->timer_queue->arg_list.size() < size) { + runnable = true; + } + pthread_mutex_unlock(&arg->timer_queue->lock); + + if (runnable) { + arg->func(arg->inner_arg); + if (arg->rm) + delete arg->inner_arg; + delete(pthread_attr_t *) arg->sevp.sigev_notify_attributes; + } +} + +class LinuxTimerQueueFactory:public OSTimerQueueFactory { + public: + virtual OSTimerQueue * createOSTimerQueue() { + LinuxTimerQueue *timerq = new LinuxTimerQueue(); + return timerq; + }; +}; + +class LinuxTimer:public OSTimer { + friend class LinuxTimerFactory; + public: + virtual unsigned long sleep(unsigned long micros) { + struct timespec req = { 0, micros }; /* Should be micros*1000 -Chris */ + nanosleep(&req, NULL); + return micros; + } + protected: + LinuxTimer() {}; +}; + +class LinuxTimerFactory:public OSTimerFactory { + public: + virtual OSTimer * createTimer() { + return new LinuxTimer(); + } +}; + +struct OSThreadArg { + OSThreadFunction func; + void *arg; + OSThreadExitCode ret; +}; + +void *OSThreadCallback(void *input) +{ + OSThreadArg *arg = (OSThreadArg *) input; + arg->ret = arg->func(arg->arg); + return 0; +} + +class LinuxThread:public OSThread { + friend class LinuxThreadFactory; + private: + + pthread_t thread_id; + OSThreadArg *arg_inner; + public: + virtual bool start(OSThreadFunction function, void *arg) { + sigset_t set; + sigset_t oset; + int err; + arg_inner = new OSThreadArg(); + arg_inner->func = function; + arg_inner->arg = arg; + sigemptyset(&set); + sigaddset(&set, SIGALRM); + err = pthread_sigmask(SIG_BLOCK, &set, &oset); + if (err != 0) { + XPTPD_ERROR + ("Add timer pthread_sigmask( SIG_BLOCK ... )"); + return false; + } + err = pthread_create(&thread_id, NULL, OSThreadCallback, + arg_inner); + if (err != 0) + return false; + sigdelset(&oset, SIGALRM); + err = pthread_sigmask(SIG_SETMASK, &oset, NULL); + if (err != 0) { + XPTPD_ERROR + ("Add timer pthread_sigmask( SIG_SETMASK ... )"); + return false; + } + + return true; + } + virtual bool join(OSThreadExitCode & exit_code) { + int err; + err = pthread_join(thread_id, NULL); + if (err != 0) + return false; + exit_code = arg_inner->ret; + delete arg_inner; + return true; + } + protected: + LinuxThread() {}; +}; + +class LinuxThreadFactory:public OSThreadFactory { + public: + OSThread * createThread() { + return new LinuxThread(); + } +}; + +class LinuxPCAPNetworkInterface:public OSNetworkInterface { + friend class LinuxPCAPNetworkInterfaceFactory; + private: + LinkLayerAddress local_addr; + int sd_event; + int sd_general; + LinuxTimestamper *timestamper; + int ifindex; + public: + virtual net_result send(LinkLayerAddress * addr, uint8_t * payload, + size_t length, bool timestamp) { + sockaddr_ll *remote = NULL; + int err; + remote = new struct sockaddr_ll; + memset(remote, 0, sizeof(*remote)); + remote->sll_family = AF_PACKET; + remote->sll_protocol = htons(PTP_ETHERTYPE); + remote->sll_ifindex = ifindex; + remote->sll_halen = ETH_ALEN; + addr->toOctetArray(remote->sll_addr); + if (timestamp) { + err = sendto(sd_event, payload, length, 0, + (sockaddr *) remote, sizeof(*remote)); + } else { + err = sendto(sd_general, payload, length, 0, + (sockaddr *) remote, sizeof(*remote)); + } + delete remote; + if (err == -1) { + XPTPD_ERROR("Failed to send: %s(%d)", strerror(errno), + errno); + return net_fatal; + } + return net_succeed; + } + + virtual net_result recv(LinkLayerAddress * addr, uint8_t * payload, + size_t & length) { + fd_set readfds; + int err; + struct msghdr msg; + struct cmsghdr *cmsg; + struct { + struct cmsghdr cm; + char control[256]; + } control; + struct sockaddr_ll remote; + struct iovec sgentry; + + struct timeval timeout = { 0, 100000 }; + + FD_ZERO(&readfds); + FD_SET(sd_event, &readfds); + + err = select(sd_event + 1, &readfds, NULL, NULL, &timeout); + if (err == 0) { + return net_trfail; + } else if (err == -1) { + if (err == EINTR) { + XPTPD_ERROR("select() recv signal"); + } else { + XPTPD_ERROR("select() failed"); + return net_fatal; + } + } + + memset(&msg, 0, sizeof(msg)); + + msg.msg_iov = &sgentry; + msg.msg_iovlen = 1; + + sgentry.iov_base = payload; + sgentry.iov_len = length; + + memset(&remote, 0, sizeof(remote)); + msg.msg_name = (caddr_t) & remote; + msg.msg_namelen = sizeof(remote); + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + + err = recvmsg(sd_event, &msg, 0); + if (err < 0) + return net_fatal; + *addr = LinkLayerAddress(remote.sll_addr); + + if (err > 0 && !(payload[0] & 0x8)) { + cmsg = CMSG_FIRSTHDR(&msg); + while (cmsg != NULL) { + if (cmsg->cmsg_level == SOL_SOCKET + && cmsg->cmsg_type == SO_TIMESTAMPING) { + struct timespec *ts_device, *ts_system; + Timestamp device, system; + ts_system = + ((struct timespec *)CMSG_DATA(cmsg)) + + 1; + system = tsToTimestamp(ts_system); + ts_device = ts_system + 1; + device = tsToTimestamp(ts_device); + timestamper->updateCrossStamp(&system, + &device); + timestamper->pushRXTimestamp(&device); + break; + } + cmsg = CMSG_NXTHDR(&msg, cmsg); + } + } + + length = err; + return net_succeed; + } + + virtual void getLinkLayerAddress(LinkLayerAddress * addr) { + *addr = local_addr; + } + + virtual unsigned getPayloadOffset() { + return 0; + } + + virtual ~ LinuxPCAPNetworkInterface() { + close(sd_event); + close(sd_general); + } + + protected: + LinuxPCAPNetworkInterface() {}; +}; + +class LinuxPCAPNetworkInterfaceFactory:public OSNetworkInterfaceFactory { + public: + virtual bool createInterface(OSNetworkInterface ** net_iface, + InterfaceLabel * label, + HWTimestamper * timestamper) { + struct ifreq device; + int err; + struct sockaddr_ll ifsock_addr; + struct packet_mreq mr_8021as; + LinkLayerAddress addr; + int ifindex; + + LinuxPCAPNetworkInterface *net_iface_l = + new LinuxPCAPNetworkInterface(); + InterfaceName *ifname = dynamic_cast < InterfaceName * >(label); + if (ifname == NULL) { + XPTPD_ERROR("ifame == NULL \n"); + return false; + } + + net_iface_l->sd_general = + socket(PF_PACKET, SOCK_DGRAM, htons(PTP_ETHERTYPE)); + if (net_iface_l->sd_general == -1) { + XPTPD_ERROR("failed to open general socket: %s \n", + strerror(errno)); + return false; + } + net_iface_l->sd_event = + socket(PF_PACKET, SOCK_DGRAM, htons(PTP_ETHERTYPE)); + if (net_iface_l->sd_event == -1) { + XPTPD_ERROR("failed to open event socket: %s \n", + strerror(errno)); + return false; + } + + memset(&device, 0, sizeof(device)); + ifname->toString(device.ifr_name, IFNAMSIZ); + err = ioctl(net_iface_l->sd_event, SIOCGIFHWADDR, &device); + if (err == -1) { + XPTPD_ERROR("Failed to get interface address: %s", + strerror(errno)); + return false; + } + addr = LinkLayerAddress(((struct sockaddr_ll *)&device.ifr_hwaddr)->sll_addr); + net_iface_l->local_addr = addr; + + err = ioctl(net_iface_l->sd_event, SIOCGIFINDEX, &device); + if (err == -1) { + XPTPD_ERROR("Failed to get interface index: %s", + strerror(errno)); + return false; + } + ifindex = device.ifr_ifindex; + net_iface_l->ifindex = ifindex; + memset(&mr_8021as, 0, sizeof(mr_8021as)); + mr_8021as.mr_ifindex = ifindex; + mr_8021as.mr_type = PACKET_MR_MULTICAST; + mr_8021as.mr_alen = 6; + memcpy(mr_8021as.mr_address, P8021AS_MULTICAST, + mr_8021as.mr_alen); + err = setsockopt(net_iface_l->sd_event, SOL_PACKET, + PACKET_ADD_MEMBERSHIP, &mr_8021as, + sizeof(mr_8021as)); + if (err == -1) { + XPTPD_ERROR + ("Unable to add PTP multicast addresses to port id: %u", + ifindex); + return false; + } + + memset(&ifsock_addr, 0, sizeof(ifsock_addr)); + ifsock_addr.sll_family = AF_PACKET; + ifsock_addr.sll_ifindex = ifindex; + ifsock_addr.sll_protocol = htons(PTP_ETHERTYPE); + err = bind(net_iface_l->sd_event, (sockaddr *) & ifsock_addr, + sizeof(ifsock_addr)); + if (err == -1) { + XPTPD_ERROR("Call to bind() failed: %s", + strerror(errno)); + return false; + } + + net_iface_l->timestamper = dynamic_cast < LinuxTimestamper * >(timestamper); + if (net_iface_l->timestamper == NULL) { + XPTPD_ERROR("timestamper == NULL\n"); + return false; + } + net_iface_l->timestamper->setSocketDescriptor(net_iface_l->sd_event); + if (!net_iface_l->timestamper->post_init(ifindex)) { + XPTPD_ERROR("post_init failed\n"); + return false; + } + *net_iface = net_iface_l; + + return true; + } +}; + +class LinuxSimpleIPC:public OS_IPC { + public: + LinuxSimpleIPC() {}; + ~LinuxSimpleIPC() {} + virtual bool init() { + return true; + } + virtual bool update(int64_t ml_phoffset, int64_t ls_phoffset, + int32_t ml_freqoffset, int32_t ls_freqoffset, + uint64_t local_time) { +#ifdef DEBUG + fprintf(stderr, + "Master-Local Phase Offset: %ld\n" + "Master-Local Frequency Offset: %d\n" + "Local-System Phase Offset: %ld\n" + "Local-System Frequency Offset: %d\n" + "Local Time: %lu\n", ml_phoffset, ml_freqoffset, + ls_phoffset, ls_freqoffset, local_time); +#endif + return true; + } +}; + +#endif diff --git a/daemons/gptp/linux/src/platform.hpp b/daemons/gptp/linux/src/platform.hpp new file mode 100644 index 0000000..eaf0654 --- /dev/null +++ b/daemons/gptp/linux/src/platform.hpp @@ -0,0 +1,46 @@ +/****************************************************************************** + + Copyright (c) 2012 Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef PLATFORM_HPP +#define PLATFORM_HPP + +#include + +#define PLAT_strncpy( dest, src, max ) strncpy( dest, src, max+1 ); + +#define PLAT_htons( s ) htons( s ) +#define PLAT_htonl( l ) htonl( l ) +#define PLAT_ntohs( s ) ntohs( s ) +#define PLAT_ntohl( l ) ntohl( l ) + +#endif diff --git a/daemons/gptp/windows/CVS/Entries b/daemons/gptp/windows/CVS/Entries new file mode 100644 index 0000000..68ce4fc --- /dev/null +++ b/daemons/gptp/windows/CVS/Entries @@ -0,0 +1,4 @@ +D/daemon_cl//// +D/x64//// +D/named_pipe_test//// +/gptp.sln/1.1/Fri Sep 21 16:52:20 2012/-kb/ diff --git a/daemons/gptp/windows/CVS/Repository b/daemons/gptp/windows/CVS/Repository new file mode 100644 index 0000000..819fa3a --- /dev/null +++ b/daemons/gptp/windows/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/windows diff --git a/daemons/gptp/windows/CVS/Root b/daemons/gptp/windows/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/windows/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/windows/daemon_cl/CVS/Entries b/daemons/gptp/windows/daemon_cl/CVS/Entries new file mode 100644 index 0000000..fb41e46 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/CVS/Entries @@ -0,0 +1,15 @@ +D/x64//// +/ReadMe.txt/1.1/Fri Sep 21 20:19:03 2012// +/daemon_cl.cpp/1.1/Fri Sep 7 19:10:38 2012// +/daemon_cl.vcxproj/1.1/Fri Sep 21 16:50:01 2012// +/daemon_cl.vcxproj.filters/1.1/Fri Sep 21 16:50:23 2012// +/daemon_cl.vcxproj.user/1.1/Fri Sep 7 18:39:51 2012// +/ipcdef.hpp/1.1/Fri Sep 7 19:11:15 2012// +/packet.cpp/1.1/Fri Sep 7 19:10:51 2012// +/packet.hpp/1.1/Fri Sep 7 19:11:26 2012// +/platform.hpp/1.1/Fri Sep 7 19:11:37 2012// +/stdafx.cpp/1.1/Fri Sep 7 18:39:51 2012// +/stdafx.h/1.1/Fri Sep 7 18:39:51 2012// +/targetver.h/1.1/Fri Sep 7 18:39:51 2012// +/tsc.hpp/1.1/Fri Sep 21 16:58:33 2012// +/windows_hal.hpp/1.1/Fri Sep 21 16:53:58 2012// diff --git a/daemons/gptp/windows/daemon_cl/CVS/Repository b/daemons/gptp/windows/daemon_cl/CVS/Repository new file mode 100644 index 0000000..d3b6fa5 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/windows/daemon_cl diff --git a/daemons/gptp/windows/daemon_cl/CVS/Root b/daemons/gptp/windows/daemon_cl/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/windows/daemon_cl/ReadMe.txt b/daemons/gptp/windows/daemon_cl/ReadMe.txt new file mode 100644 index 0000000..ae30f53 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/ReadMe.txt @@ -0,0 +1,56 @@ +======================================================================== +(C) Copyright 2009-2012 Intel Corporation, All Rights Reserved +Author: Christopher Hall +======================================================================== + +======================================================================== + CONSOLE APPLICATION : daemon_cl Project Overview +======================================================================== + +* Dependencies + + WinPCAP Developer's Pack is required for linking (WpdPack_*.zip) + WinPCAP must also be installed on any machine where the daemon runs (WinPcap_*.exe installer for windows) + +To run from the command line: + +daemon_cl.exe xx-xx-xx-xx-xx-xx + + where xx-xx-xx-xx-xx-xx is the mac address of the local interface + +* Terminology + + master - 802.1AS Grandmaster Clock + local - local network device clock (802.1AS timestamp source) + system - clock use elsewhere on a PC-like device, e.g. TSC or HPET timer + +* Interprocess Communication: + +The daemon communicates with other user processes through a named pipe. The pipe name and message format is defined in ipcdef.hpp. + +The pipe name is "gptp-update". An example is in the project named_pipe_test. + +The message format is: + + Integer64 + Integer64 + Integer32 + Integer32 + UInteger64 + +* Meaning of IPC provided values: + + master ~= local - + local ~= system - + Dmaster ~= Dlocal * (1-/1e12) + (where D denotes a delta rather than a specific value) + Dlocal ~= Dsystem * (1-/1e12) + (where D denotes a delta rather than a specific value) + +* Known Limitations: + + * There are problems with timestamp accuracy create problems using switches that impose limits on the peer rate offset + * The current driver version does not allow timestamping between the system clock (e.g. TCS) and the network device clock; + systems offsets are not valid + + diff --git a/daemons/gptp/windows/daemon_cl/daemon_cl.cpp b/daemons/gptp/windows/daemon_cl/daemon_cl.cpp new file mode 100644 index 0000000..146d0d2 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/daemon_cl.cpp @@ -0,0 +1,124 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + + +#include "ieee1588.hpp" +#include "avbts_clock.hpp" +#include "avbts_osnet.hpp" +#include "avbts_oslock.hpp" +#include "windows_hal.hpp" +#include + +#define MACSTR_LENGTH 17 + +static bool exit_flag; + +BOOL WINAPI ctrl_handler( DWORD ctrl_type ) { + bool ret; + if( ctrl_type == CTRL_C_EVENT ) { + exit_flag = true; + ret = true; + } else { + ret = false; + } + return ret; +} + +int parseMacAddr( _TCHAR *macstr, uint8_t *octet_string ) { + int i; + _TCHAR *cur = macstr; + + if( strnlen_s( macstr, MACSTR_LENGTH ) != 17 ) return -1; + + for( i = 0; i < ETHER_ADDR_OCTETS; ++i ) { + octet_string[i] = strtol( cur, &cur, 16 ) & 0xFF; + ++cur; + } + + return 0; +} + +int _tmain(int argc, _TCHAR* argv[]) +{ + bool force_slave = false; + int32_t offset = 0; + bool syntonize = false; + + // Register default network interface + WindowsPCAPNetworkInterfaceFactory *default_factory = new WindowsPCAPNetworkInterfaceFactory(); + OSNetworkInterfaceFactory::registerFactory( factory_name_t( "default" ), default_factory ); + + // Create thread, lock, timer, timerq factories + WindowsThreadFactory *thread_factory = new WindowsThreadFactory(); + WindowsTimerQueueFactory *timerq_factory = new WindowsTimerQueueFactory(); + WindowsLockFactory *lock_factory = new WindowsLockFactory(); + WindowsTimerFactory *timer_factory = new WindowsTimerFactory(); + WindowsConditionFactory *condition_factory = new WindowsConditionFactory(); + WindowsNamedPipeIPC *ipc = new WindowsNamedPipeIPC(); + if( !ipc->init() ) { + delete ipc; + ipc = NULL; + } + + // Create Low level network interface object + uint8_t local_addr_ostr[ETHER_ADDR_OCTETS]; + if( argc < 2 ) return -1; + parseMacAddr( argv[1], local_addr_ostr ); + LinkLayerAddress local_addr(local_addr_ostr); + + // Create Clock object + IEEE1588Clock *clock = new IEEE1588Clock( false, timerq_factory, ipc ); // Do not force slave + // Create HWTimestamper object + HWTimestamper *timestamper = new WindowsTimestamper(); + // Create Port Object linked to clock and low level + IEEE1588Port *port = new IEEE1588Port( clock, 1, false, timestamper, false, 0, &local_addr, + condition_factory, thread_factory, timer_factory, lock_factory ); + if( !port->init_port() ) { + printf( "Failed to initialize port\n" ); + return -1; + } + port->processEvent( POWERUP ); + + // Wait for Ctrl-C + if( !SetConsoleCtrlHandler( ctrl_handler, true )) { + printf( "Unable to register Ctrl-C handler\n" ); + return -1; + } + + while( !exit_flag ) Sleep( 1200 ); + + delete( ipc ); + + return 0; +} + diff --git a/daemons/gptp/windows/daemon_cl/daemon_cl.vcxproj b/daemons/gptp/windows/daemon_cl/daemon_cl.vcxproj new file mode 100644 index 0000000..9473646 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/daemon_cl.vcxproj @@ -0,0 +1,209 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {590D3055-A068-4B31-B4F9-B2ACC5F93663} + Win32Proj + daemon_cl + + + + Application + true + Unicode + v110 + + + Application + true + Unicode + v110 + + + Application + false + true + Unicode + v110 + + + Application + false + true + Unicode + v110 + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;WPCAP;HAVE_REMOTE + C:\Users\John\src\pcap\Include;C:\Users\John\src\gptp\common;%(AdditionalIncludeDirectories) + + + Console + true + wpcap.lib;Iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) + C:\Users\John\src\pcap\Lib;%(AdditionalLibraryDirectories) + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;WPCAP;HAVE_REMOTE + C:\Users\John\src\pcap\Include;C:\Users\John\src\gptp\common;%(AdditionalIncludeDirectories) + + + Console + true + wpcap.lib;Iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) + C:\Users\John\src\pcap\Lib;%(AdditionalLibraryDirectories) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;WPCAP;HAVE_REMOTE + C:\Users\John\src\pcap\Include;C:\Users\John\src\gptp\common;%(AdditionalIncludeDirectories) + + + Console + true + true + true + C:\Users\John\src\pcap\Lib;%(AdditionalLibraryDirectories) + wpcap.lib;Iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;WPCAP;HAVE_REMOTE + C:\Users\John\src\pcap\Include;$(SolutionDir)\daemon_cl\;..\..\..\common;%(AdditionalIncludeDirectories) + + + Console + true + true + true + C:\Users\John\src\pcap\Lib\x64;%(AdditionalLibraryDirectories) + wpcap.lib;Iphlpapi.lib;ws2_32.lib;%(AdditionalDependencies) + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + NotUsing + NotUsing + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/daemons/gptp/windows/daemon_cl/daemon_cl.vcxproj.filters b/daemons/gptp/windows/daemon_cl/daemon_cl.vcxproj.filters new file mode 100644 index 0000000..09509ef --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/daemon_cl.vcxproj.filters @@ -0,0 +1,99 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/daemons/gptp/windows/daemon_cl/daemon_cl.vcxproj.user b/daemons/gptp/windows/daemon_cl/daemon_cl.vcxproj.user new file mode 100644 index 0000000..145a860 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/daemon_cl.vcxproj.user @@ -0,0 +1,11 @@ + + + + 88-88-88-88-87-88 + WindowsLocalDebugger + + + 00-13-20-F8-84-41 + WindowsLocalDebugger + + \ No newline at end of file diff --git a/daemons/gptp/windows/daemon_cl/ipcdef.hpp b/daemons/gptp/windows/daemon_cl/ipcdef.hpp new file mode 100644 index 0000000..4ac3e32 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/ipcdef.hpp @@ -0,0 +1,88 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + + +#ifndef IPCDEF_HPP +#define IPCDEF_HPP + +#include + +#define PIPE_PREFIX "\\\\.\\pipe\\" +#define P802_1AS_PIPENAME "gptp-update" +#define OUTSTANDING_MESSAGES 10 + +#pragma pack(push,1) + +class WindowsNPipeMessage { +private: + int64_t ml_phoffset; + int64_t ls_phoffset; + int32_t ml_freqoffset; + int32_t ls_freq_offset; + uint64_t local_time; +public: + WindowsNPipeMessage() {}; + WindowsNPipeMessage( int64_t ml_phoffset, int64_t ls_phoffset, int32_t ml_freqoffset, int32_t ls_freq_offset, uint64_t local_time ) { + this->ml_phoffset = ml_phoffset; + this->ls_phoffset = ls_phoffset; + this->ml_freqoffset = ml_freqoffset; + this->ls_freq_offset = ls_freq_offset; + this->local_time = local_time; + + } + bool write( HANDLE pipe ) { + DWORD bytes_written; + DWORD last_error = ERROR_SUCCESS; + if( WriteFile( pipe, this, sizeof(*this), &bytes_written, NULL ) == 0 ) { + last_error = GetLastError(); + } + if( last_error == ERROR_SUCCESS || last_error == ERROR_PIPE_LISTENING ) { + return true; + } + return false; + } + bool read( HANDLE pipe ) { + DWORD bytes_written; + if( ReadFile( pipe, this, sizeof(*this), &bytes_written, NULL ) == 0 ) return false; + return true; + } + int64_t getMasterLocalOffset() { return ml_phoffset; } + int32_t getMasterLocalFreqOffset() { return ml_freqoffset; } + int64_t getLocalSystemOffset() { return ls_phoffset; } + int32_t getLocalSystemFreqOffset() { return ls_freq_offset; } + uint64_t getLocalTime() { return local_time; } +}; + +#pragma pack(pop) + +#endif diff --git a/daemons/gptp/windows/daemon_cl/packet.cpp b/daemons/gptp/windows/daemon_cl/packet.cpp new file mode 100644 index 0000000..dea9138 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/packet.cpp @@ -0,0 +1,207 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + + +#include "packet.hpp" +#include "platform.hpp" + +#include +#include "iphlpapi.h" + +#define MAX_FRAME_SIZE 96 + +#define WINPCAP_INTERFACENAMEPREFIX "rpcap://\\Device\\NPF_" +#define WINPCAP_INTERFACENAMEPREFIX_LENGTH 20 +#define WINPCAP_INTERFACENAMESUFFIX_LENGTH 38 +#define WINPCAP_INTERFACENAME_LENGTH WINPCAP_INTERFACENAMEPREFIX_LENGTH+WINPCAP_INTERFACENAMESUFFIX_LENGTH + +struct packet_handle { + pcap_t *iface; + char errbuf[PCAP_ERRBUF_SIZE]; + packet_addr_t iface_addr; + HANDLE capture_lock; + uint16_t ethertype; + struct bpf_program filter; +}; + + +packet_error_t mallocPacketHandle( struct packet_handle **phandle ) { + packet_error_t ret = PACKET_NO_ERROR; + + packet_handle *handle = (struct packet_handle *) malloc((size_t) sizeof( *handle )); + if( handle == NULL ) { + ret = PACKET_NOMEMORY_ERROR; + goto fnexit; + } + *phandle = handle; + + if(( handle->capture_lock = CreateMutex( NULL, FALSE, NULL )) == NULL ) { + ret = PACKET_CREATEMUTEX_ERROR; + goto fnexit; + } + handle->iface = NULL; + +fnexit: + return ret; +} + +void freePacketHandle( struct packet_handle *handle ) { + CloseHandle( handle->capture_lock ); + free((void *) handle ); +} + +packet_error_t openInterfaceByAddr( struct packet_handle *handle, packet_addr_t *addr, int timeout ) { + packet_error_t ret = PACKET_NO_ERROR; + char name[WINPCAP_INTERFACENAME_LENGTH+1] = "\0"; + + PIP_ADAPTER_ADDRESSES pAdapterAddress; + IP_ADAPTER_ADDRESSES AdapterAddress[32]; // Allocate information for up to 32 NICs + DWORD dwBufLen = sizeof(AdapterAddress); // Save memory size of buffer + + DWORD dwStatus = GetAdaptersAddresses( AF_UNSPEC, 0, NULL, AdapterAddress, &dwBufLen); + + if( dwStatus != ERROR_SUCCESS ) { + ret = PACKET_IFLOOKUP_ERROR; + goto fnexit; + } + + for( pAdapterAddress = AdapterAddress; pAdapterAddress != NULL; pAdapterAddress = pAdapterAddress->Next ) { + if( pAdapterAddress->PhysicalAddressLength == ETHER_ADDR_OCTETS && + memcmp( pAdapterAddress->PhysicalAddress, addr->addr, ETHER_ADDR_OCTETS ) == 0 ) { + break; + } + } + + if( pAdapterAddress != NULL ) { + strcpy_s( name, WINPCAP_INTERFACENAMEPREFIX ); + strncpy_s( name+WINPCAP_INTERFACENAMEPREFIX_LENGTH, WINPCAP_INTERFACENAMESUFFIX_LENGTH+1, pAdapterAddress->AdapterName, WINPCAP_INTERFACENAMESUFFIX_LENGTH ); + printf( "Opening: %s\n", name ); + handle->iface = pcap_open( name, MAX_FRAME_SIZE, PCAP_OPENFLAG_MAX_RESPONSIVENESS | PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_NOCAPTURE_LOCAL, + timeout, NULL, handle->errbuf ); + if( handle->iface == NULL ) { + ret = PACKET_IFLOOKUP_ERROR; + goto fnexit; + } + handle->iface_addr = *addr; + } else { + ret = PACKET_IFNOTFOUND_ERROR; + goto fnexit; + } + +fnexit: + return ret; +} + +void closeInterface( struct packet_handle *pfhandle ) { + if( pfhandle->iface != NULL ) pcap_close( pfhandle->iface ); +} + + +packet_error_t sendFrame( struct packet_handle *handle, packet_addr_t *addr, uint16_t ethertype, uint8_t *payload, size_t length ) { + packet_error_t ret = PACKET_NO_ERROR; + uint16_t ethertype_no = PLAT_htons( ethertype ); + uint8_t *payload_ptr = payload; + + if( length < PACKET_HDR_LENGTH ) { + ret = PACKET_BADBUFFER_ERROR; + } + + // Build Header + memcpy( payload_ptr, addr->addr, ETHER_ADDR_OCTETS ); payload_ptr+= ETHER_ADDR_OCTETS; + memcpy( payload_ptr, handle->iface_addr.addr, ETHER_ADDR_OCTETS ); payload_ptr+= ETHER_ADDR_OCTETS; + memcpy( payload_ptr, ðertype_no, sizeof( ethertype_no )); + + if( pcap_sendpacket( handle->iface, payload, (int) length+PACKET_HDR_LENGTH ) != 0 ) { + ret = PACKET_XMIT_ERROR; + goto fnexit; + } + +fnexit: + return ret; +} + +packet_error_t packetBind( struct packet_handle *handle, uint16_t ethertype ) { + packet_error_t ret = PACKET_NO_ERROR; + char filter_expression[32] = "ether proto 0x"; + + sprintf_s( filter_expression+strlen(filter_expression), 31-strlen(filter_expression), "%hx", ethertype ); + if( pcap_compile( handle->iface, &handle->filter, filter_expression, 1, 0 ) == -1 ) { + ret = PACKET_BIND_ERROR; + goto fnexit; + } + if( pcap_setfilter( handle->iface, &handle->filter ) == -1 ) { + ret = PACKET_BIND_ERROR; + goto fnexit; + } + + handle->ethertype = ethertype; + +fnexit: + return ret; +} + +// Call to recvFrame must be thread-safe. However call to pcap_next_ex() isn't because of somewhat undefined memory management semantics. +// Wrap call to pcap library with mutex +packet_error_t recvFrame( struct packet_handle *handle, packet_addr_t *addr, uint8_t *payload, size_t &length ) { + packet_error_t ret = PACKET_NO_ERROR; + struct pcap_pkthdr *hdr_r; + u_char *data; + + int pcap_result; + DWORD wait_result; + + wait_result = WaitForSingleObject( handle->capture_lock, 1000 ); + if( wait_result != WAIT_OBJECT_0 ) { + ret = PACKET_GETMUTEX_ERROR; + goto fnexit; + } + + pcap_result = pcap_next_ex( handle->iface, &hdr_r, (const u_char **) &data ); + if( pcap_result == 0 ) { + ret = PACKET_RECVTIMEOUT_ERROR; + } else if( pcap_result < 0 ) { + ret = PACKET_RECVFAILED_ERROR; + } else { + length = hdr_r->len-PACKET_HDR_LENGTH >= length ? length : hdr_r->len-PACKET_HDR_LENGTH; + memcpy( payload, data+PACKET_HDR_LENGTH, length ); + memcpy( addr->addr, data+ETHER_ADDR_OCTETS, ETHER_ADDR_OCTETS ); + } + + if( !ReleaseMutex( handle->capture_lock )) { + ret = PACKET_RLSMUTEX_ERROR; + goto fnexit; + } + +fnexit: + return ret; +} diff --git a/daemons/gptp/windows/daemon_cl/packet.hpp b/daemons/gptp/windows/daemon_cl/packet.hpp new file mode 100644 index 0000000..3e08051 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/packet.hpp @@ -0,0 +1,62 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + + +#ifndef PACKET_H +#define PACKET_H + +#include "stdint.h" + +#define ETHER_ADDR_OCTETS 6 +#define PACKET_HDR_LENGTH 14 + +typedef enum { + PACKET_NO_ERROR = 0, PACKET_NOMEMORY_ERROR, PACKET_BADBUFFER_ERROR, PACKET_XMIT_ERROR, PACKET_IFLOOKUP_ERROR, PACKET_IFNOTFOUND_ERROR, + PACKET_CREATEMUTEX_ERROR, PACKET_GETMUTEX_ERROR, PACKET_RLSMUTEX_ERROR, PACKET_RECVTIMEOUT_ERROR, PACKET_RECVFAILED_ERROR, + PACKET_BIND_ERROR +} packet_error_t; + +typedef struct { uint8_t addr[ETHER_ADDR_OCTETS]; } packet_addr_t; +typedef struct packet_handle * pfhandle_t; + +packet_error_t mallocPacketHandle( pfhandle_t *pfhandle_r ); +void freePacketHandle( pfhandle_t pfhandle ); + +packet_error_t openInterfaceByAddr( pfhandle_t pfhandle, packet_addr_t *addr, int timeout ); +void closeInterface( pfhandle_t pfhandle ); +packet_error_t sendFrame( pfhandle_t pfhandle, packet_addr_t *addr, uint16_t ethertype, uint8_t *payload, size_t length ); +packet_error_t recvFrame( pfhandle_t pfhandle, packet_addr_t *addr, uint8_t *payload, size_t &length ); + +packet_error_t packetBind( struct packet_handle *handle, uint16_t ethertype ); + +#endif /* PACKET_H */ diff --git a/daemons/gptp/windows/daemon_cl/platform.hpp b/daemons/gptp/windows/daemon_cl/platform.hpp new file mode 100644 index 0000000..bbd0fd0 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/platform.hpp @@ -0,0 +1,46 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef PLATFORM_HPP +#define PLATFORM_HPP + +#include + +#define PLAT_strncpy( dest, src, max ) strncpy_s( dest, max+1, src, _TRUNCATE ); + +#define PLAT_htons( s ) htons( s ) +#define PLAT_htonl( l ) htonl( l ) +#define PLAT_ntohs( s ) ntohs( s ) +#define PLAT_ntohl( l ) ntohl( l ) + +#endif diff --git a/daemons/gptp/windows/daemon_cl/stdafx.cpp b/daemons/gptp/windows/daemon_cl/stdafx.cpp new file mode 100644 index 0000000..a3275bf --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// daemon_cl.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/daemons/gptp/windows/daemon_cl/stdafx.h b/daemons/gptp/windows/daemon_cl/stdafx.h new file mode 100644 index 0000000..47a0d02 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: reference additional headers your program requires here diff --git a/daemons/gptp/windows/daemon_cl/targetver.h b/daemons/gptp/windows/daemon_cl/targetver.h new file mode 100644 index 0000000..90e767b --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/daemons/gptp/windows/daemon_cl/tsc.hpp b/daemons/gptp/windows/daemon_cl/tsc.hpp new file mode 100644 index 0000000..9484a09 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/tsc.hpp @@ -0,0 +1,65 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef TSC_HPP +#define TSC_HPP + +#include +#include + +#define CPUFREQ_BASE 133 + +inline unsigned __int64 PLAT_rdtsc() +{ + return __rdtsc(); +} + +// 'millis' argument specifies time to measure TSC over. A longer time is generally more reliable +// Returns TSC frequency +inline uint64_t getTSCFrequency( unsigned millis ) { + uint64_t tsc1, tsc2, multiplier; + unsigned msig, lsig; + + tsc1 = PLAT_rdtsc(); + Sleep( millis ); + tsc2 = PLAT_rdtsc(); + multiplier = (unsigned) (tsc2 - tsc1)/133; + lsig = multiplier % 1000000; + msig = (unsigned) multiplier / 1000000; + if( lsig >= 750000 ) multiplier = (msig+1)*1000000; + else if( lsig < 250000 ) multiplier = msig*1000000; + else multiplier = msig*1000000 + 500000; + return multiplier*CPUFREQ_BASE; +} + +#endif/*TSC_HPP*/ diff --git a/daemons/gptp/windows/daemon_cl/windows_hal.hpp b/daemons/gptp/windows/daemon_cl/windows_hal.hpp new file mode 100644 index 0000000..fdb1172 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/windows_hal.hpp @@ -0,0 +1,576 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#ifndef WINDOWS_HAL_HPP +#define WINDOWS_HAL_HPP + +#include "avbts_osnet.hpp" +#include "avbts_oslock.hpp" +#include "avbts_oscondition.hpp" +#include "avbts_ostimerq.hpp" +#include "avbts_ostimer.hpp" +#include "packet.hpp" +#include "ieee1588.hpp" +#include "iphlpapi.h" +#include "ipcdef.hpp" +#include "tsc.hpp" + +#include "avbts_osipc.hpp" + +#include + +#include + +class WindowsPCAPNetworkInterface : public OSNetworkInterface { + friend class WindowsPCAPNetworkInterfaceFactory; +private: + pfhandle_t handle; + LinkLayerAddress local_addr; +public: + virtual net_result send( LinkLayerAddress *addr, uint8_t *payload, size_t length, bool timestamp ) { + packet_addr_t dest; + addr->toOctetArray( dest.addr ); + if( sendFrame( handle, &dest, PTP_ETHERTYPE, payload, length ) != PACKET_NO_ERROR ) return net_fatal; + return net_succeed; + } + virtual net_result recv( LinkLayerAddress *addr, uint8_t *payload, size_t &length ) { + packet_addr_t dest; + packet_error_t pferror = recvFrame( handle, &dest, payload, length ); + if( pferror != PACKET_NO_ERROR && pferror != PACKET_RECVTIMEOUT_ERROR ) return net_fatal; + if( pferror == PACKET_RECVTIMEOUT_ERROR ) return net_trfail; + *addr = LinkLayerAddress( dest.addr ); + return net_succeed; + } + virtual void getLinkLayerAddress( LinkLayerAddress *addr ) { + *addr = local_addr; + } + virtual unsigned getPayloadOffset() { + return PACKET_HDR_LENGTH; + } + virtual ~WindowsPCAPNetworkInterface() { + closeInterface( handle ); + if( handle != NULL ) freePacketHandle( handle ); + } +protected: + WindowsPCAPNetworkInterface() { handle = NULL; }; +}; + +class WindowsPCAPNetworkInterfaceFactory : public OSNetworkInterfaceFactory { +public: + virtual bool createInterface( OSNetworkInterface **net_iface, InterfaceLabel *label, HWTimestamper *timestamper ) { + WindowsPCAPNetworkInterface *net_iface_l = new WindowsPCAPNetworkInterface(); + LinkLayerAddress *addr = dynamic_cast(label); + if( addr == NULL ) goto error_nofree; + net_iface_l->local_addr = *addr; + packet_addr_t pfaddr; + addr->toOctetArray( pfaddr.addr ); + if( mallocPacketHandle( &net_iface_l->handle ) != PACKET_NO_ERROR ) goto error_nofree; + if( openInterfaceByAddr( net_iface_l->handle, &pfaddr, 1 ) != PACKET_NO_ERROR ) goto error_free_handle; + if( packetBind( net_iface_l->handle, PTP_ETHERTYPE ) != PACKET_NO_ERROR ) goto error_free_handle; + *net_iface = net_iface_l; + + return true; + +error_free_handle: +error_nofree: + delete net_iface_l; + + return false; + } +}; + +class WindowsLock : public OSLock { + friend class WindowsLockFactory; +private: + OSLockType type; + DWORD thread_id; + HANDLE lock_c; + OSLockResult lock_l( DWORD timeout ) { + DWORD wait_result = WaitForSingleObject( lock_c, timeout ); + if( wait_result == WAIT_TIMEOUT ) return oslock_held; + else if( wait_result == WAIT_OBJECT_0 ) return oslock_ok; + else return oslock_fail; + + } + OSLockResult nonreentrant_lock_l( DWORD timeout ) { + OSLockResult result; + DWORD wait_result; + wait_result = WaitForSingleObject( lock_c, timeout ); + if( wait_result == WAIT_OBJECT_0 ) { + if( thread_id == GetCurrentThreadId() ) { + result = oslock_self; + ReleaseMutex( lock_c ); + } else { + result = oslock_ok; + thread_id = GetCurrentThreadId(); + } + } else if( wait_result == WAIT_TIMEOUT ) result = oslock_held; + else result = oslock_fail; + + return result; + } +protected: + WindowsLock() { + lock_c = NULL; + } + bool initialize( OSLockType type ) { + lock_c = CreateMutex( NULL, false, NULL ); + if( lock_c == NULL ) return false; + this->type = type; + return true; + } + OSLockResult lock() { + if( type == oslock_recursive ) { + return lock_l( INFINITE ); + } + return nonreentrant_lock_l( INFINITE ); + } + OSLockResult trylock() { + if( type == oslock_recursive ) { + return lock_l( 0 ); + } + return nonreentrant_lock_l( 0 ); + } + OSLockResult unlock() { + ReleaseMutex( lock_c ); + return oslock_ok; + } +}; + +class WindowsLockFactory : public OSLockFactory { +public: + OSLock *createLock( OSLockType type ) { + WindowsLock *lock = new WindowsLock(); + if( !lock->initialize( type )) { + delete lock; + lock = NULL; + } + return lock; + } +}; + +class WindowsCondition : public OSCondition { + friend class WindowsConditionFactory; +private: + SRWLOCK lock; + CONDITION_VARIABLE condition; +protected: + bool initialize() { + InitializeSRWLock( &lock ); + InitializeConditionVariable( &condition ); + return true; + } +public: + bool wait_prelock() { + AcquireSRWLockExclusive( &lock ); + up(); + return true; + } + bool wait() { + BOOL result = SleepConditionVariableSRW( &condition, &lock, INFINITE, 0 ); + bool ret = false; + if( result == TRUE ) { + down(); + ReleaseSRWLockExclusive( &lock ); + ret = true; + } + return ret; + } + bool signal() { + AcquireSRWLockExclusive( &lock ); + if( waiting() ) WakeAllConditionVariable( &condition ); + ReleaseSRWLockExclusive( &lock ); + return true; + } +}; + +class WindowsConditionFactory : public OSConditionFactory { +public: + OSCondition *createCondition() { + WindowsCondition *result = new WindowsCondition(); + return result->initialize() ? result : NULL; + } +}; + +class WindowsTimerQueue; + +struct TimerQueue_t; + +struct WindowsTimerQueueHandlerArg { + HANDLE timer_handle; + HANDLE queue_handle; + event_descriptor_t *inner_arg; + ostimerq_handler func; + int type; + bool rm; + WindowsTimerQueue *queue; + TimerQueue_t *timer_queue; +}; + +typedef std::list TimerArgList_t; + +struct TimerQueue_t { + TimerArgList_t arg_list; + HANDLE queue_handle; + SRWLOCK lock; +}; + + +VOID CALLBACK WindowsTimerQueueHandler( PVOID arg_in, BOOLEAN ignore ); + +typedef std::map TimerQueueMap_t; + +class WindowsTimerQueue : public OSTimerQueue { + friend class WindowsTimerQueueFactory; + friend VOID CALLBACK WindowsTimerQueueHandler( PVOID arg_in, BOOLEAN ignore ); +private: + TimerQueueMap_t timerQueueMap; + TimerArgList_t retiredTimers; + SRWLOCK retiredTimersLock; + void cleanupRetiredTimers() { + AcquireSRWLockExclusive( &retiredTimersLock ); + while( !retiredTimers.empty() ) { + WindowsTimerQueueHandlerArg *retired_arg = retiredTimers.front(); + retiredTimers.pop_front(); + ReleaseSRWLockExclusive( &retiredTimersLock ); + DeleteTimerQueueTimer( retired_arg->queue_handle, retired_arg->timer_handle, INVALID_HANDLE_VALUE ); + if( retired_arg->rm ) delete retired_arg->inner_arg; + delete retired_arg; + AcquireSRWLockExclusive( &retiredTimersLock ); + } + ReleaseSRWLockExclusive( &retiredTimersLock ); + + } +protected: + WindowsTimerQueue() { + InitializeSRWLock( &retiredTimersLock ); + }; +public: + bool addEvent( unsigned long micros, int type, ostimerq_handler func, event_descriptor_t *arg, bool rm, unsigned *event ) { + WindowsTimerQueueHandlerArg *outer_arg = new WindowsTimerQueueHandlerArg(); + cleanupRetiredTimers(); + if( timerQueueMap.find(type) == timerQueueMap.end() ) { + timerQueueMap[type].queue_handle = CreateTimerQueue(); + InitializeSRWLock( &timerQueueMap[type].lock ); + } + outer_arg->queue_handle = timerQueueMap[type].queue_handle; + outer_arg->inner_arg = arg; + outer_arg->func = func; + outer_arg->queue = this; + outer_arg->type = type; + outer_arg->timer_queue = &timerQueueMap[type]; + AcquireSRWLockExclusive( &timerQueueMap[type].lock ); + CreateTimerQueueTimer( &outer_arg->timer_handle, timerQueueMap[type].queue_handle, WindowsTimerQueueHandler, (void *) outer_arg, micros/1000, 0, 0 ); + timerQueueMap[type].arg_list.push_front(outer_arg); + ReleaseSRWLockExclusive( &timerQueueMap[type].lock ); + return true; + } + bool cancelEvent( int type, unsigned *event ) { + TimerQueueMap_t::iterator iter = timerQueueMap.find( type ); + if( iter == timerQueueMap.end() ) return false; + AcquireSRWLockExclusive( &timerQueueMap[type].lock ); + while( ! timerQueueMap[type].arg_list.empty() ) { + WindowsTimerQueueHandlerArg *del_arg = timerQueueMap[type].arg_list.front(); + timerQueueMap[type].arg_list.pop_front(); + ReleaseSRWLockExclusive( &timerQueueMap[type].lock ); + DeleteTimerQueueTimer( del_arg->queue_handle, del_arg->timer_handle, INVALID_HANDLE_VALUE ); + if( del_arg->rm ) delete del_arg->inner_arg; + delete del_arg; + AcquireSRWLockExclusive( &timerQueueMap[type].lock ); + } + ReleaseSRWLockExclusive( &timerQueueMap[type].lock ); + + return true; + } +}; + +VOID CALLBACK WindowsTimerQueueHandler( PVOID arg_in, BOOLEAN ignore ) { + WindowsTimerQueueHandlerArg *arg = (WindowsTimerQueueHandlerArg *) arg_in; + arg->func( arg->inner_arg ); + + // Remove myself from unexpired timer queue + AcquireSRWLockExclusive( &arg->timer_queue->lock ); + arg->timer_queue->arg_list.remove( arg ); + ReleaseSRWLockExclusive( &arg->timer_queue->lock ); + + // Add myself to the expired timer queue + AcquireSRWLockExclusive( &arg->queue->retiredTimersLock ); + arg->queue->retiredTimers.push_front( arg ); + ReleaseSRWLockExclusive( &arg->queue->retiredTimersLock ); +} + +class WindowsTimerQueueFactory : public OSTimerQueueFactory { +public: + virtual OSTimerQueue *createOSTimerQueue() { + WindowsTimerQueue *timerq = new WindowsTimerQueue(); + return timerq; + }; +}; + +class WindowsTimer : public OSTimer { + friend class WindowsTimerFactory; +public: + virtual unsigned long sleep( unsigned long micros ) { + Sleep( micros/1000 ); + return micros; + } +protected: + WindowsTimer() {}; +}; + +class WindowsTimerFactory : public OSTimerFactory { +public: + virtual OSTimer *createTimer() { + return new WindowsTimer(); + } +}; + +struct OSThreadArg { + OSThreadFunction func; + void *arg; + OSThreadExitCode ret; +}; + +DWORD WINAPI OSThreadCallback( LPVOID input ) { + OSThreadArg *arg = (OSThreadArg*) input; + arg->ret = arg->func( arg->arg ); + return 0; +} + +class WindowsThread : public OSThread { + friend class WindowsThreadFactory; +private: + HANDLE thread_id; + OSThreadArg *arg_inner; +public: + virtual bool start( OSThreadFunction function, void *arg ) { + arg_inner = new OSThreadArg(); + arg_inner->func = function; + arg_inner->arg = arg; + thread_id = CreateThread( NULL, 0, OSThreadCallback, arg_inner, 0, NULL ); + if( thread_id == NULL ) return false; + else return true; + } + virtual bool join( OSThreadExitCode &exit_code ) { + if( WaitForSingleObject( thread_id, INFINITE ) != WAIT_OBJECT_0 ) return false; + exit_code = arg_inner->ret; + delete arg_inner; + return true; + } +protected: + WindowsThread() {}; +}; + +class WindowsThreadFactory : public OSThreadFactory { +public: + OSThread *createThread() { + return new WindowsThread(); + } +}; + +#define NETCLOCK_HZ 1056000000 +#define ONE_WAY_PHY_DELAY 8000 + +#define NETWORK_CARD_ID_PREFIX "\\\\.\\" +#define OID_INTEL_GET_RXSTAMP 0xFF020264 +#define OID_INTEL_GET_TXSTAMP 0xFF020263 +#define OID_INTEL_GET_SYSTIM 0xFF020262 +#define OID_INTEL_SET_SYSTIM 0xFF020261 + +class WindowsTimestamper : public HWTimestamper { +private: + // No idea whether the underlying implementation is thread safe + HANDLE miniport; + LARGE_INTEGER tsc_hz; + DWORD readOID( NDIS_OID oid, void *output_buffer, DWORD size, DWORD *size_returned ) { + NDIS_OID oid_l = oid; + DWORD rc = DeviceIoControl( + miniport, + IOCTL_NDIS_QUERY_GLOBAL_STATS, + &oid_l, + sizeof(oid_l), + output_buffer, + size, + size_returned, + NULL ); + if( rc == 0 ) return GetLastError(); + return ERROR_SUCCESS; + } + Timestamp nanoseconds64ToTimestamp( uint64_t time ) { + Timestamp timestamp; + timestamp.nanoseconds = time % 1000000000; + timestamp.seconds_ls = (time / 1000000000) & 0xFFFFFFFF; + timestamp.seconds_ms = (uint16_t)((time / 1000000000) >> 32); + return timestamp; + } + uint64_t scaleNativeClockToNanoseconds( uint64_t time ) { + long double scaled_output = ((long double)NETCLOCK_HZ)/1000000000; + scaled_output = ((long double) time)/scaled_output; + return (uint64_t) scaled_output; + } + uint64_t scaleTSCClockToNanoseconds( uint64_t time ) { + long double scaled_output = ((long double)tsc_hz.QuadPart)/1000000000; + scaled_output = ((long double) time)/scaled_output; + return (uint64_t) scaled_output; + } +public: + virtual bool HWTimestamper_init( InterfaceLabel *iface_label ) { + char network_card_id[64]; + LinkLayerAddress *addr = dynamic_cast(iface_label); + if( addr == NULL ) return false; + PIP_ADAPTER_ADDRESSES pAdapterAddress; + IP_ADAPTER_ADDRESSES AdapterAddress[32]; // Allocate information for up to 32 NICs + DWORD dwBufLen = sizeof(AdapterAddress); // Save memory size of buffer + + DWORD dwStatus = GetAdaptersAddresses( AF_UNSPEC, 0, NULL, AdapterAddress, &dwBufLen); + if( dwStatus != ERROR_SUCCESS ) return false; + + for( pAdapterAddress = AdapterAddress; pAdapterAddress != NULL; pAdapterAddress = pAdapterAddress->Next ) { + if( pAdapterAddress->PhysicalAddressLength == ETHER_ADDR_OCTETS && *addr == LinkLayerAddress( pAdapterAddress->PhysicalAddress )) { + break; + } + } + + if( pAdapterAddress == NULL ) return false; + + PLAT_strncpy( network_card_id, NETWORK_CARD_ID_PREFIX, 63 ); + PLAT_strncpy( network_card_id+strlen(network_card_id), pAdapterAddress->AdapterName, 63-strlen(network_card_id) ); + + miniport = CreateFile( network_card_id, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL ); + if( miniport == INVALID_HANDLE_VALUE ) return false; + + tsc_hz.QuadPart = getTSCFrequency( 1000 ); + + return true; + } + virtual bool HWTimestamper_gettime( Timestamp *system_time, Timestamp *device_time, uint32_t *local_clock, uint32_t *nominal_clock_rate ) + { + DWORD buf[6]; + DWORD returned; + uint64_t now_net, now_tsc; + DWORD result; + + memset( buf, 0xFF, sizeof( buf )); + if(( result = readOID( OID_INTEL_GET_SYSTIM, buf, sizeof(buf), &returned )) != ERROR_SUCCESS ) return false; + + now_net = (((uint64_t)buf[1]) << 32) | buf[0]; + now_net = scaleNativeClockToNanoseconds( now_net ); + *device_time = nanoseconds64ToTimestamp( now_net ); + + now_tsc = (((uint64_t)buf[3]) << 32) | buf[2]; + now_tsc = scaleTSCClockToNanoseconds( now_tsc ); + *system_time = nanoseconds64ToTimestamp( now_tsc ); + + return true; + } + + virtual int HWTimestamper_txtimestamp( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, unsigned &clock_value, bool last ) + { + DWORD buf[8], buf_tmp[8]; + DWORD returned = 0; + uint64_t tx_r,tx_s; + DWORD result; + while(( result = readOID( OID_INTEL_GET_TXSTAMP, buf_tmp, sizeof(buf_tmp), &returned )) == ERROR_SUCCESS ) { + memcpy( buf, buf_tmp, sizeof( buf )); + } + if( result != ERROR_GEN_FAILURE ) return -1; + if( returned == 0 ) return -72; + tx_r = (((uint64_t)buf[1]) << 32) | buf[0]; + tx_s = scaleNativeClockToNanoseconds( tx_r ); + tx_s += ONE_WAY_PHY_DELAY; + timestamp = nanoseconds64ToTimestamp( tx_s ); + //fprintf( stderr, "@@@SI,%hu,%u\n", sequenceId, buf[3] ); + //fprintf( stderr, "@@TXR,%u,%u,%u,%hu,%llu,%hu,%hu\n", timestamp.seconds_ms, timestamp.seconds_ls, + // timestamp.nanoseconds, 0, tx_r, sequenceId, buf[3] ); + + return 0; + } + + virtual int HWTimestamper_rxtimestamp( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, unsigned &clock_value, bool last ) + { + DWORD buf[4], buf_tmp[4]; + DWORD returned; + uint64_t rx_r,rx_s; + DWORD result; + uint16_t packet_sequence_id; + while(( result = readOID( OID_INTEL_GET_RXSTAMP, buf_tmp, sizeof(buf_tmp), &returned )) == ERROR_SUCCESS ) { + memcpy( buf, buf_tmp, sizeof( buf )); + } + if( result != ERROR_GEN_FAILURE ) return -1; + if( returned == 0 ) return -72; + packet_sequence_id = *((uint32_t *) buf+3) >> 16; + if( PLAT_ntohs( packet_sequence_id ) != sequenceId ) return -72; + rx_r = (((uint64_t)buf[1]) << 32) | buf[0]; + rx_s = scaleNativeClockToNanoseconds( rx_r ); + rx_s -= ONE_WAY_PHY_DELAY; + timestamp = nanoseconds64ToTimestamp( rx_s ); + //fprintf( stderr, "@@RXR,%u,%u,%u,%hu,%llu\n", timestamp.seconds_ms, timestamp.seconds_ls, + // timestamp.nanoseconds, PLAT_ntohs(packet_sequence_id), rx_r ); + + return 0; + } +}; + + + +class WindowsNamedPipeIPC : public OS_IPC { +private: + HANDLE pipe; +public: + WindowsNamedPipeIPC() { }; + ~WindowsNamedPipeIPC() { + CloseHandle( pipe ); + } + virtual bool init() { + char pipename[64]; + PLAT_strncpy( pipename, PIPE_PREFIX, 63 ); + PLAT_strncpy( pipename+strlen(pipename), P802_1AS_PIPENAME, 63-strlen(pipename) ); + pipe = CreateNamedPipe( pipename, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE, PIPE_UNLIMITED_INSTANCES, + OUTSTANDING_MESSAGES*sizeof( WindowsNPipeMessage ), 0, 0, NULL ); + if( pipe == INVALID_HANDLE_VALUE ) return false; + return true; + } + virtual bool update( int64_t ml_phoffset, int64_t ls_phoffset, int32_t ml_freqoffset, int32_t ls_freq_offset, uint64_t local_time ) { + WindowsNPipeMessage msg( ml_phoffset, ls_phoffset, ml_freqoffset, ls_freq_offset, local_time ); + if( !msg.write( pipe )) { + CloseHandle(pipe); + return init(); + } + return true; + } +}; + +#endif diff --git a/daemons/gptp/windows/daemon_cl/x64/CVS/Entries b/daemons/gptp/windows/daemon_cl/x64/CVS/Entries new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/x64/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/daemons/gptp/windows/daemon_cl/x64/CVS/Repository b/daemons/gptp/windows/daemon_cl/x64/CVS/Repository new file mode 100644 index 0000000..0120903 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/x64/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/windows/daemon_cl/x64 diff --git a/daemons/gptp/windows/daemon_cl/x64/CVS/Root b/daemons/gptp/windows/daemon_cl/x64/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/windows/daemon_cl/x64/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/windows/gptp.sln b/daemons/gptp/windows/gptp.sln new file mode 100644 index 0000000..15e2131 --- /dev/null +++ b/daemons/gptp/windows/gptp.sln @@ -0,0 +1,21 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "daemon_cl", "daemon_cl\daemon_cl.vcxproj", "{590D3055-A068-4B31-B4F9-B2ACC5F93663}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_pipe_test", "named_pipe_test\named_pipe_test.vcxproj", "{303FACBB-2A44-4511-A855-2B5B2C0E3A89}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Release|x64.ActiveCfg = Release|x64 + {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Release|x64.Build.0 = Release|x64 + {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Release|x64.ActiveCfg = Release|x64 + {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/daemons/gptp/windows/named_pipe_test/CVS/Entries b/daemons/gptp/windows/named_pipe_test/CVS/Entries new file mode 100644 index 0000000..95ee666 --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/CVS/Entries @@ -0,0 +1,9 @@ +/ReadMe.txt/1.1/Fri Sep 21 20:20:49 2012// +/named_pipe_test.cpp/1.1/Fri Sep 21 20:21:47 2012// +/named_pipe_test.vcxproj/1.1/Fri Sep 21 16:52:35 2012// +/named_pipe_test.vcxproj.filters/1.1/Fri Sep 7 18:39:51 2012// +/named_pipe_test.vcxproj.user/1.1/Fri Sep 7 18:39:51 2012// +/stdafx.cpp/1.1/Fri Sep 7 18:39:51 2012// +/stdafx.h/1.1/Fri Sep 7 18:39:51 2012// +/targetver.h/1.1/Fri Sep 7 18:39:51 2012// +D diff --git a/daemons/gptp/windows/named_pipe_test/CVS/Repository b/daemons/gptp/windows/named_pipe_test/CVS/Repository new file mode 100644 index 0000000..2e82842 --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/windows/named_pipe_test diff --git a/daemons/gptp/windows/named_pipe_test/CVS/Root b/daemons/gptp/windows/named_pipe_test/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/windows/named_pipe_test/ReadMe.txt b/daemons/gptp/windows/named_pipe_test/ReadMe.txt new file mode 100644 index 0000000..ad4c1ba --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/ReadMe.txt @@ -0,0 +1,10 @@ +======================================================================== +(C) Copyright 2009-2012 Intel Corporation, All Rights Reserved +Author: Christopher Hall +======================================================================== + +======================================================================== + CONSOLE APPLICATION : named_pipe_test Project Overview +======================================================================== + +An example application to interface with gptp/daemon_cl. See ipcdef.hpp for message details. diff --git a/daemons/gptp/windows/named_pipe_test/named_pipe_test.cpp b/daemons/gptp/windows/named_pipe_test/named_pipe_test.cpp new file mode 100644 index 0000000..2247cba --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/named_pipe_test.cpp @@ -0,0 +1,114 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#include "stdafx.h" +#include "ipcdef.hpp" +#include "tsc.hpp" + +#define PIPE_PREFIX "\\\\.\\pipe\\" +#define P802_1AS_PIPENAME "gptp-update" +#define OUTSTANDING_MESSAGES 10 + +static bool exit_flag; + +BOOL WINAPI ctrl_handler( DWORD ctrl_type ) { + bool ret; + if( ctrl_type == CTRL_C_EVENT ) { + exit_flag = true; + ret = true; + } else { + ret = false; + } + return ret; +} + +uint64_t scaleTSCClockToNanoseconds( uint64_t tsc_value, uint64_t tsc_frequency ) { + long double scaled_output = ((long double)tsc_frequency)/1000000000; + scaled_output = ((long double) tsc_value)/scaled_output; + return (uint64_t) scaled_output; +} +int _tmain(int argc, _TCHAR* argv[]) +{ + char pipename[64]; + strcpy_s( pipename, 64, PIPE_PREFIX ); + strcat_s( pipename, 64-strlen(pipename), P802_1AS_PIPENAME ); + WindowsNPipeMessage msg; + HANDLE pipe; + uint64_t tsc_frequency = getTSCFrequency( 1000 ); + + pipe = CreateFile( pipename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if( pipe == INVALID_HANDLE_VALUE ) { + printf( "Failed to open gptp handle, %d\n", GetLastError() ); + } + + + // Wait for Ctrl-C + if( !SetConsoleCtrlHandler( ctrl_handler, true )) { + printf( "Unable to register Ctrl-C handler\n" ); + return -1; + } + + printf( "TSC Frequency: %llu\n", tsc_frequency ); + while( msg.read( pipe ) == true && !exit_flag ) { + uint64_t now_tscns, now_8021as; + uint64_t update_tscns, update_8021as; + unsigned delta_tscns, delta_8021as; + long double ml_ratio, ls_ratio; +#if 0 + printf( "Master-Local Offset = %lld\n", msg.getMasterLocalOffset() ); + printf( "Master-Local Frequency Offset = %d\n", msg.getMasterLocalFreqOffset() ); + printf( "Local-System Offset = %lld\n", msg.getLocalSystemOffset() ); + printf( "Local-System Frequency Offset = %d\n", msg.getLocalSystemFreqOffset() ); + printf( "Local Time = %llu\n", msg.getLocalTime() ); +#endif + now_tscns = scaleTSCClockToNanoseconds( PLAT_rdtsc(), tsc_frequency ); + update_tscns = msg.getLocalTime() + msg.getLocalSystemOffset(); + update_8021as = msg.getLocalTime() - msg.getMasterLocalOffset(); + delta_tscns = (unsigned)(now_tscns - update_tscns); + ml_ratio = -1*(((long double)msg.getMasterLocalFreqOffset())/1000000000000)+1; + ls_ratio = -1*(((long double)msg.getLocalSystemFreqOffset())/1000000000000)+1; + delta_8021as = (unsigned)(ml_ratio*ls_ratio*delta_tscns); + now_8021as = update_8021as + delta_8021as; + printf( "Time now in terms of TSC scaled to nanoseconds time: %llu\n", now_tscns ); + printf( "Last update time in terms of 802.1AS time: %llu\n", update_8021as ); + printf( "TSC delta scaled to ns: %u\n", delta_tscns ); + printf( "8021as delta scaled: %u\n", delta_8021as ); + printf( "Time now in terms of 802.1AS time: %llu\n", now_8021as ); + } + + printf( "Closing pipe\n" ); + CloseHandle( pipe ); + + return 0; +} + diff --git a/daemons/gptp/windows/named_pipe_test/named_pipe_test.vcxproj b/daemons/gptp/windows/named_pipe_test/named_pipe_test.vcxproj new file mode 100644 index 0000000..05b568f --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/named_pipe_test.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {303FACBB-2A44-4511-A855-2B5B2C0E3A89} + Win32Proj + named_pipe_test + + + + Application + true + Unicode + v110 + + + Application + true + Unicode + v110 + + + Application + false + true + Unicode + v110 + + + Application + false + true + Unicode + v110 + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + + + C:\Users\John\src\gptp\windows\gptp\daemon_cl;%(AdditionalIncludeDirectories) + + + Console + true + + + + + Use + Level3 + Disabled + + + C:\Users\John\src\gptp\windows\gptp\daemon_cl;%(AdditionalIncludeDirectories) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE + C:\Users\John\src\gptp\windows\gptp\daemon_cl;%(AdditionalIncludeDirectories) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE + ..\daemon_cl;%(AdditionalIncludeDirectories) + + + Console + true + true + true + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/daemons/gptp/windows/named_pipe_test/named_pipe_test.vcxproj.filters b/daemons/gptp/windows/named_pipe_test/named_pipe_test.vcxproj.filters new file mode 100644 index 0000000..c03b555 --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/named_pipe_test.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/daemons/gptp/windows/named_pipe_test/named_pipe_test.vcxproj.user b/daemons/gptp/windows/named_pipe_test/named_pipe_test.vcxproj.user new file mode 100644 index 0000000..695b5c7 --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/named_pipe_test.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/daemons/gptp/windows/named_pipe_test/stdafx.cpp b/daemons/gptp/windows/named_pipe_test/stdafx.cpp new file mode 100644 index 0000000..26915d0 --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// named_pipe_test.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/daemons/gptp/windows/named_pipe_test/stdafx.h b/daemons/gptp/windows/named_pipe_test/stdafx.h new file mode 100644 index 0000000..d2509e4 --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include +#include + + + +// TODO: reference additional headers your program requires here diff --git a/daemons/gptp/windows/named_pipe_test/targetver.h b/daemons/gptp/windows/named_pipe_test/targetver.h new file mode 100644 index 0000000..90e767b --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/daemons/gptp/windows/named_pipe_test/x64/Release/named_pipe_test.Build.CppClean.log b/daemons/gptp/windows/named_pipe_test/x64/Release/named_pipe_test.Build.CppClean.log new file mode 100644 index 0000000..b1d446f --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/x64/Release/named_pipe_test.Build.CppClean.log @@ -0,0 +1,16 @@ +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\cl.command.1.tlog +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\CL.read.1.tlog +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\CL.write.1.tlog +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\link.command.1.tlog +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\link.read.1.tlog +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\link.write.1.tlog +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\mt.command.1.tlog +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\mt.read.1.tlog +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\mt.write.1.tlog +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\named_pipe_test.exe.intermediate.manifest +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\named_pipe_test.obj +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\named_pipe_test.pch +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\x64\Release\stdafx.obj +\\DATAGROVEJF\STG\USERS\CHRISH\GPTP_BZR\MAIN\WINDOWS\GPTP\NAMED_PIPE_TEST\X64\RELEASE\VC100.PDB +\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\x64\Release\named_pipe_test.exe +\\DATAGROVEJF\STG\USERS\CHRISH\GPTP_BZR\MAIN\WINDOWS\GPTP\X64\RELEASE\NAMED_PIPE_TEST.PDB diff --git a/daemons/gptp/windows/named_pipe_test/x64/Release/named_pipe_test.log b/daemons/gptp/windows/named_pipe_test/x64/Release/named_pipe_test.log new file mode 100644 index 0000000..d644b10 --- /dev/null +++ b/daemons/gptp/windows/named_pipe_test/x64/Release/named_pipe_test.log @@ -0,0 +1,9 @@ +Build started 9/5/2012 6:17:28 PM. + 1>Project "\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\named_pipe_test.vcxproj" on node 2 (clean target(s)). + 1>_PrepareForClean: + Deleting file "x64\Release\named_pipe_test.lastbuildstate". + 1>Done Building Project "\\datagrovejf\STG\USERS\Chrish\gptp_bzr\main\windows\gptp\named_pipe_test\named_pipe_test.vcxproj" (clean target(s)). + +Build succeeded. + +Time Elapsed 00:00:00.30 diff --git a/daemons/gptp/windows/x64/CVS/Entries b/daemons/gptp/windows/x64/CVS/Entries new file mode 100644 index 0000000..1784810 --- /dev/null +++ b/daemons/gptp/windows/x64/CVS/Entries @@ -0,0 +1 @@ +D diff --git a/daemons/gptp/windows/x64/CVS/Repository b/daemons/gptp/windows/x64/CVS/Repository new file mode 100644 index 0000000..76c2143 --- /dev/null +++ b/daemons/gptp/windows/x64/CVS/Repository @@ -0,0 +1 @@ +linux_igb_avb/daemons/gptp/windows/x64 diff --git a/daemons/gptp/windows/x64/CVS/Root b/daemons/gptp/windows/x64/CVS/Root new file mode 100644 index 0000000..beb56f8 --- /dev/null +++ b/daemons/gptp/windows/x64/CVS/Root @@ -0,0 +1 @@ +:pserver:ekmann@azusa.jf.intel.com:/home/cvsroot/ladsw diff --git a/daemons/gptp/windows/x64/Release/daemon_cl.map b/daemons/gptp/windows/x64/Release/daemon_cl.map new file mode 100644 index 0000000..0325541 --- /dev/null +++ b/daemons/gptp/windows/x64/Release/daemon_cl.map @@ -0,0 +1,732 @@ + daemon_cl + + Timestamp is 5047f856 (Wed Sep 05 18:11:50 2012) + + Preferred load address is 0000000140000000 + + Start Length Name Class + 0001:00000000 00009f5eH .text CODE + 0001:00009f60 0000040cH .text$x CODE + 0001:0000a370 000000b2H .text$yc CODE + 0001:0000a430 0000005fH .text$yd CODE + 0002:00000000 00000328H .idata$5 DATA + 0002:00000328 00000008H .CRT$XCA DATA + 0002:00000330 00000008H .CRT$XCAA DATA + 0002:00000338 00000018H .CRT$XCU DATA + 0002:00000350 00000008H .CRT$XCZ DATA + 0002:00000358 00000008H .CRT$XIA DATA + 0002:00000360 00000008H .CRT$XIAA DATA + 0002:00000368 00000008H .CRT$XIY DATA + 0002:00000370 00000008H .CRT$XIZ DATA + 0002:00000380 00001020H .rdata DATA + 0002:000013a0 0000006cH .rdata$debug DATA + 0002:00001410 0000113cH .rdata$r DATA + 0002:00002550 00000008H .rtc$IAA DATA + 0002:00002558 00000008H .rtc$IZZ DATA + 0002:00002560 00000008H .rtc$TAA DATA + 0002:00002568 00000008H .rtc$TZZ DATA + 0002:00002570 000011e0H .xdata DATA + 0002:00003750 00000084H .xdata$x DATA + 0002:000037d4 00000078H .idata$2 DATA + 0002:0000384c 00000014H .idata$3 DATA + 0002:00003860 00000328H .idata$4 DATA + 0002:00003b88 000006daH .idata$6 DATA + 0002:00004262 00000000H .edata DATA + 0003:00000000 00000714H .data DATA + 0003:00000720 00000600H .bss DATA + 0004:00000000 000009e4H .pdata DATA + + Address Publics by Value Rva+Base Lib:Object + + 0000:00000000 ___safe_se_handler_count 0000000000000000 + 0000:00000000 ___safe_se_handler_table 0000000000000000 + 0000:00000000 __ImageBase 0000000140000000 + 0001:00000000 ??1bad_alloc@std@@UEAA@XZ 0000000140001000 f i avbts_osnet.obj + 0001:00000020 ??_Gbad_alloc@std@@UEAAPEAXI@Z 0000000140001020 f i avbts_osnet.obj + 0001:00000020 ??_Ebad_alloc@std@@UEAAPEAXI@Z 0000000140001020 f i CIL library: CIL module + 0001:00000060 ??0?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAA@AEBU?$less@Vfactory_name_t@@@1@AEBV?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@1@@Z 0000000140001060 f i avbts_osnet.obj + 0001:00000100 ??1?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAA@XZ 0000000140001100 f i avbts_osnet.obj + 0001:00000110 ?erase@?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@@2@V?$_Tree_const_iterator@V?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@@2@0@Z 0000000140001110 f i avbts_osnet.obj + 0001:000001d0 ?erase@?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@@2@V?$_Tree_const_iterator@V?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@@2@@Z 00000001400011d0 f i avbts_osnet.obj + 0001:00000520 ?clear@?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAAXXZ 0000000140001520 f i avbts_osnet.obj + 0001:000005a0 ?_Erase@?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@IEAAXPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@2@@Z 00000001400015a0 f i avbts_osnet.obj + 0001:00000600 ?_Lrotate@?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@IEAAXPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@2@@Z 0000000140001600 f i avbts_osnet.obj + 0001:00000660 ?_Rrotate@?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@IEAAXPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@2@@Z 0000000140001660 f i avbts_osnet.obj + 0001:000006c0 ??0bad_alloc@std@@QEAA@AEBV01@@Z 00000001400016c0 f i avbts_osnet.obj + 0001:000006f0 ?timerq_handler@@YAXPEAX@Z 00000001400016f0 f ieee1588clock.obj + 0001:00000700 ?addEventTimer@IEEE1588Clock@@QEAAXPEAVIEEE1588Port@@W4Event@@_K@Z 0000000140001700 f ieee1588clock.obj + 0001:000007a0 ?isBetterThan@IEEE1588Clock@@QEAA_NPEAVPTPMessageAnnounce@@@Z 00000001400017a0 f ieee1588clock.obj + 0001:00000870 ??_EInterfaceLabel@@UEAAPEAXI@Z 0000000140001870 f i CIL library: CIL module + 0001:00000870 ??_GLinkLayerAddress@@UEAAPEAXI@Z 0000000140001870 f i ieee1588port.obj + 0001:00000870 ??_ELinkLayerAddress@@UEAAPEAXI@Z 0000000140001870 f i CIL library: CIL module + 0001:00000870 ??_GInterfaceLabel@@UEAAPEAXI@Z 0000000140001870 f i ieee1588port.obj + 0001:000008a0 ?pow@@YANNH@Z 00000001400018a0 f i ieee1588port.obj + 0001:000008e0 ??1LinkLayerAddress@@UEAA@XZ 00000001400018e0 f i ieee1588port.obj + 0001:000008f0 ?openPortWrapper@@YA?AW4OSThreadExitCode@@PEAX@Z 00000001400018f0 f ieee1588port.obj + 0001:00000910 ??1?$map@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@@std@@QEAA@XZ 0000000140001910 f i ieee1588port.obj + 0001:00000950 ??0IEEE1588Port@@QEAA@PEAVIEEE1588Clock@@G_NPEAVHWTimestamper@@1HPEAVInterfaceLabel@@PEAVOSConditionFactory@@PEAVOSThreadFactory@@PEAVOSTimerFactory@@PEAVOSLockFactory@@@Z 0000000140001950 f ieee1588port.obj + 0001:00000b40 ?init_port@IEEE1588Port@@QEAA_NXZ 0000000140001b40 f ieee1588port.obj + 0001:00000cc0 ?openPort@IEEE1588Port@@QEAAPEAXXZ 0000000140001cc0 f ieee1588port.obj + 0001:00000e20 ?processEvent@IEEE1588Port@@QEAAXW4Event@@@Z 0000000140001e20 f ieee1588port.obj + 0001:00001cc0 ?calculateERBest@IEEE1588Port@@QEAAPEAVPTPMessageAnnounce@@XZ 0000000140002cc0 f ieee1588port.obj + 0001:00001d90 ?recommendState@IEEE1588Port@@QEAAXW4PortState@@_N@Z 0000000140002d90 f ieee1588port.obj + 0001:00001fa0 ?calcMasterLocalClockRateDifference@IEEE1588Port@@QEAAH_JVTimestamp@@@Z 0000000140002fa0 f ieee1588port.obj + 0001:000020e0 ?calcLocalSystemClockRateDifference@IEEE1588Port@@QEAAH_JVTimestamp@@@Z 00000001400030e0 f ieee1588port.obj + 0001:000021b0 ??A?$map@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@@std@@QEAAAEAPEAVOSNetworkInterfaceFactory@@AEBVfactory_name_t@@@Z 00000001400031b0 f i ieee1588port.obj + 0001:000022b0 ??A?$map@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@@std@@QEAAAEAVLinkLayerAddress@@AEBVPortIdentity@@@Z 00000001400032b0 f i ieee1588port.obj + 0001:000023a0 ??1?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@QEAA@XZ 00000001400033a0 f i ieee1588port.obj + 0001:000023b0 ??0?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAA@AEBU?$less@VPortIdentity@@@1@AEBV?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@1@@Z 00000001400033b0 f i ieee1588port.obj + 0001:00002440 ??1?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAA@XZ 0000000140003440 f i ieee1588port.obj + 0001:00002440 ??1?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAA@XZ 0000000140003440 f i daemon_cl.obj + 0001:00002450 ??R?$less@VPortIdentity@@@std@@QEBA_NAEBVPortIdentity@@0@Z 0000000140003450 f i ieee1588port.obj + 0001:000024a0 ?erase@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@@2@V?$_Tree_const_iterator@V?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@@2@0@Z 00000001400034a0 f i ieee1588port.obj + 0001:00002580 ?_Lbound@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@IEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@2@AEBVPortIdentity@@@Z 0000000140003580 f i ieee1588port.obj + 0001:00002610 ?erase@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@@2@V?$_Tree_const_iterator@V?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@@2@@Z 0000000140003610 f i ieee1588port.obj + 0001:00002980 ?clear@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAAXXZ 0000000140003980 f i ieee1588port.obj + 0001:00002a10 ?_Erase@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@IEAAXPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@2@@Z 0000000140003a10 f i ieee1588port.obj + 0001:00002a80 ?_Lrotate@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@IEAAXPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@2@@Z 0000000140003a80 f i ieee1588port.obj + 0001:00002ae0 ?_Rrotate@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@IEAAXPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@2@@Z 0000000140003ae0 f i ieee1588port.obj + 0001:00002b40 ?_Insert@?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@@2@V?$_Tree_const_iterator@V?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@@2@PEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@2@@Z 0000000140003b40 f i ieee1588port.obj + 0001:00002de0 ?_Insert@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@@2@V?$_Tree_const_iterator@V?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@@2@PEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@2@@Z 0000000140003de0 f i ieee1588port.obj + 0001:00003050 ?_Linsert@?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAA?AU?$pair@V?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@@std@@_N@2@PEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@2@_N@Z 0000000140004050 f i ieee1588port.obj + 0001:000031b0 ?_Insert@?$_Tree@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@IEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@@2@_NPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@2@1@Z 00000001400041b0 f i ieee1588port.obj + 0001:00003460 ?_Linsert@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAA?AU?$pair@V?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@@std@@_N@2@PEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@2@_N@Z 0000000140004460 f i ieee1588port.obj + 0001:00003610 ?_Insert@?$_Tree@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@IEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@@2@_NPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@2@1@Z 0000000140004610 f i ieee1588port.obj + 0001:000038c0 ??$_Buynode@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@1@$$QEAU?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@1@@Z 00000001400048c0 f i ieee1588port.obj + 0001:00003930 ??$_Buynode@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@1@$$QEAU?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@1@@Z 0000000140004930 f i ieee1588port.obj + 0001:00003990 ?_Buynode@?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@2@XZ 0000000140004990 f i ieee1588port.obj + 0001:00003a10 ?_Buynode@?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@2@XZ 0000000140004a10 f i ieee1588port.obj + 0001:00003a90 ??_EPTPMessagePathDelayReq@@UEAAPEAXI@Z 0000000140004a90 f i CIL library: CIL module + 0001:00003a90 ??_GPTPMessageCommon@@UEAAPEAXI@Z 0000000140004a90 f i ptp_message.obj + 0001:00003a90 ??_GPTPMessageSync@@UEAAPEAXI@Z 0000000140004a90 f i ptp_message.obj + 0001:00003a90 ??_EPTPMessageSync@@UEAAPEAXI@Z 0000000140004a90 f i CIL library: CIL module + 0001:00003a90 ??_EPTPMessageFollowUp@@UEAAPEAXI@Z 0000000140004a90 f i CIL library: CIL module + 0001:00003a90 ??_GPTPMessagePathDelayReq@@UEAAPEAXI@Z 0000000140004a90 f i ptp_message.obj + 0001:00003a90 ??_GPTPMessageFollowUp@@UEAAPEAXI@Z 0000000140004a90 f i ptp_message.obj + 0001:00003a90 ??_EPTPMessageCommon@@UEAAPEAXI@Z 0000000140004a90 f i CIL library: CIL module + 0001:00003ad0 ??_GPTPMessagePathDelayResp@@UEAAPEAXI@Z 0000000140004ad0 f i ptp_message.obj + 0001:00003ad0 ??_EPTPMessagePathDelayResp@@UEAAPEAXI@Z 0000000140004ad0 f i CIL library: CIL module + 0001:00003b30 ??_GPTPMessagePathDelayRespFollowUp@@UEAAPEAXI@Z 0000000140004b30 f i ptp_message.obj + 0001:00003b30 ??_EPTPMessagePathDelayRespFollowUp@@UEAAPEAXI@Z 0000000140004b30 f i CIL library: CIL module + 0001:00003b90 ??0PortIdentity@@QEAA@PEAEPEAG@Z 0000000140004b90 f i ptp_message.obj + 0001:00003bd0 ?addQualifiedAnnounce@IEEE1588Port@@QEAAXPEAVPTPMessageAnnounce@@@Z 0000000140004bd0 f i ptp_message.obj + 0001:00003c50 ?buildPTPMessage@@YAPEAVPTPMessageCommon@@PEADHPEAVLinkLayerAddress@@PEAVIEEE1588Port@@@Z 0000000140004c50 f ptp_message.obj + 0001:00004370 ?processMessage@PTPMessageCommon@@UEAAXPEAVIEEE1588Port@@@Z 0000000140005370 f ptp_message.obj + 0001:00004380 ?buildCommonHeader@PTPMessageCommon@@QEAAXPEAE@Z 0000000140005380 f ptp_message.obj + 0001:00004460 ??1PTPMessageCommon@@UEAA@XZ 0000000140005460 f ptp_message.obj + 0001:00004480 ??_EPTPMessageAnnounce@@UEAAPEAXI@Z 0000000140005480 f i CIL library: CIL module + 0001:00004480 ??_GPTPMessageAnnounce@@UEAAPEAXI@Z 0000000140005480 f i ptp_message.obj + 0001:000044e0 ?isBetterThan@PTPMessageAnnounce@@QEAA_NPEAV1@@Z 00000001400054e0 f ptp_message.obj + 0001:000045b0 ??0PTPMessageSync@@QEAA@PEAVIEEE1588Port@@@Z 00000001400055b0 f ptp_message.obj + 0001:00004660 ?sendPort@PTPMessageSync@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z 0000000140005660 f ptp_message.obj + 0001:000047a0 ??0PTPMessageAnnounce@@QEAA@PEAVIEEE1588Port@@@Z 00000001400057a0 f ptp_message.obj + 0001:000048e0 ?sendPort@PTPMessageAnnounce@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z 00000001400058e0 f ptp_message.obj + 0001:00004a60 ?processMessage@PTPMessageAnnounce@@UEAAXPEAVIEEE1588Port@@@Z 0000000140005a60 f ptp_message.obj + 0001:00004b50 ?processMessage@PTPMessageSync@@UEAAXPEAVIEEE1588Port@@@Z 0000000140005b50 f ptp_message.obj + 0001:00004c60 ??0PTPMessageFollowUp@@QEAA@PEAVIEEE1588Port@@@Z 0000000140005c60 f ptp_message.obj + 0001:00004d50 ?sendPort@PTPMessageFollowUp@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z 0000000140005d50 f ptp_message.obj + 0001:00004ea0 ?processMessage@PTPMessageFollowUp@@UEAAXPEAVIEEE1588Port@@@Z 0000000140005ea0 f ptp_message.obj + 0001:00005290 ?processMessage@PTPMessagePathDelayReq@@UEAAXPEAVIEEE1588Port@@@Z 0000000140006290 f ptp_message.obj + 0001:000056b0 ?sendPort@PTPMessagePathDelayReq@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z 00000001400066b0 f ptp_message.obj + 0001:000057b0 ??0PTPMessagePathDelayResp@@QEAA@PEAVIEEE1588Port@@@Z 00000001400067b0 f ptp_message.obj + 0001:00005840 ?processMessage@PTPMessagePathDelayResp@@UEAAXPEAVIEEE1588Port@@@Z 0000000140006840 f ptp_message.obj + 0001:00005990 ?sendPort@PTPMessagePathDelayResp@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z 0000000140006990 f ptp_message.obj + 0001:00005ae0 ??0PTPMessagePathDelayRespFollowUp@@QEAA@PEAVIEEE1588Port@@@Z 0000000140006ae0 f ptp_message.obj + 0001:00005b70 ?processMessage@PTPMessagePathDelayRespFollowUp@@UEAAXPEAVIEEE1588Port@@@Z 0000000140006b70 f ptp_message.obj + 0001:00006070 ?sendPort@PTPMessagePathDelayRespFollowUp@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z 0000000140007070 f ptp_message.obj + 0001:000061c0 ?_Buynode@?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAAPEAU_Node@?$_List_nod@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@2@PEAU342@0AEBQEAUWindowsTimerQueueHandlerArg@@@Z 00000001400071c0 f i daemon_cl.obj + 0001:000061c0 ?_Buynode@?$_List_val@PEAVPTPMessageAnnounce@@V?$allocator@PEAVPTPMessageAnnounce@@@std@@@std@@QEAAPEAU_Node@?$_List_nod@PEAVPTPMessageAnnounce@@V?$allocator@PEAVPTPMessageAnnounce@@@std@@@2@PEAU342@0AEBQEAVPTPMessageAnnounce@@@Z 00000001400071c0 f i ptp_message.obj + 0001:00006260 ?HWTimestamper_init@HWTimestamper@@UEAA_NPEAVInterfaceLabel@@@Z 0000000140007260 f i daemon_cl.obj + 0001:00006270 ??3@YAXPEAX0@Z 0000000140007270 f i ieee1588port.obj + 0001:00006270 ?HWTimestamper_final@HWTimestamper@@UEAAXXZ 0000000140007270 f i daemon_cl.obj + 0001:00006280 ?HWTimestamper_adjclockrate@HWTimestamper@@UEAA_NHIVTimestamp@@_J_N@Z 0000000140007280 f i daemon_cl.obj + 0001:00006280 ?HWTimestamper_adjclockrate2@HWTimestamper@@UEAA_NH@Z 0000000140007280 f i daemon_cl.obj + 0001:00006280 ?HWTimestamper_get_extclk_offset@HWTimestamper@@UEAA_NPEAVTimestamp@@PEA_JPEAH@Z 0000000140007280 f i daemon_cl.obj + 0001:00006290 ?HWTimestamper_get_extderror@HWTimestamper@@UEAAXPEAD@Z 0000000140007290 f i daemon_cl.obj + 0001:000062a0 ??_GHWTimestamper@@UEAAPEAXI@Z 00000001400072a0 f i daemon_cl.obj + 0001:000062a0 ??_GWindowsTimestamper@@UEAAPEAXI@Z 00000001400072a0 f i daemon_cl.obj + 0001:000062a0 ??_EHWTimestamper@@UEAAPEAXI@Z 00000001400072a0 f i CIL library: CIL module + 0001:000062a0 ??_EWindowsTimestamper@@UEAAPEAXI@Z 00000001400072a0 f i CIL library: CIL module + 0001:000062d0 ?send@WindowsPCAPNetworkInterface@@UEAA?AW4net_result@@PEAVLinkLayerAddress@@PEAE_K_N@Z 00000001400072d0 f i daemon_cl.obj + 0001:000063a0 ?recv@WindowsPCAPNetworkInterface@@UEAA?AW4net_result@@PEAVLinkLayerAddress@@PEAEAEA_K@Z 00000001400073a0 f i daemon_cl.obj + 0001:000064d0 ?getLinkLayerAddress@WindowsPCAPNetworkInterface@@UEAAXPEAVLinkLayerAddress@@@Z 00000001400074d0 f i daemon_cl.obj + 0001:00006500 ?getPayloadOffset@WindowsPCAPNetworkInterface@@UEAAIXZ 0000000140007500 f i daemon_cl.obj + 0001:00006510 ??_GWindowsPCAPNetworkInterface@@UEAAPEAXI@Z 0000000140007510 f i daemon_cl.obj + 0001:00006510 ??_EWindowsPCAPNetworkInterface@@UEAAPEAXI@Z 0000000140007510 f i CIL library: CIL module + 0001:00006590 ?createInterface@WindowsPCAPNetworkInterfaceFactory@@UEAA_NPEAPEAVOSNetworkInterface@@PEAVInterfaceLabel@@PEAVHWTimestamper@@@Z 0000000140007590 f i daemon_cl.obj + 0001:000066f0 ?lock@WindowsLock@@MEAA?AW4OSLockResult@@XZ 00000001400076f0 f i daemon_cl.obj + 0001:000067a0 ?trylock@WindowsLock@@MEAA?AW4OSLockResult@@XZ 00000001400077a0 f i daemon_cl.obj + 0001:00006850 ?unlock@WindowsLock@@MEAA?AW4OSLockResult@@XZ 0000000140007850 f i daemon_cl.obj + 0001:00006870 ?createLock@WindowsLockFactory@@UEAAPEAVOSLock@@W4OSLockType@@@Z 0000000140007870 f i daemon_cl.obj + 0001:000068f0 ?wait_prelock@WindowsCondition@@UEAA_NXZ 00000001400078f0 f i daemon_cl.obj + 0001:00006910 ?wait@WindowsCondition@@UEAA_NXZ 0000000140007910 f i daemon_cl.obj + 0001:00006960 ?signal@WindowsCondition@@UEAA_NXZ 0000000140007960 f i daemon_cl.obj + 0001:000069a0 ?createCondition@WindowsConditionFactory@@UEAAPEAVOSCondition@@XZ 00000001400079a0 f i daemon_cl.obj + 0001:000069f0 ?cleanupRetiredTimers@WindowsTimerQueue@@AEAAXXZ 00000001400079f0 f i daemon_cl.obj + 0001:00006ac0 ??0WindowsTimerQueue@@IEAA@XZ 0000000140007ac0 f i daemon_cl.obj + 0001:00006b60 ?addEvent@WindowsTimerQueue@@UEAA_NKHP6AXPEAX@ZPEAUevent_descriptor_t@@_NPEAI@Z 0000000140007b60 f i daemon_cl.obj + 0001:00006da0 ?cancelEvent@WindowsTimerQueue@@UEAA_NHPEAI@Z 0000000140007da0 f i daemon_cl.obj + 0001:00006f40 ??1?$map@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@@std@@QEAA@XZ 0000000140007f40 f i daemon_cl.obj + 0001:00006f80 ?WindowsTimerQueueHandler@@YAXPEAXE@Z 0000000140007f80 f daemon_cl.obj + 0001:00007090 ?createOSTimerQueue@WindowsTimerQueueFactory@@UEAAPEAVOSTimerQueue@@XZ 0000000140008090 f i daemon_cl.obj + 0001:000070d0 ?sleep@WindowsTimer@@UEAAKK@Z 00000001400080d0 f i daemon_cl.obj + 0001:00007100 ?createTimer@WindowsTimerFactory@@UEAAPEAVOSTimer@@XZ 0000000140008100 f i daemon_cl.obj + 0001:00007130 ?OSThreadCallback@@YAKPEAX@Z 0000000140008130 f daemon_cl.obj + 0001:00007150 ?start@WindowsThread@@UEAA_NP6A?AW4OSThreadExitCode@@PEAX@Z0@Z 0000000140008150 f i daemon_cl.obj + 0001:000071e0 ?join@WindowsThread@@UEAA_NAEAW4OSThreadExitCode@@@Z 00000001400081e0 f i daemon_cl.obj + 0001:00007230 ?createThread@WindowsThreadFactory@@UEAAPEAVOSThread@@XZ 0000000140008230 f i daemon_cl.obj + 0001:00007260 ?HWTimestamper_init@WindowsTimestamper@@UEAA_NPEAVInterfaceLabel@@@Z 0000000140008260 f i daemon_cl.obj + 0001:00007550 ?HWTimestamper_gettime@WindowsTimestamper@@UEAA_NPEAVTimestamp@@0PEAI1@Z 0000000140008550 f i daemon_cl.obj + 0001:00007730 ?HWTimestamper_txtimestamp@WindowsTimestamper@@UEAAHPEAVPortIdentity@@GAEAVTimestamp@@AEAI_N@Z 0000000140008730 f i daemon_cl.obj + 0001:000078d0 ?HWTimestamper_rxtimestamp@WindowsTimestamper@@UEAAHPEAVPortIdentity@@GAEAVTimestamp@@AEAI_N@Z 00000001400088d0 f i daemon_cl.obj + 0001:00007a60 ?init@WindowsNamedPipeIPC@@UEAA_NXZ 0000000140008a60 f i daemon_cl.obj + 0001:00007b40 ?update@WindowsNamedPipeIPC@@UEAA_N_J0HH_K@Z 0000000140008b40 f i daemon_cl.obj + 0001:00007bd0 ?ctrl_handler@@YAHK@Z 0000000140008bd0 f daemon_cl.obj + 0001:00007bf0 main 0000000140008bf0 f daemon_cl.obj + 0001:00008020 ??A?$map@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@@std@@QEAAAEAUTimerQueue_t@@AEBH@Z 0000000140009020 f i daemon_cl.obj + 0001:000081e0 ??1TimerQueue_t@@QEAA@XZ 00000001400091e0 f i daemon_cl.obj + 0001:000081e0 ??1?$list@PEAVPTPMessageAnnounce@@V?$allocator@PEAVPTPMessageAnnounce@@@std@@@std@@QEAA@XZ 00000001400091e0 f i ieee1588port.obj + 0001:00008240 ??1?$pair@$$CBHUTimerQueue_t@@@std@@QEAA@XZ 0000000140009240 f i daemon_cl.obj + 0001:00008240 ??$_Dest_val@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@std@@U?$pair@$$CBHUTimerQueue_t@@@2@@std@@YAXAEAV?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@0@PEAU?$pair@$$CBHUTimerQueue_t@@@0@@Z 0000000140009240 f i daemon_cl.obj + 0001:000082a0 ?_Tidy@?$list@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAAXXZ 00000001400092a0 f i daemon_cl.obj + 0001:000082f0 ??1?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAA@XZ 00000001400092f0 f i daemon_cl.obj + 0001:00008300 ??0?$_Tree@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAA@AEBU?$less@H@1@AEBV?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@1@@Z 0000000140009300 f i daemon_cl.obj + 0001:00008390 ?erase@?$_Tree@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@@2@V?$_Tree_const_iterator@V?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@@2@0@Z 0000000140009390 f i daemon_cl.obj + 0001:00008490 ??0?$list@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAA@AEBV01@@Z 0000000140009490 f i daemon_cl.obj + 0001:00008540 ?erase@?$_Tree@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@@2@V?$_Tree_const_iterator@V?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@@2@@Z 0000000140009540 f i daemon_cl.obj + 0001:000088d0 ?_Erase@?$_Tree@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@IEAAXPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@2@@Z 00000001400098d0 f i daemon_cl.obj + 0001:00008970 ?_Lrotate@?$_Tree@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@IEAAXPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@2@@Z 0000000140009970 f i daemon_cl.obj + 0001:000089d0 ?_Rrotate@?$_Tree@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@IEAAXPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@2@@Z 00000001400099d0 f i daemon_cl.obj + 0001:00008a30 ?_Insert@?$_Tree@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@@2@V?$_Tree_const_iterator@V?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@@2@PEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@2@@Z 0000000140009a30 f i daemon_cl.obj + 0001:00008c40 ?_Linsert@?$_Tree@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAA?AU?$pair@V?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@@std@@_N@2@PEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@2@_N@Z 0000000140009c40 f i daemon_cl.obj + 0001:00008d70 ?_Insert@?$_Tree@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@IEAA?AV?$_Tree_iterator@V?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@@2@_NPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@2@1@Z 0000000140009d70 f i daemon_cl.obj + 0001:00009060 ??$_Buynode@U?$pair@$$CBHUTimerQueue_t@@@std@@@?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@1@$$QEAU?$pair@$$CBHUTimerQueue_t@@@1@@Z 000000014000a060 f i daemon_cl.obj + 0001:000090e0 ??$_Insert@V?$_List_const_iterator@V?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@@std@@@?$list@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAAXV?$_List_const_iterator@V?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@@1@00Uforward_iterator_tag@1@@Z 000000014000a0e0 f i daemon_cl.obj + 0001:00009190 ?_Buynode@?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@2@XZ 000000014000a190 f i daemon_cl.obj + 0001:00009210 ?openInterfaceByAddr@@YA?AW4packet_error_t@@PEAUpacket_handle@@PEAUpacket_addr_t@@H@Z 000000014000a210 f packet.obj + 0001:000093d0 ?packetBind@@YA?AW4packet_error_t@@PEAUpacket_handle@@G@Z 000000014000a3d0 f packet.obj + 0001:000094d0 ??_U@YAPEAX_K@Z 000000014000a4d0 f msvcprt:newaop_s.obj + 0001:000094f0 __security_check_cookie 000000014000a4f0 f MSVCRT:amdsecgs.obj + 0001:00009510 ?what@exception@std@@UEBAPEBDXZ 000000014000a510 f MSVCRT:MSVCR100.dll + 0001:00009516 ??0exception@std@@QEAA@AEBV01@@Z 000000014000a516 f MSVCRT:MSVCR100.dll + 0001:0000951c _onexit 000000014000a51c f MSVCRT:atonexit.obj + 0001:000095cc atexit 000000014000a5cc f MSVCRT:atonexit.obj + 0001:000095e4 ??3@YAXPEAX@Z 000000014000a5e4 f MSVCRT:MSVCR100.dll + 0001:000095ec ??_Etype_info@@UEAAPEAXI@Z 000000014000a5ec f i MSVCRT:ti_inst.obj + 0001:00009656 ??2@YAPEAX_K@Z 000000014000a656 f MSVCRT:MSVCR100.dll + 0001:0000965c _purecall 000000014000a65c f MSVCRT:MSVCR100.dll + 0001:0000991c mainCRTStartup 000000014000a91c f MSVCRT:crtexe.obj + 0001:00009930 __report_gsfailure 000000014000a930 f MSVCRT:gs_report.obj + 0001:00009a7a __C_specific_handler 000000014000aa7a f MSVCRT:MSVCR100.dll + 0001:00009a80 _unlock 000000014000aa80 f MSVCRT:MSVCR100.dll + 0001:00009a86 __dllonexit 000000014000aa86 f MSVCRT:MSVCR100.dll + 0001:00009a8c _lock 000000014000aa8c f MSVCRT:MSVCR100.dll + 0001:00009a94 ?__ArrayUnwind@@YAXPEAX_KHP6AX0@Z@Z 000000014000aa94 f MSVCRT:ehvecdtr.obj + 0001:00009ae0 ??_M@YAXPEAX_KHP6AX0@Z@Z 000000014000aae0 f MSVCRT:ehvecdtr.obj + 0001:00009b40 ?__CxxUnhandledExceptionFilter@@YAJPEAU_EXCEPTION_POINTERS@@@Z 000000014000ab40 f MSVCRT:unhandld.obj + 0001:00009b84 __CxxSetUnhandledExceptionFilter 000000014000ab84 f MSVCRT:unhandld.obj + 0001:00009b9c _amsg_exit 000000014000ab9c f MSVCRT:MSVCR100.dll + 0001:00009ba4 _RTC_Initialize 000000014000aba4 f MSVCRT:_initsect_.obj + 0001:00009bdc _RTC_Terminate 000000014000abdc f MSVCRT:_initsect_.obj + 0001:00009c14 _XcptFilter 000000014000ac14 f MSVCRT:MSVCR100.dll + 0001:00009c20 _ValidateImageBase 000000014000ac20 f MSVCRT:pesect.obj + 0001:00009c50 _FindPESection 000000014000ac50 f MSVCRT:pesect.obj + 0001:00009ca0 _IsNonwritableInCurrentImage 000000014000aca0 f MSVCRT:pesect.obj + 0001:00009ce2 _initterm 000000014000ace2 f MSVCRT:MSVCR100.dll + 0001:00009ce8 _initterm_e 000000014000ace8 f MSVCRT:MSVCR100.dll + 0001:00009cf0 _matherr 000000014000acf0 f MSVCRT:merr.obj + 0001:00009cf0 _setargv 000000014000acf0 f MSVCRT:dllargv.obj + 0001:00009cf4 __security_init_cookie 000000014000acf4 f MSVCRT:gs_support.obj + 0001:00009da8 __crt_debugger_hook 000000014000ada8 f MSVCRT:MSVCR100.dll + 0001:00009dae ?terminate@@YAXXZ 000000014000adae f MSVCRT:MSVCR100.dll + 0001:00009db4 ??1type_info@@UEAA@XZ 000000014000adb4 f MSVCRT:MSVCR100.dll + 0001:00009db4 ?_type_info_dtor_internal_method@type_info@@QEAAXXZ 000000014000adb4 f MSVCRT:MSVCR100.dll + 0001:00009dba RtlVirtualUnwind 000000014000adba f kernel32:KERNEL32.dll + 0001:00009dc0 RtlLookupFunctionEntry 000000014000adc0 f kernel32:KERNEL32.dll + 0001:00009dc6 memcpy 000000014000adc6 f MSVCRT:MSVCR100.dll + 0001:00009dcc __GSHandlerCheckCommon 000000014000adcc f MSVCRT:gshandler.obj + 0001:00009e30 __GSHandlerCheck 000000014000ae30 f MSVCRT:gshandler.obj + 0001:00009e60 __chkstk 000000014000ae60 f MSVCRT:chkstk.obj + 0001:00009e60 _alloca_probe 000000014000ae60 MSVCRT:chkstk.obj + 0001:00009eae memcmp 000000014000aeae f MSVCRT:MSVCR100.dll + 0001:00009eb4 _CxxThrowException 000000014000aeb4 f MSVCRT:MSVCR100.dll + 0001:00009eba __CxxFrameHandler3 000000014000aeba f MSVCRT:MSVCR100.dll + 0001:00009ec0 __RTDynamicCast 000000014000aec0 f MSVCRT:MSVCR100.dll + 0001:00009ec8 __GSHandlerCheck_EH 000000014000aec8 f MSVCRT:gshandlereh.obj + 0001:00009f58 memset 000000014000af58 f MSVCRT:MSVCR100.dll + 0002:00000000 __imp_GetAdaptersAddresses 000000014000c000 Iphlpapi:IPHLPAPI.DLL + 0002:00000008 \177IPHLPAPI_NULL_THUNK_DATA 000000014000c008 Iphlpapi:IPHLPAPI.DLL + 0002:00000010 __imp_GetCurrentProcess 000000014000c010 kernel32:KERNEL32.dll + 0002:00000018 __imp_TerminateProcess 000000014000c018 kernel32:KERNEL32.dll + 0002:00000020 __imp_DecodePointer 000000014000c020 kernel32:KERNEL32.dll + 0002:00000028 __imp_GetSystemTimeAsFileTime 000000014000c028 kernel32:KERNEL32.dll + 0002:00000030 __imp_UnhandledExceptionFilter 000000014000c030 kernel32:KERNEL32.dll + 0002:00000038 __imp_SetUnhandledExceptionFilter 000000014000c038 kernel32:KERNEL32.dll + 0002:00000040 __imp_RtlVirtualUnwind 000000014000c040 kernel32:KERNEL32.dll + 0002:00000048 __imp_GetCurrentProcessId 000000014000c048 kernel32:KERNEL32.dll + 0002:00000050 __imp_GetTickCount 000000014000c050 kernel32:KERNEL32.dll + 0002:00000058 __imp_QueryPerformanceCounter 000000014000c058 kernel32:KERNEL32.dll + 0002:00000060 __imp_RtlCaptureContext 000000014000c060 kernel32:KERNEL32.dll + 0002:00000068 __imp_RtlLookupFunctionEntry 000000014000c068 kernel32:KERNEL32.dll + 0002:00000070 __imp_CreateFileA 000000014000c070 kernel32:KERNEL32.dll + 0002:00000078 __imp_CreateTimerQueue 000000014000c078 kernel32:KERNEL32.dll + 0002:00000080 __imp_WaitForSingleObject 000000014000c080 kernel32:KERNEL32.dll + 0002:00000088 __imp_ReleaseSRWLockExclusive 000000014000c088 kernel32:KERNEL32.dll + 0002:00000090 __imp_WriteFile 000000014000c090 kernel32:KERNEL32.dll + 0002:00000098 __imp_AcquireSRWLockExclusive 000000014000c098 kernel32:KERNEL32.dll + 0002:000000a0 __imp_Sleep 000000014000c0a0 kernel32:KERNEL32.dll + 0002:000000a8 __imp_InitializeConditionVariable 000000014000c0a8 kernel32:KERNEL32.dll + 0002:000000b0 __imp_GetLastError 000000014000c0b0 kernel32:KERNEL32.dll + 0002:000000b8 __imp_SleepConditionVariableSRW 000000014000c0b8 kernel32:KERNEL32.dll + 0002:000000c0 __imp_CreateNamedPipeA 000000014000c0c0 kernel32:KERNEL32.dll + 0002:000000c8 __imp_CreateTimerQueueTimer 000000014000c0c8 kernel32:KERNEL32.dll + 0002:000000d0 __imp_InitializeSRWLock 000000014000c0d0 kernel32:KERNEL32.dll + 0002:000000d8 __imp_SetConsoleCtrlHandler 000000014000c0d8 kernel32:KERNEL32.dll + 0002:000000e0 __imp_DeviceIoControl 000000014000c0e0 kernel32:KERNEL32.dll + 0002:000000e8 __imp_WakeAllConditionVariable 000000014000c0e8 kernel32:KERNEL32.dll + 0002:000000f0 __imp_CreateMutexA 000000014000c0f0 kernel32:KERNEL32.dll + 0002:000000f8 __imp_GetCurrentThreadId 000000014000c0f8 kernel32:KERNEL32.dll + 0002:00000100 __imp_ReleaseMutex 000000014000c100 kernel32:KERNEL32.dll + 0002:00000108 __imp_CloseHandle 000000014000c108 kernel32:KERNEL32.dll + 0002:00000110 __imp_DeleteTimerQueueTimer 000000014000c110 kernel32:KERNEL32.dll + 0002:00000118 __imp_CreateThread 000000014000c118 kernel32:KERNEL32.dll + 0002:00000120 __imp_EncodePointer 000000014000c120 kernel32:KERNEL32.dll + 0002:00000128 __imp_IsDebuggerPresent 000000014000c128 kernel32:KERNEL32.dll + 0002:00000130 \177KERNEL32_NULL_THUNK_DATA 000000014000c130 kernel32:KERNEL32.dll + 0002:00000138 __imp_?_Xout_of_range@std@@YAXPEBD@Z 000000014000c138 msvcprt:MSVCP100.dll + 0002:00000140 __imp_?_Xlength_error@std@@YAXPEBD@Z 000000014000c140 msvcprt:MSVCP100.dll + 0002:00000148 \177MSVCP100_NULL_THUNK_DATA 000000014000c148 msvcprt:MSVCP100.dll + 0002:00000150 __imp_??0exception@std@@QEAA@AEBQEBD@Z 000000014000c150 MSVCRT:MSVCR100.dll + 0002:00000158 __imp_??0exception@std@@QEAA@AEBV01@@Z 000000014000c158 MSVCRT:MSVCR100.dll + 0002:00000160 __imp_??1exception@std@@UEAA@XZ 000000014000c160 MSVCRT:MSVCR100.dll + 0002:00000168 __imp_??2@YAPEAX_K@Z 000000014000c168 MSVCRT:MSVCR100.dll + 0002:00000170 __imp_abort 000000014000c170 MSVCRT:MSVCR100.dll + 0002:00000178 __imp___iob_func 000000014000c178 MSVCRT:MSVCR100.dll + 0002:00000180 __imp_fprintf 000000014000c180 MSVCRT:MSVCR100.dll + 0002:00000188 __imp_strncpy_s 000000014000c188 MSVCRT:MSVCR100.dll + 0002:00000190 __imp_memset 000000014000c190 MSVCRT:MSVCR100.dll + 0002:00000198 __imp_strtol 000000014000c198 MSVCRT:MSVCR100.dll + 0002:000001a0 __imp_strnlen 000000014000c1a0 MSVCRT:MSVCR100.dll + 0002:000001a8 __imp__purecall 000000014000c1a8 MSVCRT:MSVCR100.dll + 0002:000001b0 __imp_sprintf_s 000000014000c1b0 MSVCRT:MSVCR100.dll + 0002:000001b8 __imp_free 000000014000c1b8 MSVCRT:MSVCR100.dll + 0002:000001c0 __imp_malloc 000000014000c1c0 MSVCRT:MSVCR100.dll + 0002:000001c8 __imp_strcpy_s 000000014000c1c8 MSVCRT:MSVCR100.dll + 0002:000001d0 __imp___C_specific_handler 000000014000c1d0 MSVCRT:MSVCR100.dll + 0002:000001d8 __imp__unlock 000000014000c1d8 MSVCRT:MSVCR100.dll + 0002:000001e0 __imp_?what@exception@std@@UEBAPEBDXZ 000000014000c1e0 MSVCRT:MSVCR100.dll + 0002:000001e8 __imp__lock 000000014000c1e8 MSVCRT:MSVCR100.dll + 0002:000001f0 __imp__onexit 000000014000c1f0 MSVCRT:MSVCR100.dll + 0002:000001f8 __imp__amsg_exit 000000014000c1f8 MSVCRT:MSVCR100.dll + 0002:00000200 __imp___getmainargs 000000014000c200 MSVCRT:MSVCR100.dll + 0002:00000208 __imp__XcptFilter 000000014000c208 MSVCRT:MSVCR100.dll + 0002:00000210 __imp__exit 000000014000c210 MSVCRT:MSVCR100.dll + 0002:00000218 __imp__cexit 000000014000c218 MSVCRT:MSVCR100.dll + 0002:00000220 __imp_exit 000000014000c220 MSVCRT:MSVCR100.dll + 0002:00000228 __imp___initenv 000000014000c228 MSVCRT:MSVCR100.dll + 0002:00000230 __imp__initterm 000000014000c230 MSVCRT:MSVCR100.dll + 0002:00000238 __imp__initterm_e 000000014000c238 MSVCRT:MSVCR100.dll + 0002:00000240 __imp__configthreadlocale 000000014000c240 MSVCRT:MSVCR100.dll + 0002:00000248 __imp___setusermatherr 000000014000c248 MSVCRT:MSVCR100.dll + 0002:00000250 __imp__commode 000000014000c250 MSVCRT:MSVCR100.dll + 0002:00000258 __imp__fmode 000000014000c258 MSVCRT:MSVCR100.dll + 0002:00000260 __imp___set_app_type 000000014000c260 MSVCRT:MSVCR100.dll + 0002:00000268 __imp___crt_debugger_hook 000000014000c268 MSVCRT:MSVCR100.dll + 0002:00000270 __imp_?terminate@@YAXXZ 000000014000c270 MSVCRT:MSVCR100.dll + 0002:00000278 __imp_?_type_info_dtor_internal_method@type_info@@QEAAXXZ 000000014000c278 MSVCRT:MSVCR100.dll + 0002:00000280 __imp___dllonexit 000000014000c280 MSVCRT:MSVCR100.dll + 0002:00000288 __imp_memcpy 000000014000c288 MSVCRT:MSVCR100.dll + 0002:00000290 __imp_memcmp 000000014000c290 MSVCRT:MSVCR100.dll + 0002:00000298 __imp__CxxThrowException 000000014000c298 MSVCRT:MSVCR100.dll + 0002:000002a0 __imp___CxxFrameHandler3 000000014000c2a0 MSVCRT:MSVCR100.dll + 0002:000002a8 __imp___RTDynamicCast 000000014000c2a8 MSVCRT:MSVCR100.dll + 0002:000002b0 __imp_??3@YAXPEAX@Z 000000014000c2b0 MSVCRT:MSVCR100.dll + 0002:000002b8 __imp_printf 000000014000c2b8 MSVCRT:MSVCR100.dll + 0002:000002c0 \177MSVCR100_NULL_THUNK_DATA 000000014000c2c0 MSVCRT:MSVCR100.dll + 0002:000002c8 __imp_ntohl 000000014000c2c8 ws2_32:WS2_32.dll + 0002:000002d0 __imp_htonl 000000014000c2d0 ws2_32:WS2_32.dll + 0002:000002d8 __imp_ntohs 000000014000c2d8 ws2_32:WS2_32.dll + 0002:000002e0 __imp_htons 000000014000c2e0 ws2_32:WS2_32.dll + 0002:000002e8 \177WS2_32_NULL_THUNK_DATA 000000014000c2e8 ws2_32:WS2_32.dll + 0002:000002f0 __imp_pcap_close 000000014000c2f0 wpcap:wpcap.dll + 0002:000002f8 __imp_pcap_setfilter 000000014000c2f8 wpcap:wpcap.dll + 0002:00000300 __imp_pcap_next_ex 000000014000c300 wpcap:wpcap.dll + 0002:00000308 __imp_pcap_sendpacket 000000014000c308 wpcap:wpcap.dll + 0002:00000310 __imp_pcap_compile 000000014000c310 wpcap:wpcap.dll + 0002:00000318 __imp_pcap_open 000000014000c318 wpcap:wpcap.dll + 0002:00000320 \177wpcap_NULL_THUNK_DATA 000000014000c320 wpcap:wpcap.dll + 0002:00000328 __xc_a 000000014000c328 MSVCRT:cinitexe.obj + 0002:00000350 __xc_z 000000014000c350 MSVCRT:cinitexe.obj + 0002:00000358 __xi_a 000000014000c358 MSVCRT:cinitexe.obj + 0002:00000370 __xi_z 000000014000c370 MSVCRT:cinitexe.obj + 0002:000003a8 ??_7type_info@@6B@ 000000014000c3a8 MSVCRT:ti_inst.obj + 0002:000003c0 ??_C@_0BM@PAPJHAGI@invalid?5map?1set?$DMT?$DO?5iterator?$AA@ 000000014000c3c0 avbts_osnet.obj + 0002:000003e8 ??_7bad_alloc@std@@6B@ 000000014000c3e8 avbts_osnet.obj + 0002:000003f8 ??_C@_07DOAOMMKG@Enabled?$AA@ 000000014000c3f8 ieee1588port.obj + 0002:00000400 ??_C@_08JGILNPHN@Disabled?$AA@ 000000014000c400 ieee1588port.obj + 0002:00000410 ??_C@_0P@MNFODPHI@AsCapable?3?5?$CFs?6?$AA@ 000000014000c410 ieee1588port.obj + 0002:00000420 ??_C@_0CB@NKHFMBCL@?4?4?2?4?4?2?4?4?2common?2ieee1588port?4cpp@ 000000014000c420 ieee1588port.obj + 0002:00000450 ??_C@_0GF@MDOAJEFI@ERROR?5at?5?$CFu?5in?5?$CFs?3?5Failed?5to?5ini@ 000000014000c450 ieee1588port.obj + 0002:000004b8 ??_C@_07DLHCIBDH@default?$AA@ 000000014000c4b8 ieee1588port.obj + 0002:000004c0 ??_C@_0BK@DFGFBKIK@openPort?3?5thread?5started?6?$AA@ 000000014000c4c0 ieee1588port.obj + 0002:000004e0 ??_C@_0CP@OBBALOF@ERROR?5at?5?$CFu?5in?5?$CFs?3?5Discarding?5in@ 000000014000c4e0 ieee1588port.obj + 0002:00000510 ??_C@_0DH@EKGLNKDB@ERROR?5at?5?$CFu?5in?5?$CFs?3?5read?5from?5net@ 000000014000c510 ieee1588port.obj + 0002:00000548 ??_C@_0CN@JABMLKGN@ERROR?5at?5?$CFu?5in?5?$CFs?3?5sendEventPort@ 000000014000c548 ieee1588port.obj + 0002:00000578 ??_C@_0BG@CGMOFACK@Starting?5port?5thread?6?$AA@ 000000014000c578 ieee1588port.obj + 0002:00000590 ??_C@_0DA@JEOMFCHP@ERROR?5at?5?$CFu?5in?5?$CFs?3?5Error?5creatin@ 000000014000c590 ieee1588port.obj + 0002:000005c0 ??_C@_01EEMJAFIK@?6?$AA@ 000000014000c5c0 ieee1588port.obj + 0002:000005c8 ??_C@_0CP@NPGACHBF@?$CK?$CK?$CKSync?5Timeout?5Expired?5?9?5Becomi@ 000000014000c5c8 ieee1588port.obj + 0002:00000600 ??_C@_0EA@FIDILCHK@Error?5?$CITX?$CJ?5timestamping?5PDelay?5r@ 000000014000c600 ieee1588port.obj + 0002:00000640 ??_C@_0DE@BANOKGOL@Error?5?$CITX?$CJ?5timestamping?5PDelay?5r@ 000000014000c640 ieee1588port.obj + 0002:00000678 ??_C@_0DD@OGAMEIIA@Error?5?$CITX?$CJ?5timestamping?5Sync?5?$CIRe@ 000000014000c678 ieee1588port.obj + 0002:000006b0 ??_C@_0CK@JAJCOOCC@Error?5?$CITX?$CJ?5timestamping?5Sync?0?5er@ 000000014000c6b0 ieee1588port.obj + 0002:000006e0 ??_C@_0CD@KBDOGJHF@PDelay?5Response?5Followup?5is?5NULL@ 000000014000c6e0 ieee1588port.obj + 0002:00000708 ??_C@_0BF@CMGMJLA@Switching?5to?5Master?6?$AA@ 000000014000c708 ieee1588port.obj + 0002:00000720 ??_C@_0BE@JHDPFIAH@Switching?5to?5Slave?6?$AA@ 000000014000c720 ieee1588port.obj + 0002:00000738 ??_C@_0BE@JONHPENG@map?1set?$DMT?$DO?5too?5long?$AA@ 000000014000c738 ieee1588port.obj + 0002:00000758 ??_7LinkLayerAddress@@6B@ 000000014000c758 ieee1588port.obj + 0002:00000768 ??_7InterfaceLabel@@6B@ 000000014000c768 ieee1588port.obj + 0002:00000770 ??_C@_0DO@EBENJJMN@Error?5?$CIRX?$CJ?5timestamping?5RX?5event@ 000000014000c770 ptp_message.obj + 0002:000007b0 ??_C@_0CA@LPEMILMO@?4?4?2?4?4?2?4?4?2common?2ptp_message?4cpp?$AA@ 000000014000c7b0 ptp_message.obj + 0002:000007d0 ??_C@_0HH@MLCBNOMP@ERROR?5at?5?$CFu?5in?5?$CFs?3?5?$CK?$CK?$CK?5Received?5@ 000000014000c7d0 ptp_message.obj + 0002:00000848 ??_C@_0DK@JNCBBDII@ERROR?5at?5?$CFu?5in?5?$CFs?3?5Received?5unsu@ 000000014000c848 ptp_message.obj + 0002:00000890 ??_C@_0EE@GKDAOEGN@ERROR?5at?5?$CFu?5in?5?$CFs?3?5Received?5Foll@ 000000014000c890 ptp_message.obj + 0002:000008e0 ??_C@_0EK@GKBMCKE@ERROR?5at?5?$CFu?5in?5?$CFs?3?5Received?5Foll@ 000000014000c8e0 ptp_message.obj + 0002:00000930 ??_C@_0EB@NKLDNAPB@Error?5?$CITX?$CJ?5timestamping?5PDelay?5R@ 000000014000c930 ptp_message.obj + 0002:00000978 ??_C@_0DF@LCPJCKOO@Error?5?$CITX?$CJ?5timestamping?5PDelay?5R@ 000000014000c978 ptp_message.obj + 0002:000009b0 ??_C@_0BO@DLMECCKO@Failed?5to?5get?5PDelay?5RX?5Lock?6?$AA@ 000000014000c9b0 ptp_message.obj + 0002:000009d0 ??_C@_0EH@DDBECIOJ@ERROR?5at?5?$CFu?5in?5?$CFs?3?5?$DO?$DO?$DO?5Received?5@ 000000014000c9d0 ptp_message.obj + 0002:00000a20 ??_C@_0EI@NNLKEKEC@ERROR?5at?5?$CFu?5in?5?$CFs?3?5?$DO?$DO?$DO?5Received?5@ 000000014000ca20 ptp_message.obj + 0002:00000a70 ??_C@_0FN@HBGJNHBE@ERROR?5at?5?$CFu?5in?5?$CFs?3?5Received?5PDel@ 000000014000ca70 ptp_message.obj + 0002:00000ad0 ??_C@_0CC@DILPCBD@ERROR?5at?5?$CFu?5in?5?$CFs?3?5My?5SeqId?3?5?$CFu?5@ 000000014000cad0 ptp_message.obj + 0002:00000af8 ??_C@_0CF@BHKGMNAC@ERROR?5at?5?$CFu?5in?5?$CFs?3?5Their?5SeqId?3?5@ 000000014000caf8 ptp_message.obj + 0002:00000b20 ??_C@_0FO@BHOOLJAL@ERROR?5at?5?$CFu?5in?5?$CFs?3?5Received?5PDel@ 000000014000cb20 ptp_message.obj + 0002:00000b80 ??_C@_0CH@FHAMNBPF@ERROR?5at?5?$CFu?5in?5?$CFs?3?5?$CFhu?0?5?$CFhu?0?5?$CFhu@ 000000014000cb80 ptp_message.obj + 0002:00000ba8 ??_C@_0BB@MOGOBHAF@list?$DMT?$DO?5too?5long?$AA@ 000000014000cba8 ptp_message.obj + 0002:00000bc8 ??_7PTPMessageCommon@@6B@ 000000014000cbc8 ptp_message.obj + 0002:00000be0 ??_7PTPMessageSync@@6B@ 000000014000cbe0 ptp_message.obj + 0002:00000bf8 ??_7PTPMessageAnnounce@@6B@ 000000014000cbf8 ptp_message.obj + 0002:00000c10 ??_7PTPMessagePathDelayReq@@6B@ 000000014000cc10 ptp_message.obj + 0002:00000c28 ??_7PTPMessagePathDelayResp@@6B@ 000000014000cc28 ptp_message.obj + 0002:00000c40 ??_7PTPMessagePathDelayRespFollowUp@@6B@ 000000014000cc40 ptp_message.obj + 0002:00000c58 ??_7PTPMessageFollowUp@@6B@ 000000014000cc58 ptp_message.obj + 0002:00000c68 ??_C@_04GBDIODIA@?2?2?4?2?$AA@ 000000014000cc68 daemon_cl.obj + 0002:00000c70 ??_C@_09IPJPBDHI@?2?2?4?2pipe?2?$AA@ 000000014000cc70 daemon_cl.obj + 0002:00000c80 ??_C@_0M@FKJIJDJM@gptp?9update?$AA@ 000000014000cc80 daemon_cl.obj + 0002:00000c90 ??_C@_0BL@JMMFGJEE@Failed?5to?5initialize?5port?6?$AA@ 000000014000cc90 daemon_cl.obj + 0002:00000cb0 ??_C@_0CD@KNEPODGG@Unable?5to?5register?5Ctrl?9C?5handle@ 000000014000ccb0 daemon_cl.obj + 0002:00000ce8 ??_7HWTimestamper@@6B@ 000000014000cce8 daemon_cl.obj + 0002:00000d40 ??_7WindowsPCAPNetworkInterface@@6B@ 000000014000cd40 daemon_cl.obj + 0002:00000d70 ??_7WindowsPCAPNetworkInterfaceFactory@@6B@ 000000014000cd70 daemon_cl.obj + 0002:00000d80 ??_7WindowsLock@@6B@ 000000014000cd80 daemon_cl.obj + 0002:00000da0 ??_7WindowsLockFactory@@6B@ 000000014000cda0 daemon_cl.obj + 0002:00000db0 ??_7WindowsCondition@@6B@ 000000014000cdb0 daemon_cl.obj + 0002:00000dd0 ??_7WindowsConditionFactory@@6B@ 000000014000cdd0 daemon_cl.obj + 0002:00000de0 ??_7WindowsTimerQueue@@6B@ 000000014000cde0 daemon_cl.obj + 0002:00000df8 ??_7WindowsTimerQueueFactory@@6B@ 000000014000cdf8 daemon_cl.obj + 0002:00000e08 ??_7WindowsTimer@@6B@ 000000014000ce08 daemon_cl.obj + 0002:00000e18 ??_7WindowsTimerFactory@@6B@ 000000014000ce18 daemon_cl.obj + 0002:00000e28 ??_7WindowsThread@@6B@ 000000014000ce28 daemon_cl.obj + 0002:00000e40 ??_7WindowsThreadFactory@@6B@ 000000014000ce40 daemon_cl.obj + 0002:00000e58 ??_7WindowsTimestamper@@6B@ 000000014000ce58 daemon_cl.obj + 0002:00000eb0 ??_7WindowsNamedPipeIPC@@6B@ 000000014000ceb0 daemon_cl.obj + 0002:00000ec0 ??_C@_0BF@EIMMNHOL@rpcap?3?1?1?2Device?2NPF_?$AA@ 000000014000cec0 packet.obj + 0002:00000ed8 ??_C@_0N@IELFOPPD@Opening?3?5?$CFs?6?$AA@ 000000014000ced8 packet.obj + 0002:00000ee8 ??_C@_0P@CMACLOMI@ether?5proto?50x?$AA@ 000000014000cee8 packet.obj + 0002:00000ef8 ??_C@_03OIHFBGIJ@?$CFhx?$AA@ 000000014000cef8 packet.obj + 0002:00000f00 __real@43e0000000000000 000000014000cf00 CIL library: CIL module + 0002:00000f08 __real@41cdcd6500000000 000000014000cf08 CIL library: CIL module + 0002:00000f10 __real@43f0000000000000 000000014000cf10 CIL library: CIL module + 0002:00000f18 __real@3ff0e5604189374c 000000014000cf18 CIL library: CIL module + 0002:00000f20 __real@3ff0000000000000 000000014000cf20 CIL library: CIL module + 0002:00000fc8 __real@4008000000000000 000000014000cfc8 CIL library: CIL module + 0002:00000fd0 __real@4000000000000000 000000014000cfd0 CIL library: CIL module + 0002:00001050 __real@4024000000000000 000000014000d050 CIL library: CIL module + 0002:00001410 ??_R4type_info@@6B@ 000000014000d410 MSVCRT:ti_inst.obj + 0002:00001438 ??_R3type_info@@8 000000014000d438 MSVCRT:ti_inst.obj + 0002:00001450 ??_R2type_info@@8 000000014000d450 MSVCRT:ti_inst.obj + 0002:00001460 ??_R1A@?0A@EA@type_info@@8 000000014000d460 MSVCRT:ti_inst.obj + 0002:00001488 ??_R4bad_alloc@std@@6B@ 000000014000d488 avbts_osnet.obj + 0002:000014b0 ??_R3bad_alloc@std@@8 000000014000d4b0 avbts_osnet.obj + 0002:000014c8 ??_R2bad_alloc@std@@8 000000014000d4c8 avbts_osnet.obj + 0002:000014e0 ??_R1A@?0A@EA@exception@std@@8 000000014000d4e0 avbts_osnet.obj + 0002:00001508 ??_R3exception@std@@8 000000014000d508 avbts_osnet.obj + 0002:00001520 ??_R2exception@std@@8 000000014000d520 avbts_osnet.obj + 0002:00001530 ??_R1A@?0A@EA@bad_alloc@std@@8 000000014000d530 avbts_osnet.obj + 0002:00001558 ??_R4InterfaceLabel@@6B@ 000000014000d558 ieee1588port.obj + 0002:00001580 ??_R4LinkLayerAddress@@6B@ 000000014000d580 ieee1588port.obj + 0002:000015a8 ??_R3LinkLayerAddress@@8 000000014000d5a8 ieee1588port.obj + 0002:000015c0 ??_R2LinkLayerAddress@@8 000000014000d5c0 ieee1588port.obj + 0002:000015d8 ??_R1A@?0A@EA@InterfaceLabel@@8 000000014000d5d8 ieee1588port.obj + 0002:00001600 ??_R3InterfaceLabel@@8 000000014000d600 ieee1588port.obj + 0002:00001618 ??_R2InterfaceLabel@@8 000000014000d618 ieee1588port.obj + 0002:00001628 ??_R1A@?0A@EA@LinkLayerAddress@@8 000000014000d628 ieee1588port.obj + 0002:00001650 ??_R4PTPMessageFollowUp@@6B@ 000000014000d650 ptp_message.obj + 0002:00001678 ??_R3PTPMessageFollowUp@@8 000000014000d678 ptp_message.obj + 0002:00001690 ??_R2PTPMessageFollowUp@@8 000000014000d690 ptp_message.obj + 0002:000016a8 ??_R1A@?0A@EA@PTPMessageFollowUp@@8 000000014000d6a8 ptp_message.obj + 0002:000016d0 ??_R4PTPMessagePathDelayRespFollowUp@@6B@ 000000014000d6d0 ptp_message.obj + 0002:000016f8 ??_R3PTPMessagePathDelayRespFollowUp@@8 000000014000d6f8 ptp_message.obj + 0002:00001710 ??_R2PTPMessagePathDelayRespFollowUp@@8 000000014000d710 ptp_message.obj + 0002:00001728 ??_R1A@?0A@EA@PTPMessagePathDelayRespFollowUp@@8 000000014000d728 ptp_message.obj + 0002:00001750 ??_R4PTPMessagePathDelayResp@@6B@ 000000014000d750 ptp_message.obj + 0002:00001778 ??_R3PTPMessagePathDelayResp@@8 000000014000d778 ptp_message.obj + 0002:00001790 ??_R2PTPMessagePathDelayResp@@8 000000014000d790 ptp_message.obj + 0002:000017a8 ??_R1A@?0A@EA@PTPMessagePathDelayResp@@8 000000014000d7a8 ptp_message.obj + 0002:000017d0 ??_R4PTPMessagePathDelayReq@@6B@ 000000014000d7d0 ptp_message.obj + 0002:000017f8 ??_R3PTPMessagePathDelayReq@@8 000000014000d7f8 ptp_message.obj + 0002:00001810 ??_R2PTPMessagePathDelayReq@@8 000000014000d810 ptp_message.obj + 0002:00001828 ??_R1A@?0A@EA@PTPMessagePathDelayReq@@8 000000014000d828 ptp_message.obj + 0002:00001850 ??_R4PTPMessageAnnounce@@6B@ 000000014000d850 ptp_message.obj + 0002:00001878 ??_R3PTPMessageAnnounce@@8 000000014000d878 ptp_message.obj + 0002:00001890 ??_R2PTPMessageAnnounce@@8 000000014000d890 ptp_message.obj + 0002:000018a8 ??_R1A@?0A@EA@PTPMessageAnnounce@@8 000000014000d8a8 ptp_message.obj + 0002:000018d0 ??_R4PTPMessageSync@@6B@ 000000014000d8d0 ptp_message.obj + 0002:000018f8 ??_R3PTPMessageSync@@8 000000014000d8f8 ptp_message.obj + 0002:00001910 ??_R2PTPMessageSync@@8 000000014000d910 ptp_message.obj + 0002:00001928 ??_R1A@?0A@EA@PTPMessageSync@@8 000000014000d928 ptp_message.obj + 0002:00001950 ??_R4PTPMessageCommon@@6B@ 000000014000d950 ptp_message.obj + 0002:00001978 ??_R3PTPMessageCommon@@8 000000014000d978 ptp_message.obj + 0002:00001990 ??_R2PTPMessageCommon@@8 000000014000d990 ptp_message.obj + 0002:000019a0 ??_R1A@?0A@EA@PTPMessageCommon@@8 000000014000d9a0 ptp_message.obj + 0002:000019c8 ??_R4WindowsNamedPipeIPC@@6B@ 000000014000d9c8 daemon_cl.obj + 0002:000019f0 ??_R3WindowsNamedPipeIPC@@8 000000014000d9f0 daemon_cl.obj + 0002:00001a08 ??_R2WindowsNamedPipeIPC@@8 000000014000da08 daemon_cl.obj + 0002:00001a20 ??_R1A@?0A@EA@WindowsNamedPipeIPC@@8 000000014000da20 daemon_cl.obj + 0002:00001a48 ??_R4WindowsTimestamper@@6B@ 000000014000da48 daemon_cl.obj + 0002:00001a70 ??_R3WindowsTimestamper@@8 000000014000da70 daemon_cl.obj + 0002:00001a88 ??_R2WindowsTimestamper@@8 000000014000da88 daemon_cl.obj + 0002:00001aa0 ??_R1A@?0A@EA@WindowsTimestamper@@8 000000014000daa0 daemon_cl.obj + 0002:00001ac8 ??_R4WindowsThreadFactory@@6B@ 000000014000dac8 daemon_cl.obj + 0002:00001af0 ??_R3WindowsThreadFactory@@8 000000014000daf0 daemon_cl.obj + 0002:00001b08 ??_R2WindowsThreadFactory@@8 000000014000db08 daemon_cl.obj + 0002:00001b20 ??_R1A@?0A@EA@WindowsThreadFactory@@8 000000014000db20 daemon_cl.obj + 0002:00001b48 ??_R4WindowsThread@@6B@ 000000014000db48 daemon_cl.obj + 0002:00001b70 ??_R3WindowsThread@@8 000000014000db70 daemon_cl.obj + 0002:00001b88 ??_R2WindowsThread@@8 000000014000db88 daemon_cl.obj + 0002:00001ba0 ??_R1A@?0A@EA@WindowsThread@@8 000000014000dba0 daemon_cl.obj + 0002:00001bc8 ??_R4WindowsTimerFactory@@6B@ 000000014000dbc8 daemon_cl.obj + 0002:00001bf0 ??_R3WindowsTimerFactory@@8 000000014000dbf0 daemon_cl.obj + 0002:00001c08 ??_R2WindowsTimerFactory@@8 000000014000dc08 daemon_cl.obj + 0002:00001c20 ??_R1A@?0A@EA@WindowsTimerFactory@@8 000000014000dc20 daemon_cl.obj + 0002:00001c48 ??_R4WindowsTimer@@6B@ 000000014000dc48 daemon_cl.obj + 0002:00001c70 ??_R3WindowsTimer@@8 000000014000dc70 daemon_cl.obj + 0002:00001c88 ??_R2WindowsTimer@@8 000000014000dc88 daemon_cl.obj + 0002:00001ca0 ??_R1A@?0A@EA@WindowsTimer@@8 000000014000dca0 daemon_cl.obj + 0002:00001cc8 ??_R4WindowsTimerQueueFactory@@6B@ 000000014000dcc8 daemon_cl.obj + 0002:00001cf0 ??_R3WindowsTimerQueueFactory@@8 000000014000dcf0 daemon_cl.obj + 0002:00001d08 ??_R2WindowsTimerQueueFactory@@8 000000014000dd08 daemon_cl.obj + 0002:00001d20 ??_R1A@?0A@EA@WindowsTimerQueueFactory@@8 000000014000dd20 daemon_cl.obj + 0002:00001d48 ??_R4WindowsTimerQueue@@6B@ 000000014000dd48 daemon_cl.obj + 0002:00001d70 ??_R3WindowsTimerQueue@@8 000000014000dd70 daemon_cl.obj + 0002:00001d88 ??_R2WindowsTimerQueue@@8 000000014000dd88 daemon_cl.obj + 0002:00001da0 ??_R1A@?0A@EA@WindowsTimerQueue@@8 000000014000dda0 daemon_cl.obj + 0002:00001dc8 ??_R4WindowsConditionFactory@@6B@ 000000014000ddc8 daemon_cl.obj + 0002:00001df0 ??_R3WindowsConditionFactory@@8 000000014000ddf0 daemon_cl.obj + 0002:00001e08 ??_R2WindowsConditionFactory@@8 000000014000de08 daemon_cl.obj + 0002:00001e20 ??_R1A@?0A@EA@WindowsConditionFactory@@8 000000014000de20 daemon_cl.obj + 0002:00001e48 ??_R4WindowsCondition@@6B@ 000000014000de48 daemon_cl.obj + 0002:00001e70 ??_R3WindowsCondition@@8 000000014000de70 daemon_cl.obj + 0002:00001e88 ??_R2WindowsCondition@@8 000000014000de88 daemon_cl.obj + 0002:00001ea0 ??_R1A@?0A@EA@WindowsCondition@@8 000000014000dea0 daemon_cl.obj + 0002:00001ec8 ??_R4WindowsLockFactory@@6B@ 000000014000dec8 daemon_cl.obj + 0002:00001ef0 ??_R3WindowsLockFactory@@8 000000014000def0 daemon_cl.obj + 0002:00001f08 ??_R2WindowsLockFactory@@8 000000014000df08 daemon_cl.obj + 0002:00001f20 ??_R1A@?0A@EA@WindowsLockFactory@@8 000000014000df20 daemon_cl.obj + 0002:00001f48 ??_R4WindowsLock@@6B@ 000000014000df48 daemon_cl.obj + 0002:00001f70 ??_R3WindowsLock@@8 000000014000df70 daemon_cl.obj + 0002:00001f88 ??_R2WindowsLock@@8 000000014000df88 daemon_cl.obj + 0002:00001fa0 ??_R1A@?0A@EA@WindowsLock@@8 000000014000dfa0 daemon_cl.obj + 0002:00001fc8 ??_R4WindowsPCAPNetworkInterfaceFactory@@6B@ 000000014000dfc8 daemon_cl.obj + 0002:00001ff0 ??_R3WindowsPCAPNetworkInterfaceFactory@@8 000000014000dff0 daemon_cl.obj + 0002:00002008 ??_R2WindowsPCAPNetworkInterfaceFactory@@8 000000014000e008 daemon_cl.obj + 0002:00002020 ??_R1A@?0A@EA@WindowsPCAPNetworkInterfaceFactory@@8 000000014000e020 daemon_cl.obj + 0002:00002048 ??_R4WindowsPCAPNetworkInterface@@6B@ 000000014000e048 daemon_cl.obj + 0002:00002070 ??_R3WindowsPCAPNetworkInterface@@8 000000014000e070 daemon_cl.obj + 0002:00002088 ??_R2WindowsPCAPNetworkInterface@@8 000000014000e088 daemon_cl.obj + 0002:000020a0 ??_R1A@?0A@EA@WindowsPCAPNetworkInterface@@8 000000014000e0a0 daemon_cl.obj + 0002:000020c8 ??_R3OS_IPC@@8 000000014000e0c8 daemon_cl.obj + 0002:000020e0 ??_R2OS_IPC@@8 000000014000e0e0 daemon_cl.obj + 0002:000020f0 ??_R1A@?0A@EA@OS_IPC@@8 000000014000e0f0 daemon_cl.obj + 0002:00002118 ??_R3OSTimerQueueFactory@@8 000000014000e118 daemon_cl.obj + 0002:00002130 ??_R2OSTimerQueueFactory@@8 000000014000e130 daemon_cl.obj + 0002:00002140 ??_R1A@?0A@EA@OSTimerQueueFactory@@8 000000014000e140 daemon_cl.obj + 0002:00002168 ??_R3OSTimerQueue@@8 000000014000e168 daemon_cl.obj + 0002:00002180 ??_R2OSTimerQueue@@8 000000014000e180 daemon_cl.obj + 0002:00002190 ??_R1A@?0A@EA@OSTimerQueue@@8 000000014000e190 daemon_cl.obj + 0002:000021b8 ??_R3OSConditionFactory@@8 000000014000e1b8 daemon_cl.obj + 0002:000021d0 ??_R2OSConditionFactory@@8 000000014000e1d0 daemon_cl.obj + 0002:000021e0 ??_R1A@?0A@EA@OSConditionFactory@@8 000000014000e1e0 daemon_cl.obj + 0002:00002208 ??_R3OSCondition@@8 000000014000e208 daemon_cl.obj + 0002:00002220 ??_R2OSCondition@@8 000000014000e220 daemon_cl.obj + 0002:00002230 ??_R1A@?0A@EA@OSCondition@@8 000000014000e230 daemon_cl.obj + 0002:00002258 ??_R3OSThreadFactory@@8 000000014000e258 daemon_cl.obj + 0002:00002270 ??_R2OSThreadFactory@@8 000000014000e270 daemon_cl.obj + 0002:00002280 ??_R1A@?0A@EA@OSThreadFactory@@8 000000014000e280 daemon_cl.obj + 0002:000022a8 ??_R3OSThread@@8 000000014000e2a8 daemon_cl.obj + 0002:000022c0 ??_R2OSThread@@8 000000014000e2c0 daemon_cl.obj + 0002:000022d0 ??_R1A@?0A@EA@OSThread@@8 000000014000e2d0 daemon_cl.obj + 0002:000022f8 ??_R3OSLockFactory@@8 000000014000e2f8 daemon_cl.obj + 0002:00002310 ??_R2OSLockFactory@@8 000000014000e310 daemon_cl.obj + 0002:00002320 ??_R1A@?0A@EA@OSLockFactory@@8 000000014000e320 daemon_cl.obj + 0002:00002348 ??_R3OSLock@@8 000000014000e348 daemon_cl.obj + 0002:00002360 ??_R2OSLock@@8 000000014000e360 daemon_cl.obj + 0002:00002370 ??_R1A@?0A@EA@OSLock@@8 000000014000e370 daemon_cl.obj + 0002:00002398 ??_R3OSTimerFactory@@8 000000014000e398 daemon_cl.obj + 0002:000023b0 ??_R2OSTimerFactory@@8 000000014000e3b0 daemon_cl.obj + 0002:000023c0 ??_R1A@?0A@EA@OSTimerFactory@@8 000000014000e3c0 daemon_cl.obj + 0002:000023e8 ??_R3OSTimer@@8 000000014000e3e8 daemon_cl.obj + 0002:00002400 ??_R2OSTimer@@8 000000014000e400 daemon_cl.obj + 0002:00002410 ??_R1A@?0A@EA@OSTimer@@8 000000014000e410 daemon_cl.obj + 0002:00002438 ??_R3OSNetworkInterfaceFactory@@8 000000014000e438 daemon_cl.obj + 0002:00002450 ??_R2OSNetworkInterfaceFactory@@8 000000014000e450 daemon_cl.obj + 0002:00002460 ??_R1A@?0A@EA@OSNetworkInterfaceFactory@@8 000000014000e460 daemon_cl.obj + 0002:00002488 ??_R3OSNetworkInterface@@8 000000014000e488 daemon_cl.obj + 0002:000024a0 ??_R2OSNetworkInterface@@8 000000014000e4a0 daemon_cl.obj + 0002:000024b0 ??_R1A@?0A@EA@OSNetworkInterface@@8 000000014000e4b0 daemon_cl.obj + 0002:000024d8 ??_R4HWTimestamper@@6B@ 000000014000e4d8 daemon_cl.obj + 0002:00002500 ??_R3HWTimestamper@@8 000000014000e500 daemon_cl.obj + 0002:00002518 ??_R2HWTimestamper@@8 000000014000e518 daemon_cl.obj + 0002:00002528 ??_R1A@?0A@EA@HWTimestamper@@8 000000014000e528 daemon_cl.obj + 0002:00002550 __rtc_iaa 000000014000e550 MSVCRT:_initsect_.obj + 0002:00002558 __rtc_izz 000000014000e558 MSVCRT:_initsect_.obj + 0002:00002560 __rtc_taa 000000014000e560 MSVCRT:_initsect_.obj + 0002:00002568 __rtc_tzz 000000014000e568 MSVCRT:_initsect_.obj + 0002:00003750 _CT??_R0?AVbad_alloc@std@@@8??0bad_alloc@std@@QEAA@AEBV01@@Z24 000000014000f750 avbts_osnet.obj + 0002:00003778 _CT??_R0?AVexception@std@@@8??0exception@std@@QEAA@AEBV01@@Z24 000000014000f778 avbts_osnet.obj + 0002:000037a0 _CTA2?AVbad_alloc@std@@ 000000014000f7a0 avbts_osnet.obj + 0002:000037b8 _TI2?AVbad_alloc@std@@ 000000014000f7b8 avbts_osnet.obj + 0002:000037d4 __IMPORT_DESCRIPTOR_wpcap 000000014000f7d4 wpcap:wpcap.dll + 0002:000037e8 __IMPORT_DESCRIPTOR_IPHLPAPI 000000014000f7e8 Iphlpapi:IPHLPAPI.DLL + 0002:000037fc __IMPORT_DESCRIPTOR_WS2_32 000000014000f7fc ws2_32:WS2_32.dll + 0002:00003810 __IMPORT_DESCRIPTOR_KERNEL32 000000014000f810 kernel32:KERNEL32.dll + 0002:00003824 __IMPORT_DESCRIPTOR_MSVCP100 000000014000f824 msvcprt:MSVCP100.dll + 0002:00003838 __IMPORT_DESCRIPTOR_MSVCR100 000000014000f838 MSVCRT:MSVCR100.dll + 0002:0000384c __NULL_IMPORT_DESCRIPTOR 000000014000f84c wpcap:wpcap.dll + 0003:00000000 ??_R0?AVtype_info@@@8 0000000140011000 MSVCRT:ti_inst.obj + 0003:00000020 __security_cookie 0000000140011020 MSVCRT:gs_cookie.obj + 0003:00000028 __security_cookie_complement 0000000140011028 MSVCRT:gs_cookie.obj + 0003:00000030 __native_dllmain_reason 0000000140011030 MSVCRT:natstart.obj + 0003:00000034 __native_vcclrit_reason 0000000140011034 MSVCRT:natstart.obj + 0003:00000038 __globallocalestatus 0000000140011038 MSVCRT:xthdloc.obj + 0003:0000003c __defaultmatherr 000000014001103c MSVCRT:merr.obj + 0003:00000040 ??_R0?AVbad_alloc@std@@@8 0000000140011040 avbts_osnet.obj + 0003:00000068 ??_R0?AVexception@std@@@8 0000000140011068 avbts_osnet.obj + 0003:00000090 ??_R0?AVInterfaceLabel@@@8 0000000140011090 ieee1588port.obj + 0003:000000b8 ??_R0?AVLinkLayerAddress@@@8 00000001400110b8 ieee1588port.obj + 0003:000000e0 ??_R0?AVPTPMessageFollowUp@@@8 00000001400110e0 ptp_message.obj + 0003:00000110 ??_R0?AVPTPMessagePathDelayRespFollowUp@@@8 0000000140011110 ptp_message.obj + 0003:00000148 ??_R0?AVPTPMessagePathDelayResp@@@8 0000000140011148 ptp_message.obj + 0003:00000178 ??_R0?AVPTPMessagePathDelayReq@@@8 0000000140011178 ptp_message.obj + 0003:000001a8 ??_R0?AVPTPMessageAnnounce@@@8 00000001400111a8 ptp_message.obj + 0003:000001d8 ??_R0?AVPTPMessageSync@@@8 00000001400111d8 ptp_message.obj + 0003:00000200 ??_R0?AVPTPMessageCommon@@@8 0000000140011200 ptp_message.obj + 0003:00000228 ??_R0?AVWindowsNamedPipeIPC@@@8 0000000140011228 daemon_cl.obj + 0003:00000258 ??_R0?AVWindowsTimestamper@@@8 0000000140011258 daemon_cl.obj + 0003:00000288 ??_R0?AVWindowsThreadFactory@@@8 0000000140011288 daemon_cl.obj + 0003:000002b8 ??_R0?AVWindowsThread@@@8 00000001400112b8 daemon_cl.obj + 0003:000002e0 ??_R0?AVWindowsTimerFactory@@@8 00000001400112e0 daemon_cl.obj + 0003:00000310 ??_R0?AVWindowsTimer@@@8 0000000140011310 daemon_cl.obj + 0003:00000338 ??_R0?AVWindowsTimerQueueFactory@@@8 0000000140011338 daemon_cl.obj + 0003:00000368 ??_R0?AVWindowsTimerQueue@@@8 0000000140011368 daemon_cl.obj + 0003:00000390 ??_R0?AVWindowsConditionFactory@@@8 0000000140011390 daemon_cl.obj + 0003:000003c0 ??_R0?AVWindowsCondition@@@8 00000001400113c0 daemon_cl.obj + 0003:000003e8 ??_R0?AVWindowsLockFactory@@@8 00000001400113e8 daemon_cl.obj + 0003:00000418 ??_R0?AVWindowsLock@@@8 0000000140011418 daemon_cl.obj + 0003:00000440 ??_R0?AVWindowsPCAPNetworkInterfaceFactory@@@8 0000000140011440 daemon_cl.obj + 0003:00000480 ??_R0?AVWindowsPCAPNetworkInterface@@@8 0000000140011480 daemon_cl.obj + 0003:000004b8 ??_R0?AVOS_IPC@@@8 00000001400114b8 daemon_cl.obj + 0003:000004d8 ??_R0?AVOSTimerQueueFactory@@@8 00000001400114d8 daemon_cl.obj + 0003:00000508 ??_R0?AVOSTimerQueue@@@8 0000000140011508 daemon_cl.obj + 0003:00000530 ??_R0?AVOSConditionFactory@@@8 0000000140011530 daemon_cl.obj + 0003:00000560 ??_R0?AVOSCondition@@@8 0000000140011560 daemon_cl.obj + 0003:00000588 ??_R0?AVOSThreadFactory@@@8 0000000140011588 daemon_cl.obj + 0003:000005b0 ??_R0?AVOSThread@@@8 00000001400115b0 daemon_cl.obj + 0003:000005d0 ??_R0?AVOSLockFactory@@@8 00000001400115d0 daemon_cl.obj + 0003:000005f8 ??_R0?AVOSLock@@@8 00000001400115f8 daemon_cl.obj + 0003:00000618 ??_R0?AVOSTimerFactory@@@8 0000000140011618 daemon_cl.obj + 0003:00000640 ??_R0?AVOSTimer@@@8 0000000140011640 daemon_cl.obj + 0003:00000660 ??_R0?AVOSNetworkInterfaceFactory@@@8 0000000140011660 daemon_cl.obj + 0003:00000690 ??_R0?AVOSNetworkInterface@@@8 0000000140011690 daemon_cl.obj + 0003:000006c0 ??_R0?AVHWTimestamper@@@8 00000001400116c0 daemon_cl.obj + 0003:000006e8 ?other_multicast@IEEE1588Port@@0VLinkLayerAddress@@A 00000001400116e8 ieee1588port.obj + 0003:000006f8 ?pdelay_multicast@IEEE1588Port@@0VLinkLayerAddress@@A 00000001400116f8 ieee1588port.obj + 0003:00000710 _fltused 0000000140011710 MSVCRT:dllsupp.obj + 0003:00000cc0 _dowildcard 0000000140011cc0 MSVCRT:wildcard.obj + 0003:00000cc4 _newmode 0000000140011cc4 MSVCRT:_newmode.obj + 0003:00000cc8 _commode 0000000140011cc8 MSVCRT:xncommod.obj + 0003:00000ccc _fmode 0000000140011ccc MSVCRT:xtxtmode.obj + 0003:00000cd8 ?factoryMap@OSNetworkInterfaceFactory@@0V?$map@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@@std@@A 0000000140011cd8 avbts_osnet.obj + 0003:00000cf8 __native_startup_state 0000000140011cf8 + 0003:00000d00 __native_startup_lock 0000000140011d00 + 0003:00000d08 __dyn_tls_init_callback 0000000140011d08 + 0003:00000d10 __onexitend 0000000140011d10 + 0003:00000d18 __onexitbegin 0000000140011d18 + + entry point at 0001:0000991c + + Static symbols + + 0001:00009664 pre_cpp_init 000000014000a664 f MSVCRT:crtexe.obj + 0001:000096cc __tmainCRTStartup 000000014000a6cc f MSVCRT:crtexe.obj + 0001:0000984c pre_c_init 000000014000a84c f MSVCRT:crtexe.obj + 0001:00009f60 _onexit$fin$0 000000014000af60 f MSVCRT:atonexit.obj + 0001:00009f7b __tmainCRTStartup$filt$0 000000014000af7b f MSVCRT:crtexe.obj + 0001:00009f99 ?filt$0@?0??__ArrayUnwind@@YAXPEAX_KHP6AX0@Z@Z@4HA 000000014000af99 f MSVCRT:ehvecdtr.obj + 0001:00009fda ?fin$0@?0???_M@YAXPEAX_KHP6AX0@Z@Z@4HA 000000014000afda f MSVCRT:ehvecdtr.obj + 0001:0000a010 _IsNonwritableInCurrentImage$filt$0 000000014000b010 f MSVCRT:pesect.obj + 0001:0000a040 ?catch$0@?0???$_Insert@V?$_List_const_iterator@V?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@@std@@@?$list@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAAXV?$_List_const_iterator@V?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@@1@00Uforward_iterator_tag@1@@Z@4HA 000000014000b040 f CIL library: CIL module + 0001:0000a04f __catch$??$_Insert@V?$_List_const_iterator@V?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@@std@@@?$list@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAAXV?$_List_const_iterator@V?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@@1@00Uforward_iterator_tag@1@@Z$0 000000014000b04f f CIL library: CIL module + 0001:0000a0b0 ?dtor$0@?0???0?$list@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAA@AEBV01@@Z@4HA 000000014000b0b0 f CIL library: CIL module + 0001:0000a0c0 ?catch$0@?0???0?$list@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAA@AEBV01@@Z@4HA 000000014000b0c0 f CIL library: CIL module + 0001:0000a0cd __catch$??0?$list@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAA@AEBV01@@Z$0 000000014000b0cd f CIL library: CIL module + 0001:0000a0e0 ?catch$0@?0??_Buynode@?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAAPEAU_Node@?$_List_nod@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@2@PEAU342@0AEBQEAUWindowsTimerQueueHandlerArg@@@Z@4HA 000000014000b0e0 f CIL library: CIL module + 0001:0000a0e0 ?catch$0@?0??_Buynode@?$_List_val@PEAVPTPMessageAnnounce@@V?$allocator@PEAVPTPMessageAnnounce@@@std@@@std@@QEAAPEAU_Node@?$_List_nod@PEAVPTPMessageAnnounce@@V?$allocator@PEAVPTPMessageAnnounce@@@std@@@2@PEAU342@0AEBQEAVPTPMessageAnnounce@@@Z@4HA 000000014000b0e0 f CIL library: CIL module + 0001:0000a0ed __catch$?_Buynode@?$_List_val@PEAVPTPMessageAnnounce@@V?$allocator@PEAVPTPMessageAnnounce@@@std@@@std@@QEAAPEAU_Node@?$_List_nod@PEAVPTPMessageAnnounce@@V?$allocator@PEAVPTPMessageAnnounce@@@std@@@2@PEAU342@0AEBQEAVPTPMessageAnnounce@@@Z$0 000000014000b0ed f CIL library: CIL module + 0001:0000a0ed __catch$?_Buynode@?$_List_val@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@std@@QEAAPEAU_Node@?$_List_nod@PEAUWindowsTimerQueueHandlerArg@@V?$allocator@PEAUWindowsTimerQueueHandlerArg@@@std@@@2@PEAU342@0AEBQEAUWindowsTimerQueueHandlerArg@@@Z$0 000000014000b0ed f CIL library: CIL module + 0001:0000a110 ?dtor$0@?0???0PTPMessagePathDelayResp@@QEAA@PEAVIEEE1588Port@@@Z@4HA 000000014000b110 f CIL library: CIL module + 0001:0000a110 ?dtor$0@?0???0PTPMessageAnnounce@@QEAA@PEAVIEEE1588Port@@@Z@4HA 000000014000b110 f CIL library: CIL module + 0001:0000a110 ?dtor$0@?0???0PTPMessagePathDelayRespFollowUp@@QEAA@PEAVIEEE1588Port@@@Z@4HA 000000014000b110 f CIL library: CIL module + 0001:0000a120 ?catch$0@?0???$_Buynode@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@1@$$QEAU?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@1@@Z@4HA 000000014000b120 f CIL library: CIL module + 0001:0000a12d __catch$??$_Buynode@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@?$_Tree_val@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@$0A@@std@@@1@$$QEAU?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@1@@Z$0 000000014000b12d f CIL library: CIL module + 0001:0000a150 ?catch$0@?0???$_Buynode@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@1@$$QEAU?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@1@@Z@4HA 000000014000b150 f CIL library: CIL module + 0001:0000a15d __catch$??$_Buynode@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@?$_Tree_val@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@$0A@@std@@@1@$$QEAU?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@1@@Z$0 000000014000b15d f CIL library: CIL module + 0001:0000a180 ?dtor$0@?0???$_Buynode@U?$pair@$$CBHUTimerQueue_t@@@std@@@?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@1@$$QEAU?$pair@$$CBHUTimerQueue_t@@@1@@Z@4HA 000000014000b180 f CIL library: CIL module + 0001:0000a1a0 ?catch$0@?0???$_Buynode@U?$pair@$$CBHUTimerQueue_t@@@std@@@?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@1@$$QEAU?$pair@$$CBHUTimerQueue_t@@@1@@Z@4HA 000000014000b1a0 f CIL library: CIL module + 0001:0000a1ad __catch$??$_Buynode@U?$pair@$$CBHUTimerQueue_t@@@std@@@?$_Tree_val@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@std@@QEAAPEAU_Node@?$_Tree_nod@V?$_Tmap_traits@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@$0A@@std@@@1@$$QEAU?$pair@$$CBHUTimerQueue_t@@@1@@Z$0 000000014000b1ad f CIL library: CIL module + 0001:0000a1d0 ?dtor$1@?0???1?$map@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@@std@@QEAA@XZ@4HA 000000014000b1d0 f CIL library: CIL module + 0001:0000a1d0 ?dtor$1@?0???1?$map@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@@std@@QEAA@XZ@4HA 000000014000b1d0 f CIL library: CIL module + 0001:0000a1e0 ?dtor$0@?0???0WindowsTimerQueue@@IEAA@XZ@4HA 000000014000b1e0 f CIL library: CIL module + 0001:0000a1f0 ?dtor$0@?0???A?$map@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@@std@@QEAAAEAVLinkLayerAddress@@AEBVPortIdentity@@@Z@4HA 000000014000b1f0 f CIL library: CIL module + 0001:0000a200 ?dtor$1@?0???A?$map@VPortIdentity@@VLinkLayerAddress@@U?$less@VPortIdentity@@@std@@V?$allocator@U?$pair@$$CBVPortIdentity@@VLinkLayerAddress@@@std@@@4@@std@@QEAAAEAVLinkLayerAddress@@AEBVPortIdentity@@@Z@4HA 000000014000b200 f CIL library: CIL module + 0001:0000a210 ?dtor$0@?0???0IEEE1588Port@@QEAA@PEAVIEEE1588Clock@@G_NPEAVHWTimestamper@@1HPEAVInterfaceLabel@@PEAVOSConditionFactory@@PEAVOSThreadFactory@@PEAVOSTimerFactory@@PEAVOSLockFactory@@@Z@4HA 000000014000b210 f CIL library: CIL module + 0001:0000a220 ?dtor$1@?0???0IEEE1588Port@@QEAA@PEAVIEEE1588Clock@@G_NPEAVHWTimestamper@@1HPEAVInterfaceLabel@@PEAVOSConditionFactory@@PEAVOSThreadFactory@@PEAVOSTimerFactory@@PEAVOSLockFactory@@@Z@4HA 000000014000b220 f CIL library: CIL module + 0001:0000a240 ?dtor$2@?0???0IEEE1588Port@@QEAA@PEAVIEEE1588Clock@@G_NPEAVHWTimestamper@@1HPEAVInterfaceLabel@@PEAVOSConditionFactory@@PEAVOSThreadFactory@@PEAVOSTimerFactory@@PEAVOSLockFactory@@@Z@4HA 000000014000b240 f CIL library: CIL module + 0001:0000a260 ?dtor$0@?0???A?$map@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@@std@@QEAAAEAUTimerQueue_t@@AEBH@Z@4HA 000000014000b260 f CIL library: CIL module + 0001:0000a270 ?dtor$1@?0???A?$map@HUTimerQueue_t@@U?$less@H@std@@V?$allocator@U?$pair@$$CBHUTimerQueue_t@@@std@@@3@@std@@QEAAAEAUTimerQueue_t@@AEBH@Z@4HA 000000014000b270 f CIL library: CIL module + 0001:0000a280 ?dtor$0@?0??createOSTimerQueue@WindowsTimerQueueFactory@@UEAAPEAVOSTimerQueue@@XZ@4HA 000000014000b280 f CIL library: CIL module + 0001:0000a290 ?dtor$8@?0??buildPTPMessage@@YAPEAVPTPMessageCommon@@PEADHPEAVLinkLayerAddress@@PEAVIEEE1588Port@@@Z@4HA 000000014000b290 f CIL library: CIL module + 0001:0000a2a0 ?dtor$10@?0??buildPTPMessage@@YAPEAVPTPMessageCommon@@PEADHPEAVLinkLayerAddress@@PEAVIEEE1588Port@@@Z@4HA 000000014000b2a0 f CIL library: CIL module + 0001:0000a2b0 ?dtor$0@?0??openPort@IEEE1588Port@@QEAAPEAXXZ@4HA 000000014000b2b0 f CIL library: CIL module + 0001:0000a2c0 ?dtor$0@?0??processMessage@PTPMessagePathDelayReq@@UEAAXPEAVIEEE1588Port@@@Z@4HA 000000014000b2c0 f CIL library: CIL module + 0001:0000a2d0 ?dtor$1@?0??processMessage@PTPMessagePathDelayReq@@UEAAXPEAVIEEE1588Port@@@Z@4HA 000000014000b2d0 f CIL library: CIL module + 0001:0000a2e0 ?dtor$0@?0??sendPort@PTPMessagePathDelayReq@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z@4HA 000000014000b2e0 f CIL library: CIL module + 0001:0000a2e0 ?dtor$0@?0??sendPort@PTPMessagePathDelayResp@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z@4HA 000000014000b2e0 f CIL library: CIL module + 0001:0000a2e0 ?dtor$0@?0??sendPort@PTPMessagePathDelayRespFollowUp@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z@4HA 000000014000b2e0 f CIL library: CIL module + 0001:0000a2e0 ?dtor$0@?0??sendPort@PTPMessageAnnounce@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z@4HA 000000014000b2e0 f CIL library: CIL module + 0001:0000a2e0 ?dtor$0@?0??sendPort@PTPMessageFollowUp@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z@4HA 000000014000b2e0 f CIL library: CIL module + 0001:0000a2e0 ?dtor$0@?0??sendPort@PTPMessageSync@@QEAAXPEAVIEEE1588Port@@PEAVPortIdentity@@@Z@4HA 000000014000b2e0 f CIL library: CIL module + 0001:0000a2f0 ?dtor$0@?0??processEvent@IEEE1588Port@@QEAAXW4Event@@@Z@4HA 000000014000b2f0 f CIL library: CIL module + 0001:0000a300 ?dtor$1@?0??processEvent@IEEE1588Port@@QEAAXW4Event@@@Z@4HA 000000014000b300 f CIL library: CIL module + 0001:0000a310 ?dtor$2@?0??processEvent@IEEE1588Port@@QEAAXW4Event@@@Z@4HA 000000014000b310 f CIL library: CIL module + 0001:0000a320 ?dtor$3@?0??processEvent@IEEE1588Port@@QEAAXW4Event@@@Z@4HA 000000014000b320 f CIL library: CIL module + 0001:0000a330 main$dtor$1 000000014000b330 f CIL library: CIL module + 0001:0000a340 main$dtor$2 000000014000b340 f CIL library: CIL module + 0001:0000a350 main$dtor$3 000000014000b350 f CIL library: CIL module + 0001:0000a360 ?dtor$1@?0???__F?factoryMap@OSNetworkInterfaceFactory@@0V?$map@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@@std@@A@@YAXXZ@4HA 000000014000b360 f CIL library: CIL module + 0001:0000a370 ??__E?factoryMap@OSNetworkInterfaceFactory@@0V?$map@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@@std@@A@@YAXXZ 000000014000b370 f CIL library: CIL module + 0001:0000a390 ??__E?other_multicast@IEEE1588Port@@0VLinkLayerAddress@@A@@YAXXZ 000000014000b390 f CIL library: CIL module + 0001:0000a3e0 ??__E?pdelay_multicast@IEEE1588Port@@0VLinkLayerAddress@@A@@YAXXZ 000000014000b3e0 f CIL library: CIL module + 0001:0000a430 ??__F?factoryMap@OSNetworkInterfaceFactory@@0V?$map@Vfactory_name_t@@PEAVOSNetworkInterfaceFactory@@U?$less@Vfactory_name_t@@@std@@V?$allocator@U?$pair@$$CBVfactory_name_t@@PEAVOSNetworkInterfaceFactory@@@std@@@4@@std@@A@@YAXXZ 000000014000b430 f CIL library: CIL module + 0001:0000a470 ??__F?other_multicast@IEEE1588Port@@0VLinkLayerAddress@@A@@YAXXZ 000000014000b470 f CIL library: CIL module + 0001:0000a480 ??__F?pdelay_multicast@IEEE1588Port@@0VLinkLayerAddress@@A@@YAXXZ 000000014000b480 f CIL library: CIL module diff --git a/daemons/mrpd/README b/daemons/mrpd/README new file mode 100644 index 0000000..e68d938 --- /dev/null +++ b/daemons/mrpd/README @@ -0,0 +1,11 @@ +INTRODUCTION + +The MRP daemon is required to establish stream reservations with compatible AVB +infrastructure devices. The command line selectively enables MMRP (via the +-m option), MVRP (via the -v option), and MSRP (via the -s option). You must +also specify the interface on which you want to bind the daemon to +(e.g. -i eth2). The full command line typically appears as follows: + sudo ./mrpd -mvs -i eth2 + +Sample client applications - mrpctl, mrpq, mrpl - illustrate how to connect, +query and add attributes to the MRP daemon. diff --git a/examples/Makefile b/examples/Makefile deleted file mode 100644 index a25b198..0000000 --- a/examples/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -OPT=-O2 -#CFLAGS=$(OPT) -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -ggdb -CFLAGS=$(OPT) -Wall -W -Wno-parentheses -ggdb - -CC=gcc -INCFLAGS=-I../lib -LDLIBS=-ligb -lpci -lz -pthread -LDFLAGS=-L../lib - -all: test latency_test simple_talker mrpq mrpl - -test: test.o - -simple_talker: simple_talker.o - -mrpl: mrpl.o - -mrpq: mrpq.o - -latency_test: latency_test.o - -latency_test.o: latency_test.c - gcc -c $(INCFLAGS) $(CFLAGS) latency_test.c - -test.o: test.c - gcc -c $(INCFLAGS) $(CFLAGS) test.c - -simple_talker.o: simple_talker.c - gcc -c $(INCFLAGS) -I../daemons/mrpd $(CFLAGS) simple_talker.c - -mrpl.o: mrpl.c - gcc -c $(INCFLAGS) -I../daemons/mrpd $(CFLAGS) mrpl.c - -mrpq.o: mrpq.c - gcc -c $(INCFLAGS) -I../daemons/mrpd $(CFLAGS) mrpq.c - -%: %.o - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -clean: - rm -f `find . -name "*~" -o -name "*.[oa]" -o -name "\#*\#" -o -name TAGS -o -name core -o -name "*.orig"` - diff --git a/examples/latency_test.c b/examples/latency_test.c deleted file mode 100644 index 70d0787..0000000 --- a/examples/latency_test.c +++ /dev/null @@ -1,305 +0,0 @@ -/****************************************************************************** - - Copyright (c) 2001-2012, Intel Corporation - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. 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. - - 3. Neither the name of the Intel Corporation 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. - -******************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include "igb.h" - -#define IGB_BIND_NAMESZ 24 - -device_t igb_dev; -volatile int halt_tx; - -void -sigint_handler (int signum) -{ - printf("halting ...\n"); - halt_tx = signum; -} - -int -connect() -{ - struct pci_access *pacc; - struct pci_dev *dev; - int err; - char devpath[IGB_BIND_NAMESZ]; - - memset(&igb_dev, 0, sizeof(device_t)); - - pacc = pci_alloc(); - pci_init(pacc); - pci_scan_bus(pacc); - for (dev=pacc->devices; dev; dev=dev->next) - { - pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); - - igb_dev.pci_vendor_id = dev->vendor_id; - igb_dev.pci_device_id = dev->device_id; - igb_dev.domain = dev->domain; - igb_dev.bus = dev->bus; - igb_dev.dev = dev->dev; - igb_dev.func = dev->func; - - snprintf(devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d", \ - dev->domain, dev->bus, dev->dev, dev->func ); - printf("probing %s\n", devpath); - - err = igb_probe(&igb_dev); - - if (err) { - continue; - } - - printf ("attaching to %s\n", devpath); - err = igb_attach(devpath, &igb_dev); - - if (err) { - printf ("attach failed! (%s)\n", strerror(errno)); - continue; - } - printf("attach successful to %s\n", devpath); - goto out; - } - - pci_cleanup(pacc); - return ENXIO; - -out: - pci_cleanup(pacc); - return 0; - -} - -#define VERSION_STR "1.0" - -static const char *version_str = -"latency test v" VERSION_STR "\n" -"Copyright (c) 2012, Intel Corporation\n"; - - -static void -usage( void ) { - fprintf(stderr, - "\n" - "usage: latency_test [-hr] [-d ]" - "\n" - "options:\n" - " -h show this message\n" - " -d observation window (seconds)\n" - " -p delay from sw schedule to hw transmit in usec (defaults to 20 msec)\n" - "\n" - "%s" - "\n", version_str); - exit(1); -} - -#define PACKET_IPG (20000000) /* 20 msec */ - -int -main(int argc, char *argv[]) { - int c; - unsigned i; - unsigned tqavctl; - int err; - struct igb_dma_alloc a_page; - struct igb_packet a_packet; - struct igb_packet *tmp_packet; - struct igb_packet *cleaned_packets; - struct igb_packet *free_packets; - u_int64_t last_time; - u_int64_t rdtsc0; - unsigned int captured_latency; - int obs_window = 1; - int obs_window_count; - int ipg = PACKET_IPG / 1000; - - unsigned int min = 0xFFFFFFFF; - unsigned int max = 0; - float avg = 0.0; - - for (;;) { - c = getopt(argc, argv, "hrp:d:"); - - if (c < 0) - break; - - switch (c) { - default: - case 'h': - usage(); - break; - case 'p': - sscanf(optarg, "%d", &ipg); - break; - case 'd': - sscanf(optarg, "%d", &obs_window); - break; - } - } - if (optind < argc) - usage(); - - ipg *= 1000; /* scale to nsec */ - - if (ipg > 400000000) { printf("specified delay is too large \n"); return(-1); } - - err = connect(); - - if (err) { printf("connect failed (%s)\n", strerror(errno)); return(errno); } - - err = igb_init(&igb_dev); - - if (err) { printf("init failed (%s)\n", strerror(errno)); return(errno); } - - err = igb_dma_malloc_page(&igb_dev, &a_page); - - if (err) { printf("malloc failed (%s)\n", strerror(errno)); return(errno); } - -#define PKT_SZ 200 - memset(&a_packet, 0, sizeof(a_packet)); - - a_packet.dmatime = a_packet.attime = a_packet.flags = 0; - a_packet.map.paddr = a_page.dma_paddr; - a_packet.map.mmap_size = a_page.mmap_size; - - a_packet.offset = 0; - a_packet.vaddr = a_page.dma_vaddr + a_packet.offset; - a_packet.len = PKT_SZ; - - free_packets = NULL; - - /* divide the dma page into buffers for packets */ - for (i = 1; i < ((a_page.mmap_size) / PKT_SZ); i++) { - tmp_packet = malloc(sizeof(struct igb_packet)); - if (NULL == tmp_packet) { printf("malloc failed (%s)\n", strerror(errno)); return(errno); } - *tmp_packet = a_packet; - tmp_packet->offset = (i * PKT_SZ); - tmp_packet->vaddr += tmp_packet->offset; - tmp_packet->next = free_packets; - memset(tmp_packet->vaddr, 0xffffffff, PKT_SZ); /* MAC header at least */ - free_packets = tmp_packet; - } - - igb_set_class_bandwidth(&igb_dev, 0, 0, 0); /* disable Qav */ - igb_readreg(&igb_dev, 0x3570, &tqavctl); - tqavctl &= 0xFFFF; /* zero-out the prefetch delay */ - igb_writereg(&igb_dev, 0x3570, tqavctl); - - halt_tx = 0; - signal(SIGINT, sigint_handler); - - - igb_get_wallclock(&igb_dev, &last_time, &rdtsc0); - - obs_window_count = obs_window; - - while (!halt_tx) { - tmp_packet = free_packets; - - if (NULL == tmp_packet) goto cleanup; - - free_packets = tmp_packet->next; - - igb_get_wallclock(&igb_dev, &last_time, &rdtsc0); - - tmp_packet->attime = last_time + ipg; - *(u_int64_t *)(tmp_packet->vaddr + 32) = tmp_packet->attime; - - err = igb_xmit(&igb_dev, 0, tmp_packet); - - if (ENOSPC == err) { - /* put back for now */ - tmp_packet->next = free_packets; - free_packets = tmp_packet; - } - - sleep(1); /* sleep 1 sec */ - -cleanup: - igb_clean(&igb_dev, &cleaned_packets); - i = 0; - while (cleaned_packets) { - i++; - tmp_packet = cleaned_packets; - cleaned_packets = cleaned_packets->next; - /* remap attime to compare to dma time */ - while (tmp_packet->attime > 999999999) tmp_packet->attime -= 1000000000; - if ((tmp_packet->attime > 999000000) && (tmp_packet->dmatime < 1000000)) - captured_latency = (unsigned int)(1000000000 - tmp_packet->attime + tmp_packet->dmatime); - else - captured_latency = (unsigned int)(tmp_packet->dmatime - tmp_packet->attime); - - if (captured_latency < min) - min = captured_latency; - - if (captured_latency > max) - max = captured_latency; - - avg += ((float)captured_latency / (float)obs_window); - - tmp_packet->next = free_packets; - free_packets = tmp_packet; - } - obs_window_count--; - if (0 == obs_window_count) { - obs_window_count = obs_window; - printf("min = %d max = %d avg = %f\n", min, max, avg); - min = 0xFFFFFFFF; - max = 0; - avg = 0.0; - } - - } - - igb_dma_free_page(&igb_dev, &a_page); - err = igb_detach(&igb_dev); - return(0); -} - diff --git a/examples/mrp_client/Makefile b/examples/mrp_client/Makefile new file mode 100644 index 0000000..a9d5414 --- /dev/null +++ b/examples/mrp_client/Makefile @@ -0,0 +1,26 @@ +OPT=-O2 +CFLAGS=$(OPT) -Wall -W -Wno-parentheses -ggdb + +CC=gcc +INCFLAGS=-I../../lib/igb +LDLIBS=-ligb -lpci -lz -pthread +LDFLAGS=-L../../lib/igb + +all: mrpq mrpl + +mrpl: mrpl.o + +mrpq: mrpq.o + +mrpl.o: mrpl.c + gcc -c $(INCFLAGS) -I../../daemons/mrpd $(CFLAGS) mrpl.c + +mrpq.o: mrpq.c + gcc -c $(INCFLAGS) -I../../daemons/mrpd $(CFLAGS) mrpq.c + +%: %.o + $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +clean: + rm -f `find . -name "*~" -o -name "*.[oa]" -o -name "\#*\#" -o -name TAGS -o -name core -o -name "*.orig"` mrpl mrpq + diff --git a/examples/mrpl.c b/examples/mrp_client/mrpl.c similarity index 100% rename from examples/mrpl.c rename to examples/mrp_client/mrpl.c diff --git a/examples/mrpq.c b/examples/mrp_client/mrpq.c similarity index 100% rename from examples/mrpq.c rename to examples/mrp_client/mrpq.c diff --git a/examples/simple_talker.c b/examples/simple_talker.c deleted file mode 100755 index 118fd0f..0000000 --- a/examples/simple_talker.c +++ /dev/null @@ -1,970 +0,0 @@ -/****************************************************************************** - - Copyright (c) 2012, Intel Corporation - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. 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. - - 3. Neither the name of the Intel Corporation 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. - -******************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "igb.h" -#include "mrpd.h" - -#define IGB_BIND_NAMESZ 24 - -/* global variables */ -int control_socket = -1; -device_t igb_dev; -volatile int halt_tx = 0; -volatile int listeners = 0; -volatile int mrp_okay; -volatile int mrp_error = 0;; -volatile int domain_a_valid = 0; -int domain_class_a_id; -int domain_class_a_priority; -int domain_class_a_vid; -volatile int domain_b_valid = 0; -int domain_class_b_id; -int domain_class_b_priority; -int domain_class_b_vid; - -#define VERSION_STR "1.0" - -static const char *version_str = -"simple_talker v" VERSION_STR "\n" -"Copyright (c) 2012, Intel Corporation\n"; - -#define MRPD_PORT_DEFAULT 7500 - -int mrp_join_listener(uint8_t *streamid); - -int -send_mrp_msg( char *notify_data, int notify_len) { - struct sockaddr_in addr; - socklen_t addr_len; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(MRPD_PORT_DEFAULT); - inet_aton("127.0.0.1", &addr.sin_addr); - addr_len = sizeof(addr); - - if (control_socket != -1) - return(sendto(control_socket, notify_data, notify_len, 0, (struct sockaddr *)&addr, addr_len)); - else - return(0); -} - -int -mrp_connect() { - struct sockaddr_in addr; - int sock_fd = -1; - - sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sock_fd < 0) - goto out; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(MRPD_PORT_DEFAULT); - inet_aton("127.0.0.1", &addr.sin_addr); - - memset(&addr, 0, sizeof(addr)); - - control_socket = sock_fd; - - return(0); -out: - if (sock_fd != -1) close(sock_fd); - sock_fd = -1; - return(-1); -} - -int -mrp_disconnect() { - char *msgbuf; - int rc; - - msgbuf = malloc(64); - if (NULL == msgbuf) - return -1; - - memset(msgbuf,0,64); - sprintf(msgbuf,"BYE"); - mrp_okay = 0; - rc = send_mrp_msg(msgbuf, 1500); - /* rc = recv_mrp_okay(); */ - free(msgbuf); - return rc; -} - - -int -recv_mrp_okay() { - while ((mrp_okay == 0) && (mrp_error == 0)) - usleep(20000); - return 0; -} - -int mrp_register_domain(int *class_id, int *priority, u_int16_t *vid) { - char *msgbuf; - int rc; - msgbuf = malloc(64); - if (NULL == msgbuf) - return -1; - - memset(msgbuf,0,64); - sprintf(msgbuf,"S+D:C:%d:P:%d:V:%04x", - *class_id, - *priority, - *vid); - - mrp_okay = 0; - rc = send_mrp_msg(msgbuf, 1500); - /* rc = recv_mrp_okay(); */ - free(msgbuf); - return rc; - -} - -int mrp_get_domain(int *class_a_id, int *a_priority, u_int16_t *a_vid, \ - int *class_b_id, int *b_priority, u_int16_t *b_vid ) { - char *msgbuf; - - /* we may not get a notification if we are joining late, - * so query for what is already there ... - */ - msgbuf = malloc(64); - if (NULL == msgbuf) - return -1; - - memset(msgbuf,0,64); - sprintf(msgbuf,"S??"); - send_mrp_msg(msgbuf, 64); - free(msgbuf); - - while (!halt_tx && (domain_a_valid == 0) && (domain_b_valid == 0)) - usleep(20000); - - *class_a_id = 0; - *a_priority = 0; - *a_vid = 0; - *class_b_id = 0; - *b_priority = 0; - *b_vid = 0; - - if (domain_a_valid) { - *class_a_id = domain_class_a_id; - *a_priority = domain_class_a_priority; - *a_vid = domain_class_a_vid; - } - if (domain_b_valid) { - *class_b_id = domain_class_b_id; - *b_priority = domain_class_b_priority; - *b_vid = domain_class_b_vid; - } - - return(0); -} - -unsigned char monitor_stream_id[] = {0,0,0,0,0,0,0,0}; - -int -mrp_await_listener(unsigned char *streamid) { - char *msgbuf; - - memcpy(monitor_stream_id, streamid, sizeof(monitor_stream_id)); - - msgbuf = malloc(64); - if (NULL == msgbuf) - return -1; - - memset(msgbuf,0,64); - sprintf(msgbuf,"S??"); - send_mrp_msg(msgbuf, 64); - free(msgbuf); - - /* either already there ... or need to wait ... */ - while (!halt_tx && (listeners == 0)) - usleep(20000); - - return(0); -} - -int -process_mrp_msg(char *buf, int buflen) { - - /* - * 1st character indicates application - * [MVS] - MAC, VLAN or STREAM - */ - unsigned int id; - unsigned int priority; - unsigned int vid; - int i,j,k; - unsigned int substate; - unsigned char recovered_streamid[8]; - k = 0; - -next_line: - if (k >= buflen) - return(0); - - switch (buf[k]) { - case 'E': - printf("%s from mrpd\n", buf); - fflush(stdout); - mrp_error = 1; - break; - case 'O': - mrp_okay = 1; - break; - case 'M': - case 'V': - printf("%s unhandled from mrpd\n", buf); - fflush(stdout); - /* unhandled for now */ - break; - case 'L': - /* parse a listener attribute - see if it matches our monitor_stream_id */ - i = k; - while (buf[i] != 'D') - i++; - i+=2; /* skip the ':' */ - sscanf(&(buf[i]),"%d",&substate); - - while (buf[i] != 'S') - i++; - i+=2; /* skip the ':' */ - - for (j = 0; j < 8; j++) { - sscanf(&(buf[i+2*j]),"%02x",&id); - recovered_streamid[j] = (unsigned char)id; - } - - printf("FOUND STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ", - recovered_streamid[0], - recovered_streamid[1], - recovered_streamid[2], - recovered_streamid[3], - recovered_streamid[4], - recovered_streamid[5], - recovered_streamid[6], - recovered_streamid[7]); - - switch (substate) { - case 0: - printf("with state ignore\n"); - break; - case 1: - printf("with state askfailed\n"); - break; - case 2: - printf("with state ready\n"); - break; - case 3: - printf("with state readyfail\n"); - break; - default: - printf("with state UNKNOWN (%d)\n", substate); - break; - } - - if (substate > MSRP_LISTENER_ASKFAILED) { - if (memcmp(recovered_streamid, monitor_stream_id, sizeof(recovered_streamid)) == 0) { - mrp_join_listener(recovered_streamid); - listeners = 1; - printf("added listener\n"); - } - } - fflush(stdout); - - /* try to find a newline ... */ - while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0')) - i++; - - if (i == buflen) - return(0); - if (buf[i] == '\0') - return(0); - - i++; - k = i; - goto next_line; - break; - case 'D': - i = k+4; - /* save the domain attribute */ - sscanf(&(buf[i]),"%d",&id); - while (buf[i] != 'P') - i++; - i+=2; /* skip the ':' */ - sscanf(&(buf[i]),"%d",&priority); - while (buf[i] != 'V') - i++; - i+=2; /* skip the ':' */ - sscanf(&(buf[i]),"%x",&vid); - if (id == 6) { - domain_class_a_id = id; - domain_class_a_priority = priority; - domain_class_a_vid = vid; - domain_a_valid = 1; - } else { - domain_class_b_id = id; - domain_class_b_priority = priority; - domain_class_b_vid = vid; - domain_b_valid = 1; - } - while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0')) - i++; - - if ((i == buflen) || (buf[i] == '\0')) - return(0); - i++; - k = i; - goto next_line; - break; - case 'T': - /* as simple_talker we don't care about other talkers */ - i = k; - while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0')) - i++; - if (i == buflen) - return(0); - if (buf[i] == '\0') - return(0); - - i++; - k = i; - goto next_line; - break; - case 'S': - /* handle the leave/join events */ - switch (buf[k+4]) { - case 'L': - i = k+5; - while (buf[i] != 'D') - i++; - i+=2; /* skip the ':' */ - sscanf(&(buf[i]),"%d",&substate); - - while (buf[i] != 'S') - i++; - i+=2; /* skip the ':' */ - - for (j = 0; j < 8; j++) { - sscanf(&(buf[i+2*j]),"%02x",&id); - recovered_streamid[j] = (unsigned char)id; - } - - printf("EVENT on STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ", - recovered_streamid[0], - recovered_streamid[1], - recovered_streamid[2], - recovered_streamid[3], - recovered_streamid[4], - recovered_streamid[5], - recovered_streamid[6], - recovered_streamid[7]); - - switch (substate) { - case 0: - printf("with state ignore\n"); - break; - case 1: - printf("with state askfailed\n"); - break; - case 2: - printf("with state ready\n"); - break; - case 3: - printf("with state readyfail\n"); - break; - default: - printf("with state UNKNOWN (%d)\n", substate); - break; - } - - - switch (buf[k+1]) { - case 'L': - printf("got a leave indication\n"); - if (memcmp(recovered_streamid, monitor_stream_id, sizeof(recovered_streamid)) == 0) { - listeners = 0; - printf("listener left\n"); - } - break; - case 'J': - case 'N': - printf("got a new/join indication\n"); - if (substate > MSRP_LISTENER_ASKFAILED) { - if (memcmp(recovered_streamid, monitor_stream_id, sizeof(recovered_streamid)) == 0) - mrp_join_listener(recovered_streamid); - listeners = 1; - } - break; - } - /* only care about listeners ... */ - default: - return(0); - break; - } - break; - case '\0': - break; - } - return(0); -} - - -void * -mrp_monitor_thread(void *arg) { - char *msgbuf; - struct sockaddr_in client_addr; - struct msghdr msg; - struct iovec iov; - int bytes = 0; - struct pollfd fds; - int rc; - - if (NULL == arg) - rc = 0; - else - rc = 1; - - msgbuf = (char *)malloc (MAX_MRPD_CMDSZ); - if (NULL == msgbuf) - return NULL; - while (!halt_tx) { - fds.fd = control_socket; - fds.events = POLLIN; - fds.revents = 0; - rc = poll(&fds, 1, 100); - if (rc < 0) { - free (msgbuf); - pthread_exit(NULL); - } - if (rc == 0) - continue; - if ((fds.revents & POLLIN) == 0) { - free (msgbuf); - pthread_exit(NULL); - } - - memset(&msg, 0, sizeof(msg)); - memset(&client_addr, 0, sizeof(client_addr)); - memset(msgbuf, 0, MAX_MRPD_CMDSZ); - - iov.iov_len = MAX_MRPD_CMDSZ; - iov.iov_base = msgbuf; - msg.msg_name = &client_addr; - msg.msg_namelen = sizeof(client_addr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - bytes = recvmsg(control_socket, &msg, 0); - if (bytes < 0) - continue; - - process_mrp_msg(msgbuf, bytes); - } - free (msgbuf); - - pthread_exit(NULL); -} - -pthread_t monitor_thread; -pthread_attr_t monitor_attr; - -int -mrp_monitor() { - pthread_attr_init(&monitor_attr); - pthread_create(&monitor_thread, NULL, mrp_monitor_thread, NULL); - - return(0); -} - -int -mrp_join_listener(uint8_t *streamid) { - char *msgbuf; - int rc; - - msgbuf = malloc(1500); - if (NULL == msgbuf) - return -1; - - memset(msgbuf,0,1500); - sprintf(msgbuf,"S+L:%02X%02X%02X%02X%02X%02X%02X%02X" - ":D:2", - streamid[0], - streamid[1], - streamid[2], - streamid[3], - streamid[4], - streamid[5], - streamid[6], - streamid[7]); - - mrp_okay = 0; - rc = send_mrp_msg(msgbuf, 1500); - /* rc = recv_mrp_okay(); */ - free(msgbuf); - return rc; -} - -int -mrp_advertise_stream( - uint8_t *streamid, - uint8_t *destaddr, - u_int16_t vlan, - int pktsz, - int interval, - int priority, - int latency) { - char *msgbuf; - int rc; - - msgbuf = malloc(1500); - if (NULL == msgbuf) - return -1; - - memset(msgbuf,0,1500); - sprintf(msgbuf,"S++S:%02X%02X%02X%02X%02X%02X%02X%02X" - ":A:%02X%02X%02X%02X%02X%02X" - ":V:%04X" - ":Z:%d" - ":I:%d" - ":P:%d" - ":L:%d", - streamid[0], - streamid[1], - streamid[2], - streamid[3], - streamid[4], - streamid[5], - streamid[6], - streamid[7], - destaddr[0], - destaddr[1], - destaddr[2], - destaddr[3], - destaddr[4], - destaddr[5], - vlan, - pktsz, - interval, - priority << 5, - latency); - - mrp_okay = 0; - rc = send_mrp_msg(msgbuf, 1500); - /* rc = recv_mrp_okay(); */ - free(msgbuf); - return rc; -} - -int -mrp_unadvertise_stream( - uint8_t *streamid, - uint8_t *destaddr, - u_int16_t vlan, - int pktsz, - int interval, - int priority, - int latency) { - char *msgbuf; - int rc; - - msgbuf = malloc(1500); - if (NULL == msgbuf) - return -1; - - memset(msgbuf,0,1500); - sprintf(msgbuf,"S--S:%02X%02X%02X%02X%02X%02X%02X%02X" - ":A:%02X%02X%02X%02X%02X%02X" - ":V:%04X" - ":Z:%d" - ":I:%d" - ":P:%d" - ":L:%d", - streamid[0], - streamid[1], - streamid[2], - streamid[3], - streamid[4], - streamid[5], - streamid[6], - streamid[7], - destaddr[0], - destaddr[1], - destaddr[2], - destaddr[3], - destaddr[4], - destaddr[5], - vlan, - pktsz, - interval, - priority << 5, - latency); - - mrp_okay = 0; - rc = send_mrp_msg(msgbuf, 1500); - /* rc = recv_mrp_okay(); */ - free(msgbuf); - return rc; -} - -void -sigint_handler (int signum) -{ - printf("got SIGINT\n"); - halt_tx = signum; -} - -int -pci_connect() -{ - struct pci_access *pacc; - struct pci_dev *dev; - int err; - char devpath[IGB_BIND_NAMESZ]; - - memset(&igb_dev, 0, sizeof(device_t)); - - pacc = pci_alloc(); - pci_init(pacc); - pci_scan_bus(pacc); - for (dev=pacc->devices; dev; dev=dev->next) - { - pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); - - igb_dev.pci_vendor_id = dev->vendor_id; - igb_dev.pci_device_id = dev->device_id; - igb_dev.domain = dev->domain; - igb_dev.bus = dev->bus; - igb_dev.dev = dev->dev; - igb_dev.func = dev->func; - - snprintf(devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d", \ - dev->domain, dev->bus, dev->dev, dev->func ); - - err = igb_probe(&igb_dev); - - if (err) { - continue; - } - - printf ("attaching to %s\n", devpath); - err = igb_attach(devpath, &igb_dev); - - if (err) { - printf ("attach failed! (%s)\n", strerror(errno)); - continue; - } - goto out; - } - - pci_cleanup(pacc); - return ENXIO; - -out: - pci_cleanup(pacc); - return 0; - -} - -unsigned char STATION_ADDR[] = {0,0,0,0,0,0}; -unsigned char STREAM_ID[] = {0,0,0,0,0,0,0,0}; -unsigned char DEST_ADDR[] = {0x91, 0xE0, 0xF0, 0x00, 0x00, 0x00}; /* IEEE 1722 reserved address */ - -int -get_mac_address(char *interface) { - struct ifreq if_request; - int lsock; - int rc; - - lsock = socket(PF_PACKET, SOCK_RAW, htons(0x800)); - if (lsock < 0) - return -1; - - memset(&if_request, 0, sizeof(if_request)); - - strncpy(if_request.ifr_name, interface, sizeof(if_request.ifr_name)); - - rc = ioctl(lsock, SIOCGIFHWADDR, &if_request); - if (rc < 0) { - close(lsock); - return -1; - } - - memcpy(STATION_ADDR, if_request.ifr_hwaddr.sa_data, sizeof(STATION_ADDR)); - close(lsock); - return 0; -} - -static void -usage( void ) { - fprintf(stderr, - "\n" - "usage: simple_talker [-h] -i interface-name" - "\n" - "options:\n" - " -h show this message\n" - " -i specify interface for AVB connection\n" - "\n" - "%s" - "\n", version_str); - exit(1); -} - -#define PACKET_IPG (125000) /* (1) packet every 125 msec */ - -int -main(int argc, char *argv[]) { - unsigned i; - int err; - struct igb_dma_alloc a_page; - struct igb_packet a_packet; - struct igb_packet *tmp_packet; - struct igb_packet *cleaned_packets; - struct igb_packet *free_packets; - int c; - u_int64_t last_time; - u_int64_t rdtsc0; - int rc = 0; - char *interface = NULL; - int class_a_id = 0; - int a_priority = 0; - u_int16_t a_vid = 0; - int class_b_id = 0; - int b_priority = 0; - u_int16_t b_vid = 0; - - for (;;) { - c = getopt(argc, argv, "hi:"); - - if (c < 0) - break; - - switch (c) { - case 'h': - usage(); - break; - case 'i': - if (interface) { - printf("only one interface per daemon is supported\n"); - usage(); - } - interface = strdup(optarg); - break; - } - } - if (optind < argc) - usage(); - - if (NULL == interface) { - usage(); - } - - rc = mrp_connect(); - if (rc) { - printf("socket creation failed\n"); - return(errno); - } - - err = pci_connect(); - - if (err) { - printf("connect failed (%s) - are you running as root?\n", strerror(errno)); - return(errno); - } - - err = igb_init(&igb_dev); - - if (err) { - printf("init failed (%s) - is the driver really loaded?\n", strerror(errno)); - return(errno); - } - - err = igb_dma_malloc_page(&igb_dev, &a_page); - - if (err) { - printf("malloc failed (%s) - out of memory?\n", strerror(errno)); - return(errno); - } - - signal(SIGINT, sigint_handler); - - rc = get_mac_address(interface); - if (rc) { - printf("failed to open interface\n"); - usage(); - } - - mrp_monitor(); - mrp_get_domain(&class_a_id, &a_priority, &a_vid, &class_b_id, &b_priority, &b_vid); - - printf("detected domain Class A PRIO=%d VID=%04x...\n", a_priority, a_vid); - - mrp_register_domain(&class_a_id, &a_priority, &a_vid); - igb_set_class_bandwidth(&igb_dev, 0, 0, 0); /* xxx Qav */ - - memset(STREAM_ID, 0, sizeof(STREAM_ID)); - - memcpy(STREAM_ID, STATION_ADDR, sizeof(STATION_ADDR)); - -#define PKT_SZ 200 - a_packet.dmatime = a_packet.attime = a_packet.flags = 0; - a_packet.map.paddr = a_page.dma_paddr; - a_packet.map.mmap_size = a_page.mmap_size; - - a_packet.offset = 0; - a_packet.vaddr = a_page.dma_vaddr + a_packet.offset; - a_packet.len = PKT_SZ; - - free_packets = NULL; - - /* divide the dma page into buffers for packets */ - for (i = 1; i < ((a_page.mmap_size) / PKT_SZ); i++) { - tmp_packet = malloc(sizeof(struct igb_packet)); - if (NULL == tmp_packet) { printf("failed to allocate igb_packet memory!\n"); return(errno); } - - *tmp_packet = a_packet; - tmp_packet->offset = (i * PKT_SZ); - tmp_packet->vaddr += tmp_packet->offset; - tmp_packet->next = free_packets; - memset(tmp_packet->vaddr, 0, PKT_SZ); /* MAC header at least */ - memcpy(tmp_packet->vaddr, DEST_ADDR, sizeof(DEST_ADDR)); - memcpy(tmp_packet->vaddr+6, STATION_ADDR, sizeof(STATION_ADDR)); - /* Q-tag */ - ((char *)tmp_packet->vaddr)[12] = 0x81; - ((char *)tmp_packet->vaddr)[13] = 0x00; - ((char *)tmp_packet->vaddr)[14] = ((a_priority << 13 | a_vid) ) >> 8; - ((char *)tmp_packet->vaddr)[15] = ((a_priority << 13 | a_vid) ) & 0xFF; - ((char *)tmp_packet->vaddr)[16] = 0x88; /* experimental etype */ - ((char *)tmp_packet->vaddr)[17] = 0xB5; - free_packets = tmp_packet; - } - - - /* - * subtract 16 bytes for the MAC header/Q-tag - pktsz is limited to the - * data payload of the ethernet frame . - * - * IPG is scaled to the Class (A) observation interval of packets per 125 usec - */ - printf("advertising stream ...\n"); - mrp_advertise_stream( STREAM_ID, DEST_ADDR, a_vid, PKT_SZ - 16, PACKET_IPG / 125000, a_priority, 3900); - - printf("awaiting a listener ...\n"); - - mrp_await_listener(STREAM_ID); - - printf("got a listener ...\n"); - - halt_tx = 0; - - rc = nice(-20); - - igb_get_wallclock(&igb_dev, &last_time, &rdtsc0); - - while (listeners && !halt_tx) { - tmp_packet = free_packets; - - if (NULL == tmp_packet) - goto cleanup; - - free_packets = tmp_packet->next; - - /* unfortuntely unless this thread is at rtprio - * you get pre-empted between fetching the time - * and programming the packet and get a late packet - */ - tmp_packet->attime = last_time + PACKET_IPG; - *(u_int64_t *)(tmp_packet->vaddr + 32) = tmp_packet->attime; - err = igb_xmit(&igb_dev, 0, tmp_packet); - - if (!err) { - continue; - } - - if (ENOSPC == err) { - /* put back for now */ - tmp_packet->next = free_packets; - free_packets = tmp_packet; - } -cleanup: - igb_clean(&igb_dev, &cleaned_packets); - i = 0; - while (cleaned_packets) { - i++; - tmp_packet = cleaned_packets; - cleaned_packets = cleaned_packets->next; - tmp_packet->next = free_packets; - free_packets = tmp_packet; - } - } - - rc = nice(0); - - if (halt_tx == 0) - printf("listener left ...\n"); - - halt_tx = 1; - mrp_unadvertise_stream( STREAM_ID, DEST_ADDR, a_vid, PKT_SZ - 16, PACKET_IPG / 125000, a_priority, 3900); - - igb_set_class_bandwidth(&igb_dev, 0, 0, 0); /* disable Qav */ - - rc = mrp_disconnect(); - igb_dma_free_page(&igb_dev, &a_page); - err = igb_detach(&igb_dev); - pthread_exit(NULL); - return(0); -} - diff --git a/examples/simple_talker/Makefile b/examples/simple_talker/Makefile new file mode 100644 index 0000000..6e3984c --- /dev/null +++ b/examples/simple_talker/Makefile @@ -0,0 +1,21 @@ +OPT=-O2 +CFLAGS=$(OPT) -Wall -W -Wno-parentheses + +CC=gcc +INCFLAGS=-I../../lib/igb +LDLIBS=-ligb -lpci -lz -lrt -lm -pthread +LDFLAGS=-L../../lib/igb + +all: simple_talker + +simple_talker: simple_talker.o + +simple_talker.o: simple_talker.c + gcc -c $(INCFLAGS) -I../../daemons/mrpd $(CFLAGS) simple_talker.c + +%: %.o + $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +clean: + rm -f `find . -name "*~" -o -name "*.[oa]" -o -name "\#*\#" -o -name TAGS -o -name core -o -name "*.orig"` simple_talker + diff --git a/examples/simple_talker/README b/examples/simple_talker/README new file mode 100644 index 0000000..79e0db1 --- /dev/null +++ b/examples/simple_talker/README @@ -0,0 +1,22 @@ +EXAMPLE APPLICATIONS + +The 'simple_talker' application illustrates the various steps to publish a stream +and streaming 1722/61883 audio frames after a listener connects. The audio +itself is a simple sine wave. It has been tested with other vendors listeners +at AVNu plug-fests. + +The simple talker application requires root permissions to execute and +attach to the driver. + sudo ./simple_talker + +To exit the app, hit Ctrl-C. The application gracefully tears down +the connection to the driver. If the application unexpectedly aborts the +kernel-mode driver also reclaims the various buffers and attempts to clean up. +The application should be able to re-initialize and use the transmit queues +without restarting the driver. + +Note this application requires using the provided gptp timesync daemon to +provide the 802.1AS presentation times included in the 1722 frames. This +application also requires the mrpd daemon to be running to detect and +establish various stream reservation parameters. + diff --git a/examples/simple_talker/simple_talker.c b/examples/simple_talker/simple_talker.c new file mode 100755 index 0000000..f7178c4 --- /dev/null +++ b/examples/simple_talker/simple_talker.c @@ -0,0 +1,1155 @@ +/****************************************************************************** + + Copyright (c) 2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the Intel Corporation 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. + +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "igb.h" +#include "mrpd.h" +#include +#include +#include + +typedef struct { + int64_t ml_phoffset; + int64_t ls_phoffset; + int32_t ml_freqoffset; + int32_t ls_freqoffset; + int64_t local_time; +} gPtpTimeData; + + +#define SHM_SIZE 4*8 + sizeof(pthread_mutex_t) /* 3 - 64 bit and 2 - 32 bits */ +#define SHM_NAME "/ptp" + +#define MAX_SAMPLE_VALUE ((1U << ((sizeof(int32_t)*8)-1))-1) + +#define SRC_CHANNELS (2) +#define SAMPLES_PER_SECOND (48000) +#define FREQUENCY (480) +#define SAMPLES_PER_CYCLE (SAMPLES_PER_SECOND/FREQUENCY) +#define GAIN (.5) + +#define SYSTEM_FREQ_FILENAME "/sys/module/igb_avb/parameters/TEN_USEC_COUNT" + +//1722 header +#define ETH_TYPE 0x22F0 + +#define CD_SUBTYPE 0x02 /* for simple audio format */ +#define SV_VER_MR_RS_GV_TV 0x81 +#define RS_TU 0x00 +#define SAMPLE_FORMAT_NON_INTR_FLOAT 0x02 +#define NOMINAL_SAMPLE_RATE 0x09 +#define LINEAR_SAMPLE_MSB 0x20 +unsigned char GATEWAY_INFO[] = + { SAMPLE_FORMAT_NON_INTR_FLOAT, 0, NOMINAL_SAMPLE_RATE, LINEAR_SAMPLE_MSB }; + +#define SAMPLE_SIZE 4 /* 4 bytes */ +#define SAMPLES_PER_FRAME 6 +#define CHANNELS 2 +#define PAYLOAD_SIZE SAMPLE_SIZE*SAMPLES_PER_FRAME*CHANNELS /* 6*4 * 2 channels = 48 bytes */ + +#define IGB_BIND_NAMESZ 24 + +#define XMIT_DELAY (200000000) /* us */ +#define RENDER_DELAY (XMIT_DELAY+2000000) /* us */ +typedef enum { false = 0, true = 1 } bool; +typedef struct __attribute__ ((packed)) { + uint64_t subtype:7; + uint64_t cd_indicator:1; + uint64_t timestamp_valid:1; + uint64_t gateway_valid:1; + uint64_t reserved0:1; + uint64_t reset:1; + uint64_t version:3; + uint64_t sid_valid:1; + uint64_t seq_number:8; + uint64_t timestamp_uncertain:1; + uint64_t reserved1:7; + uint64_t stream_id; + uint64_t timestamp:32; + uint64_t gateway_info:32; + uint64_t length:16; +} seventeen22_header; + +/* 61883 CIP with SYT Field */ +typedef struct { + uint16_t packet_channel:6; + uint16_t format_tag:2; + uint16_t app_control:4; + uint16_t packet_tcode:4; + uint16_t source_id:6; + uint16_t reserved0:2; + uint16_t data_block_size:8; + uint16_t reserved1:2; + uint16_t source_packet_header:1; + uint16_t quadlet_padding_count:3; + uint16_t fraction_number:2; + uint16_t data_block_continuity:8; + uint16_t format_id:6; + uint16_t eoh:2; + uint16_t format_dependent_field:8; + uint16_t syt; +} six1883_header; + +typedef struct { + uint8_t label; + uint8_t value[3]; +} six1883_sample; + +/* global variables */ +int control_socket = -1; +device_t igb_dev; +volatile int halt_tx = 0; +volatile int listeners = 0; +volatile int mrp_okay; +volatile int mrp_error = 0;; +volatile int domain_a_valid = 0; +int domain_class_a_id; +int domain_class_a_priority; +int domain_class_a_vid; +volatile int domain_b_valid = 0; +int domain_class_b_id; +int domain_class_b_priority; +int domain_class_b_vid; + +#define VERSION_STR "1.0" +static const char *version_str = "simple_talker v" VERSION_STR "\n" + "Copyright (c) 2012, Intel Corporation\n"; + +#define MRPD_PORT_DEFAULT 7500 +static inline uint64_t ST_rdtsc(void) +{ + uint64_t ret; + unsigned c, d; + asm volatile ("rdtsc":"=a" (c), "=d"(d)); + ret = d; + ret <<= 32; + ret |= c; + return ret; +} + +static int shm_fd = -1; +static char *memory_offset_buffer = NULL; +int gptpinit(void) +{ + shm_fd = shm_open(SHM_NAME, O_RDWR, 0); + if (shm_fd == -1) { + perror("shm_open()"); + return false; + } + memory_offset_buffer = + (char *)mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, + shm_fd, 0); + if (memory_offset_buffer == (char *)-1) { + perror("mmap()"); + memory_offset_buffer = NULL; + shm_unlink(SHM_NAME); + return false; + } + return true; +} + +void gptpdeinit(void) +{ + if (memory_offset_buffer != NULL) { + munmap(memory_offset_buffer, SHM_SIZE); + } + if (shm_fd != -1) { + close(shm_fd); + } +} + +int gptpscaling(gPtpTimeData * td) +{ + pthread_mutex_lock((pthread_mutex_t *) memory_offset_buffer); + memcpy(td, memory_offset_buffer + sizeof(pthread_mutex_t), sizeof(*td)); + pthread_mutex_unlock((pthread_mutex_t *) memory_offset_buffer); + + fprintf(stderr, "ml_phoffset = %lld, ls_phoffset = %lld\n", + td->ml_phoffset, td->ls_phoffset); + fprintf(stderr, "ml_freqffset = %d, ls_freqoffset = %d\n", + td->ml_freqoffset, td->ls_freqoffset); + + return true; +} + +void gensine32(int32_t * buf, unsigned count) +{ + long double interval = (2 * ((long double)M_PI)) / count; + unsigned i; + for (i = 0; i < count; ++i) { + buf[i] = + (int32_t) (MAX_SAMPLE_VALUE * sinl(i * interval) * GAIN); + } +} + +int get_samples(unsigned count, int32_t * buffer) +{ + static int init = 0; + static int32_t samples_onechannel[100]; + static unsigned index = 0; + + if (init == 0) { + gensine32(samples_onechannel, 100); + init = 1; + } + + while (count > 0) { + int i; + for (i = 0; i < SRC_CHANNELS; ++i) { + *(buffer++) = samples_onechannel[index]; + } + index = (index + 1) % 100; + --count; + } + + return 0; +} + +int mrp_join_listener(uint8_t * streamid); +int send_mrp_msg(char *notify_data, int notify_len) +{ + struct sockaddr_in addr; + socklen_t addr_len; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(MRPD_PORT_DEFAULT); + inet_aton("127.0.0.1", &addr.sin_addr); + addr_len = sizeof(addr); + if (control_socket != -1) + return (sendto + (control_socket, notify_data, notify_len, 0, + (struct sockaddr *)&addr, addr_len)); + + else + return (0); +} + +int mrp_connect() +{ + struct sockaddr_in addr; + int sock_fd = -1; + sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock_fd < 0) + goto out; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(MRPD_PORT_DEFAULT); + inet_aton("127.0.0.1", &addr.sin_addr); + memset(&addr, 0, sizeof(addr)); + control_socket = sock_fd; + return (0); + out: if (sock_fd != -1) + close(sock_fd); + sock_fd = -1; + return (-1); +} + +int mrp_disconnect() +{ + char *msgbuf; + int rc; + msgbuf = malloc(64); + if (NULL == msgbuf) + return -1; + memset(msgbuf, 0, 64); + sprintf(msgbuf, "BYE"); + mrp_okay = 0; + rc = send_mrp_msg(msgbuf, 1500); + + /* rc = recv_mrp_okay(); */ + free(msgbuf); + return rc; +} + +int recv_mrp_okay() +{ + while ((mrp_okay == 0) && (mrp_error == 0)) + usleep(20000); + return 0; +} + +int mrp_register_domain(int *class_id, int *priority, u_int16_t * vid) +{ + char *msgbuf; + int rc; + msgbuf = malloc(64); + if (NULL == msgbuf) + return -1; + memset(msgbuf, 0, 64); + sprintf(msgbuf, "S+D:C:%d:P:%d:V:%04x", *class_id, *priority, *vid); + mrp_okay = 0; + rc = send_mrp_msg(msgbuf, 1500); + + /* rc = recv_mrp_okay(); */ + free(msgbuf); + return rc; +} + +int mrp_get_domain(int *class_a_id, int *a_priority, u_int16_t * a_vid, + int *class_b_id, int *b_priority, u_int16_t * b_vid) +{ + char *msgbuf; + + /* we may not get a notification if we are joining late, + * so query for what is already there ... + */ + msgbuf = malloc(64); + if (NULL == msgbuf) + return -1; + memset(msgbuf, 0, 64); + sprintf(msgbuf, "S??"); + send_mrp_msg(msgbuf, 64); + free(msgbuf); + while (!halt_tx && (domain_a_valid == 0) && (domain_b_valid == 0)) + usleep(20000); + *class_a_id = 0; + *a_priority = 0; + *a_vid = 0; + *class_b_id = 0; + *b_priority = 0; + *b_vid = 0; + if (domain_a_valid) { + *class_a_id = domain_class_a_id; + *a_priority = domain_class_a_priority; + *a_vid = domain_class_a_vid; + } + if (domain_b_valid) { + *class_b_id = domain_class_b_id; + *b_priority = domain_class_b_priority; + *b_vid = domain_class_b_vid; + } + return (0); +} +unsigned char monitor_stream_id[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +int mrp_await_listener(unsigned char *streamid) +{ + char *msgbuf; + memcpy(monitor_stream_id, streamid, sizeof(monitor_stream_id)); + msgbuf = malloc(64); + if (NULL == msgbuf) + return -1; + memset(msgbuf, 0, 64); + sprintf(msgbuf, "S??"); + send_mrp_msg(msgbuf, 64); + free(msgbuf); + + /* either already there ... or need to wait ... */ + while (!halt_tx && (listeners == 0)) + usleep(20000); + return (0); +} + +int process_mrp_msg(char *buf, int buflen) +{ + + /* + * 1st character indicates application + * [MVS] - MAC, VLAN or STREAM + */ + unsigned int id; + unsigned int priority; + unsigned int vid; + int i, j, k; + unsigned int substate; + unsigned char recovered_streamid[8]; + k = 0; + next_line:if (k >= buflen) + return (0); + switch (buf[k]) { + case 'E': + printf("%s from mrpd\n", buf); + fflush(stdout); + mrp_error = 1; + break; + case 'O': + mrp_okay = 1; + break; + case 'M': + case 'V': + printf("%s unhandled from mrpd\n", buf); + fflush(stdout); + + /* unhandled for now */ + break; + case 'L': + + /* parse a listener attribute - see if it matches our monitor_stream_id */ + i = k; + while (buf[i] != 'D') + i++; + i += 2; /* skip the ':' */ + sscanf(&(buf[i]), "%d", &substate); + while (buf[i] != 'S') + i++; + i += 2; /* skip the ':' */ + for (j = 0; j < 8; j++) { + sscanf(&(buf[i + 2 * j]), "%02x", &id); + recovered_streamid[j] = (unsigned char)id; + } printf + ("FOUND STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ", + recovered_streamid[0], recovered_streamid[1], + recovered_streamid[2], recovered_streamid[3], + recovered_streamid[4], recovered_streamid[5], + recovered_streamid[6], recovered_streamid[7]); + switch (substate) { + case 0: + printf("with state ignore\n"); + break; + case 1: + printf("with state askfailed\n"); + break; + case 2: + printf("with state ready\n"); + break; + case 3: + printf("with state readyfail\n"); + break; + default: + printf("with state UNKNOWN (%d)\n", substate); + break; + } + if (substate > MSRP_LISTENER_ASKFAILED) { + if (memcmp + (recovered_streamid, monitor_stream_id, + sizeof(recovered_streamid)) == 0) { + mrp_join_listener(recovered_streamid); + listeners = 1; + printf("added listener\n"); + } + } + fflush(stdout); + + /* try to find a newline ... */ + while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0')) + i++; + if (i == buflen) + return (0); + if (buf[i] == '\0') + return (0); + i++; + k = i; + goto next_line; + break; + case 'D': + i = k + 4; + + /* save the domain attribute */ + sscanf(&(buf[i]), "%d", &id); + while (buf[i] != 'P') + i++; + i += 2; /* skip the ':' */ + sscanf(&(buf[i]), "%d", &priority); + while (buf[i] != 'V') + i++; + i += 2; /* skip the ':' */ + sscanf(&(buf[i]), "%x", &vid); + if (id == 6) { + domain_class_a_id = id; + domain_class_a_priority = priority; + domain_class_a_vid = vid; + domain_a_valid = 1; + } else { + domain_class_b_id = id; + domain_class_b_priority = priority; + domain_class_b_vid = vid; + domain_b_valid = 1; + } + while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0')) + i++; + if ((i == buflen) || (buf[i] == '\0')) + return (0); + i++; + k = i; + goto next_line; + break; + case 'T': + + /* as simple_talker we don't care about other talkers */ + i = k; + while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0')) + i++; + if (i == buflen) + return (0); + if (buf[i] == '\0') + return (0); + i++; + k = i; + goto next_line; + break; + case 'S': + + /* handle the leave/join events */ + switch (buf[k + 4]) { + case 'L': + i = k + 5; + while (buf[i] != 'D') + i++; + i += 2; /* skip the ':' */ + sscanf(&(buf[i]), "%d", &substate); + while (buf[i] != 'S') + i++; + i += 2; /* skip the ':' */ + for (j = 0; j < 8; j++) { + sscanf(&(buf[i + 2 * j]), "%02x", &id); + recovered_streamid[j] = (unsigned char)id; + } printf + ("EVENT on STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ", + recovered_streamid[0], recovered_streamid[1], + recovered_streamid[2], recovered_streamid[3], + recovered_streamid[4], recovered_streamid[5], + recovered_streamid[6], recovered_streamid[7]); + switch (substate) { + case 0: + printf("with state ignore\n"); + break; + case 1: + printf("with state askfailed\n"); + break; + case 2: + printf("with state ready\n"); + break; + case 3: + printf("with state readyfail\n"); + break; + default: + printf("with state UNKNOWN (%d)\n", substate); + break; + } + switch (buf[k + 1]) { + case 'L': + printf("got a leave indication\n"); + if (memcmp + (recovered_streamid, monitor_stream_id, + sizeof(recovered_streamid)) == 0) { + listeners = 0; + printf("listener left\n"); + } + break; + case 'J': + case 'N': + printf("got a new/join indication\n"); + if (substate > MSRP_LISTENER_ASKFAILED) { + if (memcmp + (recovered_streamid, + monitor_stream_id, + sizeof(recovered_streamid)) == 0) + mrp_join_listener + (recovered_streamid); + listeners = 1; + } + break; + } + + /* only care about listeners ... */ + default: + return (0); + break; + } + break; + case '\0': + break; + } + return (0); +} + +void *mrp_monitor_thread(void *arg) +{ + char *msgbuf; + struct sockaddr_in client_addr; + struct msghdr msg; + struct iovec iov; + int bytes = 0; + struct pollfd fds; + int rc; + if (NULL == arg) + rc = 0; + + else + rc = 1; + msgbuf = (char *)malloc(MAX_MRPD_CMDSZ); + if (NULL == msgbuf) + return NULL; + while (!halt_tx) { + fds.fd = control_socket; + fds.events = POLLIN; + fds.revents = 0; + rc = poll(&fds, 1, 100); + if (rc < 0) { + free(msgbuf); + pthread_exit(NULL); + } + if (rc == 0) + continue; + if ((fds.revents & POLLIN) == 0) { + free(msgbuf); + pthread_exit(NULL); + } + memset(&msg, 0, sizeof(msg)); + memset(&client_addr, 0, sizeof(client_addr)); + memset(msgbuf, 0, MAX_MRPD_CMDSZ); + iov.iov_len = MAX_MRPD_CMDSZ; + iov.iov_base = msgbuf; + msg.msg_name = &client_addr; + msg.msg_namelen = sizeof(client_addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + bytes = recvmsg(control_socket, &msg, 0); + if (bytes < 0) + continue; + process_mrp_msg(msgbuf, bytes); + } + free(msgbuf); + pthread_exit(NULL); +} + +pthread_t monitor_thread; +pthread_attr_t monitor_attr; +int mrp_monitor() +{ + pthread_attr_init(&monitor_attr); + pthread_create(&monitor_thread, NULL, mrp_monitor_thread, NULL); + return (0); +} + +int mrp_join_listener(uint8_t * streamid) +{ + char *msgbuf; + int rc; + msgbuf = malloc(1500); + if (NULL == msgbuf) + return -1; + memset(msgbuf, 0, 1500); + sprintf(msgbuf, "S+L:%02X%02X%02X%02X%02X%02X%02X%02X" + ":D:2", streamid[0], streamid[1], streamid[2], streamid[3], + streamid[4], streamid[5], streamid[6], streamid[7]); + mrp_okay = 0; + rc = send_mrp_msg(msgbuf, 1500); + + /* rc = recv_mrp_okay(); */ + free(msgbuf); + return rc; +} + +int +mrp_advertise_stream(uint8_t * streamid, + uint8_t * destaddr, + u_int16_t vlan, + int pktsz, int interval, int priority, int latency) +{ + char *msgbuf; + int rc; + msgbuf = malloc(1500); + if (NULL == msgbuf) + return -1; + memset(msgbuf, 0, 1500); + sprintf(msgbuf, "S++S:%02X%02X%02X%02X%02X%02X%02X%02X" + ":A:%02X%02X%02X%02X%02X%02X" + ":V:%04X" + ":Z:%d" + ":I:%d" + ":P:%d" + ":L:%d", streamid[0], streamid[1], streamid[2], + streamid[3], streamid[4], streamid[5], streamid[6], + streamid[7], destaddr[0], destaddr[1], destaddr[2], + destaddr[3], destaddr[4], destaddr[5], vlan, pktsz, + interval, priority << 5, latency); + mrp_okay = 0; + rc = send_mrp_msg(msgbuf, 1500); + + /* rc = recv_mrp_okay(); */ + free(msgbuf); + return rc; +} + +int +mrp_unadvertise_stream(uint8_t * streamid, + uint8_t * destaddr, + u_int16_t vlan, + int pktsz, int interval, int priority, int latency) +{ + char *msgbuf; + int rc; + msgbuf = malloc(1500); + if (NULL == msgbuf) + return -1; + memset(msgbuf, 0, 1500); + sprintf(msgbuf, "S--S:%02X%02X%02X%02X%02X%02X%02X%02X" + ":A:%02X%02X%02X%02X%02X%02X" + ":V:%04X" + ":Z:%d" + ":I:%d" + ":P:%d" + ":L:%d", streamid[0], streamid[1], streamid[2], + streamid[3], streamid[4], streamid[5], streamid[6], + streamid[7], destaddr[0], destaddr[1], destaddr[2], + destaddr[3], destaddr[4], destaddr[5], vlan, pktsz, + interval, priority << 5, latency); + mrp_okay = 0; + rc = send_mrp_msg(msgbuf, 1500); + + /* rc = recv_mrp_okay(); */ + free(msgbuf); + return rc; +} + +void sigint_handler(int signum) +{ + printf("got SIGINT\n"); + halt_tx = signum; +} + +int pci_connect() +{ + struct pci_access *pacc; + struct pci_dev *dev; + int err; + char devpath[IGB_BIND_NAMESZ]; + memset(&igb_dev, 0, sizeof(device_t)); + pacc = pci_alloc(); + pci_init(pacc); + pci_scan_bus(pacc); + for (dev = pacc->devices; dev; dev = dev->next) { + pci_fill_info(dev, + PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); + igb_dev.pci_vendor_id = dev->vendor_id; + igb_dev.pci_device_id = dev->device_id; + igb_dev.domain = dev->domain; + igb_dev.bus = dev->bus; + igb_dev.dev = dev->dev; + igb_dev.func = dev->func; + snprintf(devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d", + dev->domain, dev->bus, dev->dev, dev->func); + err = igb_probe(&igb_dev); + if (err) { + continue; + } + printf("attaching to %s\n", devpath); + err = igb_attach(devpath, &igb_dev); + if (err) { + printf("attach failed! (%s)\n", strerror(errno)); + continue; + } + goto out; + } + pci_cleanup(pacc); + return ENXIO; + out: pci_cleanup(pacc); + return 0; +} + +unsigned char STATION_ADDR[] = { 0, 0, 0, 0, 0, 0 }; +unsigned char STREAM_ID[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* IEEE 1722 reserved address */ +unsigned char DEST_ADDR[] = { 0x91, 0xE0, 0xF0, 0x00, 0x0e, 0x80 }; + +int get_mac_address(char *interface) +{ + struct ifreq if_request; + int lsock; + int rc; + lsock = socket(PF_PACKET, SOCK_RAW, htons(0x800)); + if (lsock < 0) + return -1; + memset(&if_request, 0, sizeof(if_request)); + strncpy(if_request.ifr_name, interface, sizeof(if_request.ifr_name)); + rc = ioctl(lsock, SIOCGIFHWADDR, &if_request); + if (rc < 0) { + close(lsock); + return -1; + } + memcpy(STATION_ADDR, if_request.ifr_hwaddr.sa_data, + sizeof(STATION_ADDR)); + close(lsock); + return 0; +} + +static void usage(void) +{ + fprintf(stderr, "\n" + "usage: simple_talker [-h] -i interface-name" + "\n" + "options:\n" + " -h show this message\n" + " -i specify interface for AVB connection\n" + "\n" "%s" "\n", version_str); + exit(1); +} + +#define PACKET_IPG (125000) /* (1) packet every 125 usec */ + +int main(int argc, char *argv[]) +{ + unsigned i; + int err; + struct igb_dma_alloc a_page; + struct igb_packet a_packet; + struct igb_packet *tmp_packet; + struct igb_packet *cleaned_packets; + struct igb_packet *free_packets; + int c; + u_int64_t last_time; + int rc = 0; + char *interface = NULL; + int class_a_id = 0; + int a_priority = 0; + u_int16_t a_vid = 0; + int class_b_id = 0; + int b_priority = 0; + u_int16_t b_vid = 0; + int seqnum; + int time_stamp; + int16_t data_length; + unsigned total_samples = 0; + int TEN_USEC_COUNT; + gPtpTimeData td; + int32_t sample_buffer[SAMPLES_PER_FRAME * SRC_CHANNELS]; + seventeen22_header *header0; + six1883_header *header1; + six1883_sample *sample; + FILE *freqfile; + char freqstring[8]; + uint64_t now_tscns, now_8021as; + uint64_t update_tscns, update_8021as; + unsigned delta_tscns, delta_8021as, delta_local; + long double ml_ratio, ls_ratio; + + for (;;) { + c = getopt(argc, argv, "hi:"); + if (c < 0) + break; + switch (c) { + case 'h': + usage(); + break; + case 'i': + if (interface) { + printf + ("only one interface per daemon is supported\n"); + usage(); + } + interface = strdup(optarg); + break; + } + } + if (optind < argc) + usage(); + if (NULL == interface) { + usage(); + } + rc = mrp_connect(); + if (rc) { + printf("socket creation failed\n"); + return (errno); + } + err = pci_connect(); + if (err) { + printf("connect failed (%s) - are you running as root?\n", + strerror(errno)); + return (errno); + } + err = igb_init(&igb_dev); + if (err) { + printf("init failed (%s) - is the driver really loaded?\n", + strerror(errno)); + return (errno); + } + err = igb_dma_malloc_page(&igb_dev, &a_page); + if (err) { + printf("malloc failed (%s) - out of memory?\n", + strerror(errno)); + return (errno); + } + signal(SIGINT, sigint_handler); + rc = get_mac_address(interface); + if (rc) { + printf("failed to open interface\n"); + usage(); + } + + freqfile = fopen(SYSTEM_FREQ_FILENAME, "r"); + if (freqfile == NULL) { + printf("Failed to open kernel module parameter: %s\n", + strerror(errno)); + return errno; + } + + if (fscanf(freqfile, "%7s", freqstring) != 1) { + printf("Failed to read kernel module parameter: %s\n", + strerror(errno)); + return errno; + } + + TEN_USEC_COUNT = atoi(freqstring); + /* fprintf(stderr, "TEN_USEC_COUNT = %d\n", TEN_USEC_COUNT); */ + + mrp_monitor(); + + /* + * should use mrp_get_domain() above but this is a simplification + */ + domain_a_valid = 1; + class_a_id = MSRP_SR_CLASS_A; + a_priority = MSRP_SR_CLASS_A_PRIO; + a_vid = 2; + printf("detected domain Class A PRIO=%d VID=%04x...\n", a_priority, + a_vid); + +#define PKT_SZ 100 + + mrp_register_domain(&class_a_id, &a_priority, &a_vid); + igb_set_class_bandwidth(&igb_dev, PACKET_IPG / 125000, 0, PKT_SZ - 22, + 0); + + memset(STREAM_ID, 0, sizeof(STREAM_ID)); + memcpy(STREAM_ID, STATION_ADDR, sizeof(STATION_ADDR)); + + a_packet.dmatime = a_packet.attime = a_packet.flags = 0; + a_packet.map.paddr = a_page.dma_paddr; + a_packet.map.mmap_size = a_page.mmap_size; + a_packet.offset = 0; + a_packet.vaddr = a_page.dma_vaddr + a_packet.offset; + a_packet.len = PKT_SZ; + free_packets = NULL; + seqnum = 0; + + /* divide the dma page into buffers for packets */ + for (i = 1; i < ((a_page.mmap_size) / PKT_SZ); i++) { + tmp_packet = malloc(sizeof(struct igb_packet)); + if (NULL == tmp_packet) { + printf("failed to allocate igb_packet memory!\n"); + return (errno); + } + *tmp_packet = a_packet; + tmp_packet->offset = (i * PKT_SZ); + tmp_packet->vaddr += tmp_packet->offset; + tmp_packet->next = free_packets; + memset(tmp_packet->vaddr, 0, PKT_SZ); /* MAC header at least */ + memcpy(tmp_packet->vaddr, DEST_ADDR, sizeof(DEST_ADDR)); + memcpy(tmp_packet->vaddr + 6, STATION_ADDR, + sizeof(STATION_ADDR)); + + /* Q-tag */ + ((char *)tmp_packet->vaddr)[12] = 0x81; + ((char *)tmp_packet->vaddr)[13] = 0x00; + ((char *)tmp_packet->vaddr)[14] = + ((a_priority << 13 | a_vid)) >> 8; + ((char *)tmp_packet->vaddr)[15] = + ((a_priority << 13 | a_vid)) & 0xFF; + ((char *)tmp_packet->vaddr)[16] = 0x22; /* 1722 eth type */ + ((char *)tmp_packet->vaddr)[17] = 0xF0; + + /* 1722 header update + payload */ + header0 = + (seventeen22_header *) (((char *)tmp_packet->vaddr) + 18); + header0->cd_indicator = 0; + header0->subtype = 0; + header0->sid_valid = 1; + header0->version = 0; + header0->reset = 0; + header0->reserved0 = 0; + header0->gateway_valid = 0; + header0->reserved1 = 0; + header0->timestamp_uncertain = 0; + memset(&(header0->stream_id), 0, sizeof(header0->stream_id)); + memcpy(&(header0->stream_id), STATION_ADDR, + sizeof(STATION_ADDR)); + header0->length = htons(32); + header1 = (six1883_header *) (header0 + 1); + header1->format_tag = 1; + header1->packet_channel = 0x1F; + header1->packet_tcode = 0xA; + header1->app_control = 0x0; + header1->reserved0 = 0; + header1->source_id = 0x3F; + header1->data_block_size = CHANNELS; + header1->fraction_number = 0; + header1->quadlet_padding_count = 0; + header1->source_packet_header = 0; + header1->reserved1 = 0; + header1->eoh = 0x2; + header1->format_id = 0x10; + header1->format_dependent_field = 0x02; + header1->syt = 0xFFFF; + tmp_packet->len = + 18 + sizeof(seventeen22_header) + sizeof(six1883_header) + + (SAMPLES_PER_FRAME * CHANNELS * sizeof(six1883_sample)); + free_packets = tmp_packet; + } + + /* + * subtract 16 bytes for the MAC header/Q-tag - pktsz is limited to the + * data payload of the ethernet frame . + * + * IPG is scaled to the Class (A) observation interval of packets per 125 usec + */ + fprintf(stderr, "advertising stream ...\n"); + mrp_advertise_stream(STREAM_ID, DEST_ADDR, a_vid, PKT_SZ - 16, + PACKET_IPG / 125000, a_priority, 3900); + fprintf(stderr, "awaiting a listener ...\n"); + mrp_await_listener(STREAM_ID); + printf("got a listener ...\n"); + halt_tx = 0; + + gptpinit(); + gptpscaling(&td); + + now_tscns = ST_rdtsc() * 10000 / TEN_USEC_COUNT; + update_tscns = td.local_time + td.ls_phoffset; + update_8021as = td.local_time - td.ml_phoffset; + delta_tscns = (unsigned)(now_tscns - update_tscns); + ml_ratio = -1 * (((long double)td.ml_freqoffset) / 1000000000000) + 1; + ls_ratio = -1 * (((long double)td.ls_freqoffset) / 1000000000000) + 1; + delta_local = (unsigned)(ls_ratio * delta_tscns); + delta_8021as = (unsigned)(ml_ratio * ls_ratio * delta_tscns); + now_8021as = update_8021as + delta_8021as; + last_time = td.local_time + delta_local + XMIT_DELAY; + + time_stamp = now_8021as + RENDER_DELAY; + + rc = nice(-20); + + while (listeners && !halt_tx) { + tmp_packet = free_packets; + if (NULL == tmp_packet) + goto cleanup; + header0 = + (seventeen22_header *) (((char *)tmp_packet->vaddr) + 18); + header1 = (six1883_header *) (header0 + 1); + free_packets = tmp_packet->next; + + /* unfortuntely unless this thread is at rtprio + * you get pre-empted between fetching the time + * and programming the packet and get a late packet + */ + tmp_packet->attime = last_time + PACKET_IPG; + last_time += PACKET_IPG; + + get_samples(SAMPLES_PER_FRAME, sample_buffer); + header0->seq_number = seqnum++; + if (seqnum % 4 == 0) + header0->timestamp_valid = 0; + + else + header0->timestamp_valid = 1; + + time_stamp = htonl(time_stamp); + header0->timestamp = time_stamp; + time_stamp = ntohl(time_stamp); + time_stamp += PACKET_IPG; + header1->data_block_continuity = total_samples; + total_samples += SAMPLES_PER_FRAME; + sample = + (six1883_sample *) (((char *)tmp_packet->vaddr) + + (18 + sizeof(seventeen22_header) + + sizeof(six1883_header))); + + for (i = 0; i < SAMPLES_PER_FRAME * CHANNELS; ++i) { + uint32_t tmp = htonl(sample_buffer[i]); + sample[i].label = 0x40; + memcpy(&(sample[i].value), &(tmp), + sizeof(sample[i].value)); + } + + err = igb_xmit(&igb_dev, 0, tmp_packet); + + if (!err) { + continue; + } + + if (ENOSPC == err) { + + /* put back for now */ + tmp_packet->next = free_packets; + free_packets = tmp_packet; + } + + cleanup: igb_clean(&igb_dev, &cleaned_packets); + i = 0; + while (cleaned_packets) { + i++; + tmp_packet = cleaned_packets; + cleaned_packets = cleaned_packets->next; + tmp_packet->next = free_packets; + free_packets = tmp_packet; + } + } + rc = nice(0); + + if (halt_tx == 0) + printf("listener left ...\n"); + halt_tx = 1; + + mrp_unadvertise_stream(STREAM_ID, DEST_ADDR, a_vid, PKT_SZ - 16, + PACKET_IPG / 125000, a_priority, 3900); + + igb_set_class_bandwidth(&igb_dev, 0, 0, 0, 0); /* disable Qav */ + + rc = mrp_disconnect(); + + igb_dma_free_page(&igb_dev, &a_page); + + err = igb_detach(&igb_dev); + + pthread_exit(NULL); + + return (0); +} diff --git a/examples/test.c b/examples/test.c deleted file mode 100644 index 524aa24..0000000 --- a/examples/test.c +++ /dev/null @@ -1,219 +0,0 @@ -/****************************************************************************** - - Copyright (c) 2001-2012, Intel Corporation - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. 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. - - 3. Neither the name of the Intel Corporation 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. - -******************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include "igb.h" - -#define IGB_BIND_NAMESZ 24 - -device_t igb_dev; -volatile int halt_tx; - -void -sigint_handler (int signum) -{ - printf("got SIGINT\n"); - halt_tx = signum; -} - -int -connect() -{ - struct pci_access *pacc; - struct pci_dev *dev; - int err; - char devpath[IGB_BIND_NAMESZ]; - - memset(&igb_dev, 0, sizeof(device_t)); - - pacc = pci_alloc(); - pci_init(pacc); - pci_scan_bus(pacc); - for (dev=pacc->devices; dev; dev=dev->next) - { - pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); - - igb_dev.pci_vendor_id = dev->vendor_id; - igb_dev.pci_device_id = dev->device_id; - igb_dev.domain = dev->domain; - igb_dev.bus = dev->bus; - igb_dev.dev = dev->dev; - igb_dev.func = dev->func; - - snprintf(devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d", \ - dev->domain, dev->bus, dev->dev, dev->func ); - printf("probing %s\n", devpath); - - err = igb_probe(&igb_dev); - - if (err) { - continue; - } - - printf ("attaching to %s\n", devpath); - err = igb_attach(devpath, &igb_dev); - - if (err) { - printf ("attach failed! (%s)\n", strerror(errno)); - continue; - } - printf("attach successful to %s\n", devpath); - goto out; - } - - pci_cleanup(pacc); - return ENXIO; - -out: - pci_cleanup(pacc); - return 0; - -} - -#define PACKET_IPG (20000000) /* 20 msec */ - -int -main() -{ - unsigned i; - int err; - struct igb_dma_alloc a_page; - struct igb_packet a_packet; - struct igb_packet *tmp_packet; - struct igb_packet *cleaned_packets; - struct igb_packet *free_packets; - u_int64_t last_time; - u_int64_t rdtsc0; - - err = connect(); - - if (err) { printf("connect failed (%s)\n", strerror(errno)); return(errno); } - - err = igb_init(&igb_dev); - - if (err) { printf("init failed (%s)\n", strerror(errno)); return(errno); } - - err = igb_dma_malloc_page(&igb_dev, &a_page); - - if (err) { printf("malloc failed (%s)\n", strerror(errno)); return(errno); } - -#define PKT_SZ 200 - a_packet.dmatime = a_packet.attime = a_packet.flags = 0; - a_packet.map.paddr = a_page.dma_paddr; - a_packet.map.mmap_size = a_page.mmap_size; - - a_packet.offset = 0; - a_packet.vaddr = a_page.dma_vaddr + a_packet.offset; - a_packet.len = PKT_SZ; - - free_packets = NULL; - - /* divide the dma page into buffers for packets */ - for (i = 1; i < ((a_page.mmap_size) / PKT_SZ); i++) { - tmp_packet = malloc(sizeof(struct igb_packet)); - if (NULL == tmp_packet) { printf("failed to allocate igb_packet memory!\n"); return(errno); } - - *tmp_packet = a_packet; - tmp_packet->offset = (i * PKT_SZ); - tmp_packet->vaddr += tmp_packet->offset; - tmp_packet->next = free_packets; - memset(tmp_packet->vaddr, 0xffffffff, PKT_SZ); /* MAC header at least */ - free_packets = tmp_packet; - } - - igb_set_class_bandwidth(&igb_dev, 0, 0, 0); /* disable Qav */ - - halt_tx = 0; - signal(SIGINT, sigint_handler); - - - igb_get_wallclock(&igb_dev, &last_time, &rdtsc0); - - while (!halt_tx) { - tmp_packet = free_packets; - - if (NULL == tmp_packet) goto cleanup; - - free_packets = tmp_packet->next; - - tmp_packet->attime = last_time + PACKET_IPG; - *(u_int64_t *)(tmp_packet->vaddr + 32) = tmp_packet->attime; - - err = igb_xmit(&igb_dev, 0, tmp_packet); - - if (!err) { last_time += PACKET_IPG; continue; } - - if (ENOSPC == err) { - /* put back for now */ - tmp_packet->next = free_packets; - free_packets = tmp_packet; - } -cleanup: - igb_clean(&igb_dev, &cleaned_packets); - i = 0; - while (cleaned_packets) { - i++; - tmp_packet = cleaned_packets; - cleaned_packets = cleaned_packets->next; - /* remap attime to compare to dma time */ - while (tmp_packet->attime > 999999999) tmp_packet->attime -= 1000000000; - /* doesn't handle wrap-around ! */ - printf("delta(attime-dmatime)=%d\n", (unsigned int)(tmp_packet->attime - tmp_packet->dmatime)); - tmp_packet->next = free_packets; - free_packets = tmp_packet; - } - - } - - igb_dma_free_page(&igb_dev, &a_page); - err = igb_detach(&igb_dev); - return(0); -} - diff --git a/kmod/LICENSE b/kmod/igb/LICENSE similarity index 100% rename from kmod/LICENSE rename to kmod/igb/LICENSE diff --git a/kmod/Makefile b/kmod/igb/Makefile similarity index 100% rename from kmod/Makefile rename to kmod/igb/Makefile diff --git a/kmod/igb/README b/kmod/igb/README new file mode 100644 index 0000000..08f9a5c --- /dev/null +++ b/kmod/igb/README @@ -0,0 +1,31 @@ +INTRODUCTION + +This component demonstrates various features of the Intel I210 Ethernet +controller. These features can be used for developing Audio/Video Bridging +applications, Industrial Ethernet applications which require precise timing +control over frame transmission, or test harnesses for measuring system +latencies and sampling events. + +This component - igb_avb - is limited to the Intel I210 Ethernet controller. +The kernel module can be loaded in parallel to existing in-kernel igb modules +which may be used on other supported Intel LAN controllers. Modifications are +required to the in-kernel drivers if the existing in-kernel igb driver has +support for the Intel I210. + +BUILDING + +The kernel igb module can be built which supports the latest Linux kernel +3.x PTP clock support - to enable, modify kmod/Makefile and enable -DCONFIG_PTP +as a build option (e.g. EXTRA_CFLAGS += -DCONFIG_PTP). + +RUNNING + +To install the kernel mode driver, you must have root permissions. Typically, +the driver is loaded by: + sudo modprobe dca + sudo modprobe ptp + sudo insmod ./igb_avb.ko + +As 3.4 and later kernels include support for the I210, you may need to 'rmmod +igb' before loading the igb_avb module. + diff --git a/kmod/e1000_82575.c b/kmod/igb/e1000_82575.c similarity index 100% rename from kmod/e1000_82575.c rename to kmod/igb/e1000_82575.c diff --git a/kmod/e1000_82575.h b/kmod/igb/e1000_82575.h similarity index 100% rename from kmod/e1000_82575.h rename to kmod/igb/e1000_82575.h diff --git a/kmod/e1000_api.c b/kmod/igb/e1000_api.c similarity index 100% rename from kmod/e1000_api.c rename to kmod/igb/e1000_api.c diff --git a/kmod/e1000_api.h b/kmod/igb/e1000_api.h similarity index 100% rename from kmod/e1000_api.h rename to kmod/igb/e1000_api.h diff --git a/kmod/e1000_defines.h b/kmod/igb/e1000_defines.h similarity index 100% rename from kmod/e1000_defines.h rename to kmod/igb/e1000_defines.h diff --git a/kmod/e1000_hw.h b/kmod/igb/e1000_hw.h similarity index 100% rename from kmod/e1000_hw.h rename to kmod/igb/e1000_hw.h diff --git a/kmod/e1000_i210.c b/kmod/igb/e1000_i210.c similarity index 100% rename from kmod/e1000_i210.c rename to kmod/igb/e1000_i210.c diff --git a/kmod/e1000_i210.h b/kmod/igb/e1000_i210.h similarity index 100% rename from kmod/e1000_i210.h rename to kmod/igb/e1000_i210.h diff --git a/kmod/e1000_mac.c b/kmod/igb/e1000_mac.c similarity index 100% rename from kmod/e1000_mac.c rename to kmod/igb/e1000_mac.c diff --git a/kmod/e1000_mac.h b/kmod/igb/e1000_mac.h similarity index 100% rename from kmod/e1000_mac.h rename to kmod/igb/e1000_mac.h diff --git a/kmod/e1000_manage.c b/kmod/igb/e1000_manage.c similarity index 100% rename from kmod/e1000_manage.c rename to kmod/igb/e1000_manage.c diff --git a/kmod/e1000_manage.h b/kmod/igb/e1000_manage.h similarity index 100% rename from kmod/e1000_manage.h rename to kmod/igb/e1000_manage.h diff --git a/kmod/e1000_mbx.c b/kmod/igb/e1000_mbx.c similarity index 100% rename from kmod/e1000_mbx.c rename to kmod/igb/e1000_mbx.c diff --git a/kmod/e1000_mbx.h b/kmod/igb/e1000_mbx.h similarity index 100% rename from kmod/e1000_mbx.h rename to kmod/igb/e1000_mbx.h diff --git a/kmod/e1000_nvm.c b/kmod/igb/e1000_nvm.c similarity index 100% rename from kmod/e1000_nvm.c rename to kmod/igb/e1000_nvm.c diff --git a/kmod/e1000_nvm.h b/kmod/igb/e1000_nvm.h similarity index 100% rename from kmod/e1000_nvm.h rename to kmod/igb/e1000_nvm.h diff --git a/kmod/e1000_osdep.h b/kmod/igb/e1000_osdep.h similarity index 100% rename from kmod/e1000_osdep.h rename to kmod/igb/e1000_osdep.h diff --git a/kmod/e1000_phy.c b/kmod/igb/e1000_phy.c similarity index 100% rename from kmod/e1000_phy.c rename to kmod/igb/e1000_phy.c diff --git a/kmod/e1000_phy.h b/kmod/igb/e1000_phy.h similarity index 100% rename from kmod/e1000_phy.h rename to kmod/igb/e1000_phy.h diff --git a/kmod/e1000_regs.h b/kmod/igb/e1000_regs.h similarity index 100% rename from kmod/e1000_regs.h rename to kmod/igb/e1000_regs.h diff --git a/kmod/igb.h b/kmod/igb/igb.h similarity index 100% rename from kmod/igb.h rename to kmod/igb/igb.h diff --git a/kmod/igb_ethtool.c b/kmod/igb/igb_ethtool.c similarity index 100% rename from kmod/igb_ethtool.c rename to kmod/igb/igb_ethtool.c diff --git a/kmod/igb_main.c b/kmod/igb/igb_main.c similarity index 100% rename from kmod/igb_main.c rename to kmod/igb/igb_main.c diff --git a/kmod/igb_param.c b/kmod/igb/igb_param.c similarity index 100% rename from kmod/igb_param.c rename to kmod/igb/igb_param.c diff --git a/kmod/igb_procfs.c b/kmod/igb/igb_procfs.c similarity index 100% rename from kmod/igb_procfs.c rename to kmod/igb/igb_procfs.c diff --git a/kmod/igb_ptp.c b/kmod/igb/igb_ptp.c similarity index 100% rename from kmod/igb_ptp.c rename to kmod/igb/igb_ptp.c diff --git a/kmod/igb_regtest.h b/kmod/igb/igb_regtest.h similarity index 100% rename from kmod/igb_regtest.h rename to kmod/igb/igb_regtest.h diff --git a/kmod/igb_sysfs.c b/kmod/igb/igb_sysfs.c similarity index 100% rename from kmod/igb_sysfs.c rename to kmod/igb/igb_sysfs.c diff --git a/kmod/igb_vmdq.c b/kmod/igb/igb_vmdq.c similarity index 100% rename from kmod/igb_vmdq.c rename to kmod/igb/igb_vmdq.c diff --git a/kmod/igb_vmdq.h b/kmod/igb/igb_vmdq.h similarity index 100% rename from kmod/igb_vmdq.h rename to kmod/igb/igb_vmdq.h diff --git a/kmod/kcompat.c b/kmod/igb/kcompat.c similarity index 100% rename from kmod/kcompat.c rename to kmod/igb/kcompat.c diff --git a/kmod/kcompat.h b/kmod/igb/kcompat.h similarity index 100% rename from kmod/kcompat.h rename to kmod/igb/kcompat.h diff --git a/kmod/kcompat_ethtool.c b/kmod/igb/kcompat_ethtool.c similarity index 100% rename from kmod/kcompat_ethtool.c rename to kmod/igb/kcompat_ethtool.c diff --git a/lib/LICENSE b/lib/igb/LICENSE similarity index 100% rename from lib/LICENSE rename to lib/igb/LICENSE diff --git a/lib/Makefile b/lib/igb/Makefile similarity index 100% rename from lib/Makefile rename to lib/igb/Makefile diff --git a/lib/e1000_82575.h b/lib/igb/e1000_82575.h similarity index 100% rename from lib/e1000_82575.h rename to lib/igb/e1000_82575.h diff --git a/lib/e1000_defines.h b/lib/igb/e1000_defines.h similarity index 100% rename from lib/e1000_defines.h rename to lib/igb/e1000_defines.h diff --git a/lib/e1000_hw.h b/lib/igb/e1000_hw.h similarity index 100% rename from lib/e1000_hw.h rename to lib/igb/e1000_hw.h diff --git a/lib/e1000_osdep.h b/lib/igb/e1000_osdep.h similarity index 100% rename from lib/e1000_osdep.h rename to lib/igb/e1000_osdep.h diff --git a/lib/e1000_regs.h b/lib/igb/e1000_regs.h similarity index 100% rename from lib/e1000_regs.h rename to lib/igb/e1000_regs.h diff --git a/lib/igb.c b/lib/igb/igb.c similarity index 91% rename from lib/igb.c rename to lib/igb/igb.c index c149e99..4c814fa 100644 --- a/lib/igb.c +++ b/lib/igb/igb.c @@ -981,7 +981,11 @@ igb_get_wallclock(device_t *dev, u_int64_t *curtime, u_int64_t *rdtsc) return(0); } int -igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b, u_int32_t tpktsz) +igb_set_class_bandwidth(device_t *dev, + u_int32_t class_a, + u_int32_t class_b, + u_int32_t tpktsz_a, + u_int32_t tpktsz_b) { u_int32_t tqavctrl; u_int32_t tqavcc0, tqavcc1; @@ -992,6 +996,7 @@ igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b, u_i struct e1000_hw *hw; struct igb_link_cmd link; int err; + float class_a_percent, class_b_percent; if (NULL == dev) return EINVAL; adapter = (struct adapter *)dev->private_data; @@ -1011,9 +1016,17 @@ igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b, u_i if (link.duplex != FULL_DUPLEX ) return EINVAL; - if ((class_a + class_b) > 75 ) return EINVAL; + if (tpktsz_a < 64) + tpktsz_a = 64; /* minimum ethernet frame size */ - if ((tpktsz < 64) || (tpktsz > 2000)) return EINVAL; + if (tpktsz_a > 1500) + return EINVAL; + + if (tpktsz_b < 64) + tpktsz_b = 64; /* minimum ethernet frame size */ + + if (tpktsz_b > 1500) + return EINVAL; tqavctrl = E1000_READ_REG(hw, E1000_TQAVCTRL); @@ -1032,24 +1045,59 @@ igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b, u_i else linkrate = E1000_TQAVCC_LINKRATE; - /* XXX convert to fixed point or floating point percents */ - class_a_idle = (class_a * 2 * linkrate / 100); /* 'class_a' is a percent */ - class_b_idle = (class_b * 2 * linkrate / 100); + /* + * class_a and class_b are the packets-per-(respective)observation + * interval (125 usec for class A, 250 usec for class B) + * these parameters are also used when establishing the MSRP + * talker advertise attribute (as well as the tpktsize) + * + * note that class_a and class_b are independent of the media + * rate. For our idle slope calculation, we need to scale the + * (tpktsz + (media overhead)) * rate -> percentage of media rate. + */ + + /* 12=Ethernet IPG, 8=Preamble+Start of Frame, 18=Mac Header with VLAN+Etype, 4=CRC */ + class_a_percent = (float)((tpktsz_a + (12 + 8 + 18 + 4)) * class_a) ; + class_b_percent = (float)((tpktsz_b + (12 + 8 + 18 + 4)) * class_b) ; + + class_a_percent /= 0.000125; /* class A observation window */ + class_b_percent /= 0.000250; /* class B observation window */ + + if (link.speed == 100) { + class_a_percent /= (100000000.0 / 8); /* bytes-per-sec @ 100Mbps */ + class_b_percent /= (100000000.0 / 8); + class_a_idle = (u_int32_t)(class_a_percent * 0.2 * (float)linkrate + 0.5); + class_b_idle = (u_int32_t)(class_b_percent * 0.2 * (float)linkrate + 0.5); + } else { + class_a_percent /= (1000000000.0 / 8); /* bytes-per-sec @ 1Gbps */ + class_b_percent /= (1000000000.0 / 8); + class_a_idle = (u_int32_t)(class_a_percent * 2.0 * (float)linkrate + 0.5); + class_b_idle = (u_int32_t)(class_b_percent * 2.0 * (float)linkrate + 0.5); + } + + if ((class_a_percent + class_b_percent) > 0.75) + return EINVAL; tqavcc0 |= class_a_idle; tqavcc1 |= class_b_idle; /* - * The datasheet lists a formula for configuring the high credit threshold, - * however it is only relevant in the conditions the high priority SR queues - * are internally pre-empted by manageability traffic or low power proxy modes - - * and if the SR queues are pre-empted, they would burst more packets than expected. - * So - if you enable manageability or proxy modes while running AVB traffic, you - * should program the high credit thresholds to prevent non-compliant packet bursts. - * But be aware the stream didn't stream as much bandwidth as it reserved, - * and you may have had an underrun on the listener. + * hiCredit is the number of idleslope credits accumulated due to delay T + * + * we assume the maxInterferenceSize is 18 + 4 + 1500 (1522). + * Note: if EEE is enabled, we should use for maxInterferenceSize + * the overhead of link recovery (a media-specific quantity). + */ + tqavhc0 = 0x80000000 + (class_a_idle * 1522 / linkrate ); /* L.10 */ + + /* + * Class B high credit is is the same, except the delay + * is the MaxBurstSize of Class A + maxInterferenceSize of non-SR traffic + * + * L.41 + * max Class B delay = (1522 + tpktsz_a) / (linkrate - class_a_idle) */ - tqavhc0 = 0xFFFFFFFF; - tqavhc1 = 0xFFFFFFFF; + + tqavhc1 = 0x80000000 + (class_b_idle * ((1522 + tpktsz_a)/ (linkrate - class_a_idle))); /* implicitly enable the Qav shaper */ tqavctrl |= E1000_TQAVCTRL_TX_ARB; diff --git a/lib/igb.h b/lib/igb/igb.h similarity index 98% rename from lib/igb.h rename to lib/igb/igb.h index 4e8239c..5eba112 100644 --- a/lib/igb.h +++ b/lib/igb/igb.h @@ -86,7 +86,7 @@ void igb_dma_free_page(device_t *dev, struct igb_dma_alloc *page); int igb_xmit(device_t *dev, unsigned int queue_index, struct igb_packet *packet); void igb_clean(device_t *dev, struct igb_packet **cleaned_packets); int igb_get_wallclock(device_t *dev, u_int64_t *curtime, u_int64_t *rdtsc); -int igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b, u_int32_t tpktsz); +int igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b, u_int32_t tpktsz_a, u_int32_t tpktsz_b); void igb_trigger(device_t *dev, u_int32_t data); void igb_readreg(device_t *dev, u_int32_t reg, u_int32_t *data); diff --git a/lib/igb_internal.h b/lib/igb/igb_internal.h similarity index 100% rename from lib/igb_internal.h rename to lib/igb/igb_internal.h