summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Hall <christopher.s.hall@intel.com>2017-10-18 13:23:08 -0700
committerChristopher S. Hall <christopher.s.hall@intel.com>2017-12-13 12:09:44 -0500
commitd04ba86e2bb17aa3568df7be1caddd44387c0cbd (patch)
treeb1507357a19ddcd7b623041dd207c467881e5f1d
parent9bbb455e4eb27a428404e00bb82b2cf3976dd087 (diff)
downloadOpen-AVB-d04ba86e2bb17aa3568df7be1caddd44387c0cbd.tar.gz
Added wireless timestamper and port code
buildPTPMessage friend declarations and function definition now use CommonPort object processMessage method in PTP message classes now use CommonPort argument redundant documentation for buildPTPMessage and processMessage removed leaving only that in the base class Add cast to addEventTimerLocked() call (CommonPort::processEvent) preventing Windows compiler warnings Moved all message interval maintenance to CommonPort, also simiplifying Signal message processing Divided FollowUp processing code into two functions for code received on an EtherPort or a WirelessPort (as a Vendor Extension) Modified Windows daemon code to accept a wireless flags Added Windows wireless adapter abstract class to implement a PROSet-like interface for Windows Implemented an Intel specific Windows wireless adapter class tested on 8260 hardware with driver version 19.50.1.6
-rw-r--r--daemons/gptp/README.rst29
-rw-r--r--daemons/gptp/common/avbts_clock.hpp9
-rw-r--r--daemons/gptp/common/avbts_message.hpp105
-rw-r--r--daemons/gptp/common/avbts_osipc.hpp1
-rw-r--r--daemons/gptp/common/common_port.cpp9
-rw-r--r--daemons/gptp/common/common_port.hpp97
-rw-r--r--daemons/gptp/common/ether_port.cpp97
-rw-r--r--daemons/gptp/common/ether_port.hpp38
-rw-r--r--daemons/gptp/common/ieee1588.hpp12
-rw-r--r--daemons/gptp/common/ptp_message.cpp624
-rw-r--r--daemons/gptp/common/wireless_port.cpp242
-rw-r--r--daemons/gptp/common/wireless_port.hpp179
-rw-r--r--daemons/gptp/common/wireless_tstamper.cpp127
-rw-r--r--daemons/gptp/common/wireless_tstamper.hpp221
-rw-r--r--daemons/gptp/linux/src/daemon_cl.cpp1
-rw-r--r--daemons/gptp/windows/daemon_cl/daemon_cl.cpp129
-rw-r--r--daemons/gptp/windows/daemon_cl/intel_wireless.cpp424
-rw-r--r--daemons/gptp/windows/daemon_cl/intel_wireless.hpp187
-rw-r--r--daemons/gptp/windows/daemon_cl/tsc.hpp13
-rw-r--r--daemons/gptp/windows/daemon_cl/windows_hal.cpp180
-rw-r--r--daemons/gptp/windows/daemon_cl/windows_hal.hpp114
-rw-r--r--daemons/gptp/windows/daemon_cl/work_queue.cpp106
-rw-r--r--daemons/gptp/windows/daemon_cl/work_queue.hpp74
-rw-r--r--daemons/gptp/windows/named_pipe_test/named_pipe_test.cpp2
24 files changed, 2564 insertions, 456 deletions
diff --git a/daemons/gptp/README.rst b/daemons/gptp/README.rst
index f56fd719..1e26543d 100644
--- a/daemons/gptp/README.rst
+++ b/daemons/gptp/README.rst
@@ -94,6 +94,35 @@ To run from the command line:
where xx-xx-xx-xx-xx-xx is the mac address of the local interface
+Windows Wireless Specific
++++++++++++++++++++++++++
+
+Additional Driver/Hardware Requirements:
+
+* Intel(R) 8260 Adapter
+
+* Intel(R) PROSet/Wireless Software
+
+
+The wireless software can be downloaded from:
+
+https://downloadcenter.intel.com/ (Search)
+
+Running the daemon:
+
+Currently, the driver only works with peer-to-peer wireless connections.
+The connection must be established prior to running the daemon.
+
+./gptp.exe -w <local hw device MAC> <local P2P MAC> <remove P2P MAC>
+
+Other limitations:
+
+Some versions of Windows(R) 10 do not allow WinPcap(R) to inject frames and
+the BMCA algorithm can't complete. The result is both peers assume the master
+role. To fix this, force one peer to be slave with the following command line:
+
+./gptp.exe -w -R 255 <local hw device MAC> <local P2P MAC> <remove P2P MAC>
+
Other Available PTP Daemons
---------------------------
There are a number of existing ptp daemon projects. Some of the other known
diff --git a/daemons/gptp/common/avbts_clock.hpp b/daemons/gptp/common/avbts_clock.hpp
index feb8d9d1..614464c2 100644
--- a/daemons/gptp/common/avbts_clock.hpp
+++ b/daemons/gptp/common/avbts_clock.hpp
@@ -550,6 +550,15 @@ public:
FrequencyRatio local_system_freq_offset, unsigned sync_count,
unsigned pdelay_count, PortState port_state, bool asCapable );
+ /**
+ * @brief Get local:system frequency ratio
+ * @return clock ratio
+ */
+ FrequencyRatio getLocalSystemFreqOffset()
+ {
+ return _local_system_freq_offset;
+ }
+
/**
* @brief Get the IEEE1588Clock identity value
* @return clock identity
diff --git a/daemons/gptp/common/avbts_message.hpp b/daemons/gptp/common/avbts_message.hpp
index f18d1213..f5ccd9a1 100644
--- a/daemons/gptp/common/avbts_message.hpp
+++ b/daemons/gptp/common/avbts_message.hpp
@@ -204,6 +204,17 @@ public:
};
/**
+ * @brief Builds PTP message from buffer
+ * @param buf [in] byte buffer containing PTP message
+ * @param size [in] length of buffer in bytes
+ * @param remote [in] address from where message was received
+ * @param port [in] port object that message was recieved on
+ * @return PTP message object
+ */
+PTPMessageCommon *buildPTPMessage
+( char *buf, int size, LinkLayerAddress *remote, CommonPort *port );
+
+/**
* @brief Provides the PTPMessage common interface used during building of
* PTP messages.
*/
@@ -373,10 +384,10 @@ protected:
/**
* @brief Generic interface for processing PTP message
- * @param port IEEE1588 port
+ * @param port CommonPort object
* @return void
*/
- virtual void processMessage( EtherPort *port );
+ virtual void processMessage( CommonPort *port );
/**
* @brief Builds PTP common header
@@ -386,8 +397,7 @@ protected:
void buildCommonHeader(uint8_t * buf);
friend PTPMessageCommon *buildPTPMessage
- ( char *buf, int size, LinkLayerAddress * remote,
- EtherPort *port );
+ ( char *buf, int size, LinkLayerAddress *remote, CommonPort *port );
};
/*Exact fit. No padding*/
@@ -589,12 +599,7 @@ class PTPMessageAnnounce:public PTPMessageCommon {
return ret;
}
- /**
- * @brief Processes PTP message
- * @param port EtherPort
- * @return void
- */
- void processMessage( EtherPort *port );
+ void processMessage( CommonPort *port );
/**
* @brief Assembles PTPMessageAnnounce message on the
@@ -608,8 +613,7 @@ class PTPMessageAnnounce:public PTPMessageCommon {
( CommonPort *port, PortIdentity *destIdentity);
friend PTPMessageCommon *buildPTPMessage
- ( char *buf, int size, LinkLayerAddress *remote,
- EtherPort *port );
+ ( char *buf, int size, LinkLayerAddress *remote, CommonPort *port );
};
/**
@@ -632,12 +636,7 @@ class PTPMessageSync : public PTPMessageCommon {
*/
~PTPMessageSync();
- /**
- * @brief Processes PTP messages
- * @param port [in] EtherPort
- * @return void
- */
- void processMessage( EtherPort *port );
+ void processMessage( CommonPort *port );
/**
* @brief Gets origin timestamp value
@@ -659,8 +658,7 @@ class PTPMessageSync : public PTPMessageCommon {
(EtherPort *port, PortIdentity *destIdentity );
friend PTPMessageCommon *buildPTPMessage
- ( char *buf, int size, LinkLayerAddress * remote,
- EtherPort *port );
+ ( char *buf, int size, LinkLayerAddress *remote, CommonPort *port );
};
/* Exact fit. No padding*/
@@ -866,7 +864,15 @@ public:
/**
* @brief Builds the PTPMessageFollowUP object
*/
- PTPMessageFollowUp( EtherPort *port );
+ PTPMessageFollowUp( CommonPort *port );
+
+ /**
+ * @brief write followup message into buffer
+ * @param port [in] associated CommonPort object
+ * @param buf_ptr [out] buffer to write data to
+ * @return number of bytes written to buffer
+ */
+ size_t buildMessage(CommonPort *port, uint8_t *buf_ptr);
/**
* @brief Assembles PTPMessageFollowUp message on the
@@ -879,12 +885,16 @@ public:
bool sendPort
( EtherPort *port, PortIdentity *destIdentity );
+ void processMessage( CommonPort *port );
+
/**
- * @brief Processes PTP messages
- * @param port [in] EtherPort
- * @return void
- */
- void processMessage( EtherPort *port );
+ * @brief Processes PTP messages
+ * @param port [in] CommonPort
+ * @param receipt [in] local time message was received
+ * @param delay
+ * @return void
+ */
+ void processMessage( CommonPort *port, Timestamp receipt );
/**
* @brief Gets the precise origin timestamp value
@@ -916,8 +926,7 @@ public:
}
friend PTPMessageCommon *buildPTPMessage
- ( char *buf, int size, LinkLayerAddress *remote,
- EtherPort *port );
+ ( char *buf, int size, LinkLayerAddress *remote, CommonPort *port );
};
/**
@@ -953,12 +962,7 @@ class PTPMessagePathDelayReq : public PTPMessageCommon {
bool sendPort
( EtherPort *port, PortIdentity *destIdentity );
- /**
- * @brief Processes PTP messages
- * @param port [in] EtherPort
- * @return void
- */
- void processMessage( EtherPort *port );
+ void processMessage( CommonPort *port );
/**
* @brief Gets origin timestamp value
@@ -969,8 +973,7 @@ class PTPMessagePathDelayReq : public PTPMessageCommon {
}
friend PTPMessageCommon *buildPTPMessage
- ( char *buf, int size, LinkLayerAddress *remote,
- EtherPort *port );
+ ( char *buf, int size, LinkLayerAddress *remote, CommonPort *port );
};
/**
@@ -1004,12 +1007,7 @@ public:
bool sendPort
( EtherPort *port, PortIdentity *destIdentity );
- /**
- * @brief Processes PTP messages
- * @param port [in] EtherPort
- * @return void
- */
- void processMessage( EtherPort *port );
+ void processMessage( CommonPort *port );
/**
* @brief Sets the request receipt timestamp
@@ -1042,8 +1040,7 @@ public:
}
friend PTPMessageCommon *buildPTPMessage
- ( char *buf, int size, LinkLayerAddress *remote,
- EtherPort *port );
+ ( char *buf, int size, LinkLayerAddress *remote, CommonPort *port );
};
/**
@@ -1078,12 +1075,7 @@ public:
bool sendPort
( EtherPort *port, PortIdentity *destIdentity );
- /**
- * @brief Processes PTP messages
- * @param port [in] EtherPort
- * @return void
- */
- void processMessage( EtherPort *port );
+ void processMessage( CommonPort *port );
/**
* @brief Sets the response origin timestamp
@@ -1116,8 +1108,7 @@ public:
}
friend PTPMessageCommon *buildPTPMessage
- ( char *buf, int size, LinkLayerAddress *remote,
- EtherPort *port );
+ ( char *buf, int size, LinkLayerAddress *remote, CommonPort *port );
};
/*Exact fit. No padding*/
@@ -1267,16 +1258,10 @@ public:
bool sendPort
( EtherPort *port, PortIdentity *destIdentity );
- /**
- * @brief Processes PTP messages
- * @param port [in] EtherPort
- * @return void
- */
- void processMessage( EtherPort *port );
+ void processMessage( CommonPort *port );
friend PTPMessageCommon *buildPTPMessage
- ( char *buf, int size, LinkLayerAddress *remote,
- EtherPort * port);
+ ( char *buf, int size, LinkLayerAddress *remote, CommonPort *port );
};
#endif
diff --git a/daemons/gptp/common/avbts_osipc.hpp b/daemons/gptp/common/avbts_osipc.hpp
index 00bac5dd..2adb3dbd 100644
--- a/daemons/gptp/common/avbts_osipc.hpp
+++ b/daemons/gptp/common/avbts_osipc.hpp
@@ -36,7 +36,6 @@
#include <stdint.h>
#include <ptptypes.hpp>
-#include <ether_port.hpp>
/**@file*/
diff --git a/daemons/gptp/common/common_port.cpp b/daemons/gptp/common/common_port.cpp
index d8ba54f6..268bc62d 100644
--- a/daemons/gptp/common/common_port.cpp
+++ b/daemons/gptp/common/common_port.cpp
@@ -61,9 +61,11 @@ CommonPort::CommonPort( PortInit_t *portInit ) :
port_state = PTP_INITIALIZING;
clock->registerPort(this, ifindex);
qualified_announce = NULL;
+ automotive_profile = portInit->automotive_profile;
announce_sequence_id = 0;
signal_sequence_id = 0;
sync_sequence_id = 0;
+ initialLogPdelayReqInterval = portInit->initialLogPdelayReqInterval;
initialLogSyncInterval = portInit->initialLogSyncInterval;
log_mean_announce_interval = 0;
pdelay_count = 0;
@@ -563,7 +565,7 @@ bool CommonPort::processEvent( Event e )
else
{
clock->addEventTimerLocked(this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
- ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * pow(2.0, getAnnounceInterval()) * 1000000000.0);
+ (uint64_t) ( ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * pow(2.0, getAnnounceInterval()) * 1000000000.0 ));
}
// Do any media specific initialization
@@ -732,6 +734,11 @@ bool CommonPort::adjustClockPhase( int64_t phase_adjust )
return false;
}
+FrequencyRatio CommonPort::getLocalSystemFreqOffset()
+{
+ return clock->getLocalSystemFreqOffset();
+}
+
Timestamp CommonPort::getTxPhyDelay( uint32_t link_speed ) const
{
if( phy_delay->count( link_speed ) != 0 )
diff --git a/daemons/gptp/common/common_port.hpp b/daemons/gptp/common/common_port.hpp
index d5d0adda..4f195836 100644
--- a/daemons/gptp/common/common_port.hpp
+++ b/daemons/gptp/common/common_port.hpp
@@ -45,6 +45,10 @@
#include <math.h>
+#define SYNC_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< Sync rcpt timeout multiplier */
+#define ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< Annc rcpt timeout mult */
+#define LOG2_INTERVAL_INVALID -127 /* Invalid Log base 2 interval value */
+
class IEEE1588Clock;
/**
@@ -214,6 +218,9 @@ typedef struct {
/* net_label Network label */
InterfaceLabel *net_label;
+ /* Virtual Network label (e.g. WiFi Direct network MAC) */
+ InterfaceLabel *virtual_label;
+
/* automotive_profile set the AVnu automotive profile */
bool automotive_profile;
@@ -313,6 +320,7 @@ private:
PortState port_state;
bool testMode;
+ bool automotive_profile;
signed char log_mean_sync_interval;
signed char log_mean_announce_interval;
@@ -336,6 +344,9 @@ private:
* received as slave */
unsigned pdelay_count;
+ signed char initialLogPdelayReqInterval;
+ signed char log_min_mean_pdelay_req_interval;
+
PTPMessageAnnounce *qualified_announce;
uint16_t announce_sequence_id;
@@ -436,6 +447,13 @@ public:
}
/**
+ * @brief Return frequency offset between local timestamp clock
+ * system clock
+ * @return local:system ratio
+ */
+ FrequencyRatio getLocalSystemFreqOffset();
+
+ /**
* @brief Gets a pointer to IEEE1588Clock
* @return Pointer to clock
*/
@@ -1115,6 +1133,63 @@ public:
virtual void becomeSlave( bool restart_syntonization ) = 0;
/**
+ * @brief Gets the AVnu automotive profile flag
+ * @return automotive_profile flag
+ */
+ bool getAutomotiveProfile() { return(automotive_profile); }
+
+ /**
+ * @brief Sets the pDelay minimum interval
+ * @param val time interval
+ * @return none
+ */
+ void setPDelayInterval(signed char val) {
+ log_min_mean_pdelay_req_interval = val;
+ }
+
+ /**
+ * @brief Gets the pDelay minimum interval
+ * @return PDelay interval
+ */
+ signed char getPDelayInterval(void) {
+ return log_min_mean_pdelay_req_interval;
+ }
+
+ /**
+ * @brief Sets the pDelay minimum interval back to initial
+ * value
+ * @return none
+ */
+ void resetInitPDelayInterval(void) {
+ log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
+ }
+
+ /**
+ * @brief set initial pdelay interval
+ * @param interval [in] log base 2 pdelay rate
+ */
+ void setInitPDelayInterval( int8_t interval )
+ {
+ initialLogPdelayReqInterval = interval;
+ }
+
+ /**
+ * @brief get initial pdelay interval
+ * @return log base 2 pdelay rate
+ */
+ int8_t getInitPDelayInterval(void)
+ {
+ return initialLogPdelayReqInterval;
+ }
+
+ /**
+ * @brief Start pDelay interval timer
+ * @param waitTime time interval
+ * @return none
+ */
+ virtual void startPDelayIntervalTimer( unsigned long long waitTime ) {}
+
+ /**
* @brief Sets current sync count value.
* @param cnt [in] sync count value
* @return void
@@ -1336,20 +1411,24 @@ public:
*/
virtual bool _processEvent( Event e ) = 0;
+ /**
+ * @brief Performs media specific setup after start sync is completed
+ * @return void
+ */
virtual void syncDone() = 0;
/**
- * @brief Sends a general message to a port. No timestamps
- * @param buf [in] Pointer to the data buffer
- * @param len Size of the message
- * @param mcast_type Enumeration
- * MulticastType (pdelay, none or other). Depracated.
- * @param destIdentity Destination port identity
- * @return void
- */
+ * @brief Sends a general message to a port. No timestamps
+ * @param buf [in] Pointer to the data buffer
+ * @param len Size of the message
+ * @param mcast_type Enumeration
+ * MulticastType (pdelay, none or other). Depracated.
+ * @param destIdentity Destination port identity
+ * @return void
+ */
virtual void sendGeneralPort
(uint16_t etherType, uint8_t * buf, int len, MulticastType mcast_type,
- PortIdentity * destIdentity) = 0;
+ PortIdentity * destIdentity) = 0;
/**
* @brief Sets link speed
diff --git a/daemons/gptp/common/ether_port.cpp b/daemons/gptp/common/ether_port.cpp
index 2325fb99..e576705c 100644
--- a/daemons/gptp/common/ether_port.cpp
+++ b/daemons/gptp/common/ether_port.cpp
@@ -85,7 +85,6 @@ EtherPort::~EtherPort()
EtherPort::EtherPort( PortInit_t *portInit ) :
CommonPort( portInit )
{
- automotive_profile = portInit->automotive_profile;
linkUp = portInit->linkUp;
setTestMode( portInit->testMode );
@@ -98,29 +97,29 @@ EtherPort::EtherPort( PortInit_t *portInit ) :
duplicate_resp_counter = 0;
last_invalid_seqid = 0;
- initialLogPdelayReqInterval = portInit->initialLogPdelayReqInterval;
operLogPdelayReqInterval = portInit->operLogPdelayReqInterval;
operLogSyncInterval = portInit->operLogSyncInterval;
- if (automotive_profile) {
+ if (getAutomotiveProfile())
+ {
setAsCapable( true );
if (getInitSyncInterval() == LOG2_INTERVAL_INVALID)
setInitSyncInterval( -5 ); // 31.25 ms
- if (initialLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
- initialLogPdelayReqInterval = 0; // 1 second
+ if (getInitPDelayInterval() == LOG2_INTERVAL_INVALID)
+ setInitPDelayInterval( 0 ); // 1 second
if (operLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
operLogPdelayReqInterval = 0; // 1 second
if (operLogSyncInterval == LOG2_INTERVAL_INVALID)
operLogSyncInterval = 0; // 1 second
- }
- else {
+ } else
+ {
setAsCapable( false );
if ( getInitSyncInterval() == LOG2_INTERVAL_INVALID )
setInitSyncInterval( -3 ); // 125 ms
- if (initialLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
- initialLogPdelayReqInterval = 0; // 1 second
+ if (getInitPDelayInterval() == LOG2_INTERVAL_INVALID)
+ setInitPDelayInterval( 0 ); // 1 second
if (operLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
operLogPdelayReqInterval = 0; // 1 second
if (operLogSyncInterval == LOG2_INTERVAL_INVALID)
@@ -128,7 +127,7 @@ EtherPort::EtherPort( PortInit_t *portInit ) :
}
/*TODO: Add intervals below to a config interface*/
- log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
+ resetInitPDelayInterval();
last_sync = NULL;
last_pdelay_req = NULL;
@@ -138,7 +137,8 @@ EtherPort::EtherPort( PortInit_t *portInit ) :
setPdelayCount(0);
setSyncCount(0);
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
if (isGM) {
avbSyncState = 1;
}
@@ -169,10 +169,16 @@ bool EtherPort::_init_port( void )
void EtherPort::startPDelay()
{
if(!pdelayHalted()) {
- if (automotive_profile) {
- if (log_min_mean_pdelay_req_interval != PTPMessageSignalling::sigMsgInterval_NoSend) {
+ if( getAutomotiveProfile( ))
+ {
+ if( getPDelayInterval() !=
+ PTPMessageSignalling::sigMsgInterval_NoSend)
+ {
long long unsigned int waitTime;
- waitTime = ((long long) (pow((double)2, log_min_mean_pdelay_req_interval) * 1000000000.0));
+ waitTime = ((long long)
+ (pow((double)2,
+ getPDelayInterval()) *
+ 1000000000.0));
waitTime = waitTime > EVENT_TIMER_GRANULARITY ? waitTime : EVENT_TIMER_GRANULARITY;
pdelay_started = true;
startPDelayIntervalTimer(waitTime);
@@ -194,7 +200,8 @@ void EtherPort::stopPDelay()
void EtherPort::startSyncRateIntervalTimer()
{
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
sync_rate_interval_timer_started = true;
if (isGM) {
// GM will wait up to 8 seconds for signaling rate
@@ -325,7 +332,8 @@ bool EtherPort::_processEvent( Event e )
switch (e) {
case POWERUP:
case INITIALIZE:
- if (!automotive_profile) {
+ if( !getAutomotiveProfile( ))
+ {
if ( getPortState() != PTP_SLAVE &&
getPortState() != PTP_MASTER )
{
@@ -355,7 +363,8 @@ bool EtherPort::_processEvent( Event e )
port_ready_condition->wait();
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
setStationState(STATION_STATE_ETHERNET_READY);
if (getTestMode())
{
@@ -387,7 +396,7 @@ bool EtherPort::_processEvent( Event e )
// If the automotive profile is enabled, handle the event by
// doing nothing and returning true, preventing the default
// action from executing
- if( automotive_profile )
+ if( getAutomotiveProfile( ))
ret = true;
else
ret = false;
@@ -396,7 +405,8 @@ bool EtherPort::_processEvent( Event e )
case LINKUP:
haltPdelay(false);
startPDelay();
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
GPTP_LOG_EXCEPTION("LINKUP");
}
else {
@@ -408,11 +418,16 @@ bool EtherPort::_processEvent( Event e )
} else if( getPortState() == PTP_MASTER ) {
becomeMaster( true );
} else {
- clock->addEventTimerLocked(this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
- ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * pow(2.0, getAnnounceInterval()) * 1000000000.0);
+ clock->addEventTimerLocked
+ ( this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
+ (uint64_t)
+ ( ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER *
+ pow( 2.0, getAnnounceInterval( )) *
+ 1000000000.0 ));
}
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
setAsCapable( true );
setStationState(STATION_STATE_ETHERNET_READY);
@@ -427,7 +442,7 @@ bool EtherPort::_processEvent( Event e )
resetInitSyncInterval();
setAnnounceInterval( 0 );
- log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
+ resetInitPDelayInterval();
if (!isGM) {
// Send an initial signaling message
@@ -468,7 +483,8 @@ bool EtherPort::_processEvent( Event e )
break;
case LINKDOWN:
stopPDelay();
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
GPTP_LOG_EXCEPTION("LINK DOWN");
}
else {
@@ -484,7 +500,7 @@ bool EtherPort::_processEvent( Event e )
break;
case ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES:
case SYNC_RECEIPT_TIMEOUT_EXPIRES:
- if( !automotive_profile )
+ if( !getAutomotiveProfile( ))
{
ret = false;
break;
@@ -568,8 +584,8 @@ bool EtherPort::_processEvent( Event e )
tx_succeed = sync->sendPort(this, NULL);
GPTP_LOG_DEBUG("Sent SYNC message");
- if ( automotive_profile &&
- getPortState() == PTP_MASTER )
+ if( getAutomotiveProfile() &&
+ getPortState() == PTP_MASTER )
{
if (avbSyncState > 0) {
avbSyncState--;
@@ -618,7 +634,8 @@ bool EtherPort::_processEvent( Event e )
break;
case FAULT_DETECTED:
GPTP_LOG_ERROR("Received FAULT_DETECTED event");
- if (!automotive_profile) {
+ if( !getAutomotiveProfile( ))
+ {
setAsCapable(false);
}
break;
@@ -637,7 +654,8 @@ bool EtherPort::_processEvent( Event e )
pdelay_rx_lock->unlock();
break;
case PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES:
- if (!automotive_profile) {
+ if( !getAutomotiveProfile( ))
+ {
GPTP_LOG_EXCEPTION("PDelay Response Receipt Timeout");
setAsCapable(false);
}
@@ -668,8 +686,9 @@ bool EtherPort::_processEvent( Event e )
sendSignalMessage = true;
}
- if (log_min_mean_pdelay_req_interval != operLogPdelayReqInterval) {
- log_min_mean_pdelay_req_interval = operLogPdelayReqInterval;
+ if( getPDelayInterval() != operLogPdelayReqInterval)
+ {
+ setPDelayInterval( operLogPdelayReqInterval );
sendSignalMessage = true;
}
@@ -678,10 +697,10 @@ bool EtherPort::_processEvent( Event e )
// Send operational signalling message
PTPMessageSignalling *sigMsg = new PTPMessageSignalling(this);
if (sigMsg) {
- if (automotive_profile)
+ if( getAutomotiveProfile( ))
sigMsg->setintervals(PTPMessageSignalling::sigMsgInterval_NoChange, getSyncInterval(), PTPMessageSignalling::sigMsgInterval_NoChange);
else
- sigMsg->setintervals(log_min_mean_pdelay_req_interval, getSyncInterval(), PTPMessageSignalling::sigMsgInterval_NoChange);
+ sigMsg->setintervals(getPDelayInterval(), getSyncInterval(), PTPMessageSignalling::sigMsgInterval_NoChange);
sigMsg->sendPort(this, NULL);
delete sigMsg;
}
@@ -720,7 +739,8 @@ void EtherPort::becomeMaster( bool annc ) {
stopSyncReceiptTimer();
if( annc ) {
- if (!automotive_profile) {
+ if( !getAutomotiveProfile( ))
+ {
startAnnounce();
}
}
@@ -738,7 +758,8 @@ void EtherPort::becomeSlave( bool restart_syntonization ) {
setPortState( PTP_SLAVE );
- if (!automotive_profile) {
+ if( !getAutomotiveProfile( ))
+ {
clock->addEventTimerLocked
(this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
(ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER*
@@ -832,7 +853,8 @@ void EtherPort::startPDelayIntervalTimer
void EtherPort::syncDone() {
GPTP_LOG_VERBOSE("Sync complete");
- if (automotive_profile && getPortState() == PTP_SLAVE) {
+ if( getAutomotiveProfile() && getPortState() == PTP_SLAVE )
+ {
if (avbSyncState > 0) {
avbSyncState--;
if (avbSyncState == 0) {
@@ -849,7 +871,8 @@ void EtherPort::syncDone() {
}
}
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
if (!sync_rate_interval_timer_started) {
if ( getSyncInterval() != operLogSyncInterval )
{
diff --git a/daemons/gptp/common/ether_port.hpp b/daemons/gptp/common/ether_port.hpp
index 32968dc4..4c878951 100644
--- a/daemons/gptp/common/ether_port.hpp
+++ b/daemons/gptp/common/ether_port.hpp
@@ -60,10 +60,6 @@
#define TEST_STATUS_MULTICAST 0x011BC50AC000ULL /*!< AVnu Automotive profile test status msg Multicast value */
#define PDELAY_RESP_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< PDelay timeout multiplier*/
-#define SYNC_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< Sync receipt timeout multiplier*/
-#define ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< Announce receipt timeout multiplier*/
-
-#define LOG2_INTERVAL_INVALID -127 /* Simple out of range Log base 2 value used for Sync and PDelay msg internvals */
/**
* @brief PortType enumeration. Selects between delay request-response (E2E) mechanism
@@ -98,7 +94,6 @@ class EtherPort : public CommonPort
/* Port Configuration */
signed char log_mean_unicast_sync_interval;
signed char log_min_mean_delay_req_interval;
- signed char log_min_mean_pdelay_req_interval;
unsigned int duplicate_resp_counter;
uint16_t last_invalid_seqid;
@@ -109,8 +104,6 @@ class EtherPort : public CommonPort
// asCapable : already defined as asCapable
signed char operLogPdelayReqInterval;
signed char operLogSyncInterval;
- signed char initialLogPdelayReqInterval;
- bool automotive_profile;
// Test Status variables
uint32_t linkUpCount;
@@ -201,12 +194,6 @@ protected:
void syncDone();
/**
- * @brief Gets the AVnu automotive profile flag
- * @return automotive_profile flag
- */
- bool getAutomotiveProfile() { return( automotive_profile ); }
-
- /**
* @brief Destroys a EtherPort
*/
~EtherPort();
@@ -303,31 +290,6 @@ protected:
void removeForeignMasterAll(void);
/**
- * @brief Gets the pDelay minimum interval
- * @return PDelay interval
- */
- signed char getPDelayInterval(void) {
- return log_min_mean_pdelay_req_interval;
- }
-
- /**
- * @brief Sets the pDelay minimum interval
- * @param val time interval
- * @return none
- */
- void setPDelayInterval(signed char val) {
- log_min_mean_pdelay_req_interval = val;
- }
-
- /**
- * @brief Sets the pDelay minimum interval back to initial
- * value
- * @return none */
- void setInitPDelayInterval(void) {
- log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
- }
-
- /**
* @brief Start pDelay interval timer
* @param waitTime time interval
* @return none
diff --git a/daemons/gptp/common/ieee1588.hpp b/daemons/gptp/common/ieee1588.hpp
index bd95a5fa..cf3d59e4 100644
--- a/daemons/gptp/common/ieee1588.hpp
+++ b/daemons/gptp/common/ieee1588.hpp
@@ -452,16 +452,4 @@ static inline void TIMESTAMP_ADD_NS( Timestamp &ts, uint64_t ns ) {
ts.nanoseconds = (uint32_t)nanos;
}
-/**
- * @brief Builds a PTP message
- * @param buf [in] message buffer to send
- * @param size message length
- * @param remote Destination link layer address
- * @param port [in] IEEE1588 port
- * @return PTP message instance of PTPMessageCommon
- */
-PTPMessageCommon *buildPTPMessage
-( char *buf, int size, LinkLayerAddress *remote,
- EtherPort *port );
-
#endif
diff --git a/daemons/gptp/common/ptp_message.cpp b/daemons/gptp/common/ptp_message.cpp
index 9219338b..6decc7a3 100644
--- a/daemons/gptp/common/ptp_message.cpp
+++ b/daemons/gptp/common/ptp_message.cpp
@@ -67,7 +67,7 @@ bool PTPMessageCommon::isSenderEqual(PortIdentity portIdentity)
PTPMessageCommon *buildPTPMessage
( char *buf, int size, LinkLayerAddress *remote,
- EtherPort *port )
+ CommonPort *port )
{
OSTimer *timer = port->getTimerFactory()->createTimer();
PTPMessageCommon *msg = NULL;
@@ -80,6 +80,7 @@ PTPMessageCommon *buildPTPMessage
PortIdentity *sourcePortIdentity;
Timestamp timestamp(0, 0, 0);
unsigned counter_value = 0;
+ EtherPort *eport = NULL;
#if PTP_DEBUG
{
@@ -123,8 +124,18 @@ PTPMessageCommon *buildPTPMessage
if (!(messageType >> 3)) {
int iter = 5;
long req = 4000; // = 1 ms
+
+ eport = dynamic_cast <EtherPort *> ( port );
+ if (eport == NULL)
+ {
+ GPTP_LOG_ERROR
+ ( "Received Event Message, but port type "
+ "doesn't support timestamping\n" );
+ goto abort;
+ }
+
int ts_good =
- port->getRxTimestamp
+ eport->getRxTimestamp
(sourcePortIdentity, messageId, timestamp, counter_value, false);
while (ts_good != GPTP_EC_SUCCESS && iter-- != 0) {
// Waits at least 1 time slice regardless of size of 'req'
@@ -134,7 +145,7 @@ PTPMessageCommon *buildPTPMessage
"Error (RX) timestamping RX event packet (Retrying), error=%d",
ts_good );
ts_good =
- port->getRxTimestamp(sourcePortIdentity, messageId,
+ eport->getRxTimestamp(sourcePortIdentity, messageId,
timestamp, counter_value,
iter == 0);
req *= 2;
@@ -527,7 +538,8 @@ PTPMessageCommon *buildPTPMessage
buf + PTP_COMMON_HDR_LOG_MSG_INTRVL(PTP_COMMON_HDR_OFFSET),
sizeof(msg->logMeanMessageInterval));
- port->addSockAddrMap(msg->sourcePortIdentity, remote);
+ if( eport != NULL )
+ eport->addSockAddrMap( msg->sourcePortIdentity, remote );
msg->_timestamp = timestamp;
msg->_timestamp_counter_value = counter_value;
@@ -587,7 +599,7 @@ bool PTPMessageCommon::getTxTimestamp( EtherPort *port, uint32_t link_speed )
return ts_good == GPTP_EC_SUCCESS;
}
-void PTPMessageCommon::processMessage( EtherPort *port )
+void PTPMessageCommon::processMessage( CommonPort *port )
{
_gc = true;
return;
@@ -838,7 +850,7 @@ bool PTPMessageAnnounce::sendPort
return true;
}
-void PTPMessageAnnounce::processMessage( EtherPort *port )
+void PTPMessageAnnounce::processMessage( CommonPort *port )
{
ClockIdentity my_clock_identity;
@@ -875,15 +887,25 @@ void PTPMessageAnnounce::processMessage( EtherPort *port )
1000000000.0)));
}
-void PTPMessageSync::processMessage( EtherPort *port )
+void PTPMessageSync::processMessage( CommonPort *port )
{
+ EtherPort *eport = dynamic_cast <EtherPort *> (port);
+ PTPMessageSync *old_sync;
+
+ if (eport == NULL)
+ {
+ GPTP_LOG_ERROR( "Discarding sync message on wrong port type" );
+ _gc = true;
+ goto done;
+ }
+
if (port->getPortState() == PTP_DISABLED ) {
- // Do nothing Sync messages should be ignored when in this state
+ // Do nothing Sync messages should be ignored in this state
return;
}
if (port->getPortState() == PTP_FAULTY) {
// According to spec recovery is implementation specific
- port->recoverPort();
+ eport->recoverPort();
return;
}
@@ -892,12 +914,12 @@ void PTPMessageSync::processMessage( EtherPort *port )
#if CHECK_ASSIST_BIT
if( flags[PTP_ASSIST_BYTE] & (0x1<<PTP_ASSIST_BIT)) {
#endif
- PTPMessageSync *old_sync = port->getLastSync();
+ old_sync = eport->getLastSync();
if (old_sync != NULL) {
delete old_sync;
}
- port->setLastSync(this);
+ eport->setLastSync(this);
_gc = false;
goto done;
#if CHECK_ASSIST_BIT
@@ -912,7 +934,7 @@ void PTPMessageSync::processMessage( EtherPort *port )
return;
}
-PTPMessageFollowUp::PTPMessageFollowUp( EtherPort *port ) :
+PTPMessageFollowUp::PTPMessageFollowUp( CommonPort *port ) :
PTPMessageCommon( port )
{
messageType = FOLLOWUP_MESSAGE; /* This is an event message */
@@ -923,52 +945,65 @@ PTPMessageFollowUp::PTPMessageFollowUp( EtherPort *port ) :
return;
}
-bool PTPMessageFollowUp::sendPort
-( EtherPort *port, PortIdentity *destIdentity )
+size_t PTPMessageFollowUp::buildMessage( CommonPort *port, uint8_t *buf_ptr )
{
- 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 */
+ Copy in common header */
messageLength =
- PTP_COMMON_HDR_LENGTH + PTP_FOLLOWUP_LENGTH + sizeof(tlv);
+ PTP_COMMON_HDR_LENGTH + PTP_FOLLOWUP_LENGTH + sizeof(tlv);
+ unsigned char tspec_msg_t = 0;
+ Timestamp preciseOriginTimestamp_BE;
+
tspec_msg_t |= messageType & 0xF;
buildCommonHeader(buf_ptr);
preciseOriginTimestamp_BE.seconds_ms =
- PLAT_htons(preciseOriginTimestamp.seconds_ms);
+ PLAT_htons(preciseOriginTimestamp.seconds_ms);
preciseOriginTimestamp_BE.seconds_ls =
- PLAT_htonl(preciseOriginTimestamp.seconds_ls);
+ PLAT_htonl(preciseOriginTimestamp.seconds_ls);
preciseOriginTimestamp_BE.nanoseconds =
- PLAT_htonl(preciseOriginTimestamp.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));
+ &(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));
+ &(preciseOriginTimestamp_BE.seconds_ls),
+ sizeof(preciseOriginTimestamp.seconds_ls));
memcpy(buf_ptr + PTP_FOLLOWUP_NSEC(PTP_FOLLOWUP_OFFSET),
- &(preciseOriginTimestamp_BE.nanoseconds),
- sizeof(preciseOriginTimestamp.nanoseconds));
+ &(preciseOriginTimestamp_BE.nanoseconds),
+ sizeof(preciseOriginTimestamp.nanoseconds));
/*Change time base indicator to Network Order before sending it*/
uint16_t tbi_NO = PLAT_htonl(tlv.getGMTimeBaseIndicator());
tlv.setGMTimeBaseIndicator(tbi_NO);
- tlv.toByteString(buf_ptr + PTP_COMMON_HDR_LENGTH + PTP_FOLLOWUP_LENGTH);
+ tlv.toByteString(buf_ptr + PTP_COMMON_HDR_LENGTH +
+ PTP_FOLLOWUP_LENGTH);
- GPTP_LOG_VERBOSE
- ("Follow-Up Time: %u seconds(hi)", preciseOriginTimestamp.seconds_ms);
- GPTP_LOG_VERBOSE
- ("Follow-Up Time: %u seconds", preciseOriginTimestamp.seconds_ls);
- GPTP_LOG_VERBOSE
- ("FW-UP Time: %u nanoseconds", preciseOriginTimestamp.nanoseconds);
- GPTP_LOG_VERBOSE
- ("FW-UP Time: %x seconds", preciseOriginTimestamp.seconds_ls);
- GPTP_LOG_VERBOSE
- ("FW-UP Time: %x nanoseconds", preciseOriginTimestamp.nanoseconds);
+ port->incCounter_ieee8021AsPortStatTxFollowUpCount();
+
+ return PTP_COMMON_HDR_LENGTH + PTP_FOLLOWUP_LENGTH + sizeof(tlv);
+}
+
+bool PTPMessageFollowUp::sendPort
+( EtherPort *port, PortIdentity *destIdentity )
+{
+ uint8_t buf_t[256];
+ uint8_t *buf_ptr = buf_t + port->getPayloadOffset();
+ memset(buf_t, 0, 256);
+ /* Create packet in buf
+ Copy in common header */
+ buildMessage(port, buf_ptr);
+
+ GPTP_LOG_VERBOSE( "Follow-Up Time: %u seconds(hi)",
+ preciseOriginTimestamp.seconds_ms);
+ GPTP_LOG_VERBOSE( "Follow-Up Time: %u seconds",
+ preciseOriginTimestamp.seconds_ls);
+ GPTP_LOG_VERBOSE( "FW-UP Time: %u nanoseconds",
+ preciseOriginTimestamp.nanoseconds);
+ GPTP_LOG_VERBOSE( "FW-UP Time: %x seconds",
+ preciseOriginTimestamp.seconds_ls);
+ GPTP_LOG_VERBOSE( "FW-UP Time: %x nanoseconds",
+ preciseOriginTimestamp.nanoseconds);
#ifdef DEBUG
GPTP_LOG_VERBOSE("Follow-up Dump:");
for (int i = 0; i < messageLength; ++i) {
@@ -976,17 +1011,16 @@ bool PTPMessageFollowUp::sendPort
}
#endif
- port->sendGeneralPort(PTP_ETHERTYPE, buf_t, messageLength, MCAST_OTHER, destIdentity);
-
- port->incCounter_ieee8021AsPortStatTxFollowUpCount();
+ port->sendGeneralPort( PTP_ETHERTYPE, buf_t, messageLength,
+ MCAST_OTHER, destIdentity );
return true;
}
-void PTPMessageFollowUp::processMessage( EtherPort *port )
+void PTPMessageFollowUp::processMessage
+( CommonPort *port, Timestamp sync_arrival )
{
uint64_t delay;
- Timestamp sync_arrival;
Timestamp system_time(0, 0, 0);
Timestamp device_time(0, 0, 0);
@@ -1000,166 +1034,201 @@ void PTPMessageFollowUp::processMessage( EtherPort *port )
int32_t scaledLastGmFreqChange = 0;
scaledNs scaledLastGmPhaseChange;
- GPTP_LOG_DEBUG("Processing a follow-up message");
-
- // Expire any SYNC_RECEIPT timers that exist
- port->stopSyncReceiptTimer();
-
- if (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;
- }
-
port->incCounter_ieee8021AsPortStatRxFollowUpCount();
- PortIdentity sync_id;
- PTPMessageSync *sync = port->getLastSync();
- if (sync == NULL) {
- GPTP_LOG_ERROR("Received Follow Up but there is no sync message");
- return;
- }
- sync->getPortIdentity(&sync_id);
-
- if (sync->getSequenceId() != sequenceId || sync_id != *sourcePortIdentity)
- {
- unsigned int cnt = 0;
-
- if( !port->incWrongSeqIDCounter(&cnt) )
- {
- port->becomeMaster( true );
- port->setWrongSeqIDCounter(0);
- }
- GPTP_LOG_ERROR
- ("Received Follow Up %d times but cannot find corresponding Sync", cnt);
+ if (!port->getLinkDelay(&delay))
goto done;
- }
- if (sync->getTimestamp()._version != port->getTimestampVersion())
- {
- GPTP_LOG_ERROR("Received Follow Up but timestamp version indicates Sync is out of date");
- goto done;
- }
-
- sync_arrival = sync->getTimestamp();
-
- if( !port->getLinkDelay(&delay) ) {
- goto done;
- }
-
- master_local_freq_offset = tlv.getRateOffset();
+ master_local_freq_offset = tlv.getRateOffset();
master_local_freq_offset /= 1ULL << 41;
master_local_freq_offset += 1.0;
master_local_freq_offset /= port->getPeerRateOffset();
correctionField /= 1 << 16;
- correction = (int64_t)((delay * master_local_freq_offset) + correctionField );
+ correction = (int64_t)
+ ((delay * master_local_freq_offset) + correctionField);
- if( correction > 0 )
- TIMESTAMP_ADD_NS( preciseOriginTimestamp, correction );
- else TIMESTAMP_SUB_NS( preciseOriginTimestamp, -correction );
+ if (correction > 0)
+ TIMESTAMP_ADD_NS(preciseOriginTimestamp, correction);
+ else TIMESTAMP_SUB_NS(preciseOriginTimestamp, -correction);
local_clock_adjustment =
- port->getClock()->
- calcMasterLocalClockRateDifference
- ( preciseOriginTimestamp, sync_arrival );
+ port->getClock()->
+ calcMasterLocalClockRateDifference
+ (preciseOriginTimestamp, sync_arrival);
if( local_clock_adjustment == NEGATIVE_TIME_JUMP )
{
- GPTP_LOG_VERBOSE("Received Follow Up but preciseOrigintimestamp indicates negative time jump");
+ GPTP_LOG_VERBOSE
+ ( "Received Follow Up but preciseOrigintimestamp "
+ "indicates negative time jump" );
goto done;
}
- scalar_offset = TIMESTAMP_TO_NS( sync_arrival );
+ scalar_offset = TIMESTAMP_TO_NS( sync_arrival );
scalar_offset -= TIMESTAMP_TO_NS( preciseOriginTimestamp );
- GPTP_LOG_VERBOSE
- ("Followup Correction Field: %Ld, Link Delay: %lu", correctionField,
- delay);
- GPTP_LOG_VERBOSE
- ("FollowUp Scalar = %lld", scalar_offset);
+ GPTP_LOG_VERBOSE( "Followup Correction Field: %lld, Link Delay: %lu",
+ correctionField, delay );
+ GPTP_LOG_VERBOSE( "FollowUp Scalar = %lld",
+ scalar_offset );
- /* Otherwise synchronize clock with approximate time from Sync message */
+ /* Otherwise synchronize clock with approximate Sync time */
uint32_t local_clock, nominal_clock_rate;
uint32_t device_sync_time_offset;
port->getDeviceTime(system_time, device_time, local_clock,
- nominal_clock_rate);
- GPTP_LOG_VERBOSE
- ( "Device Time = %llu,System Time = %llu",
- TIMESTAMP_TO_NS(device_time), TIMESTAMP_TO_NS(system_time));
+ nominal_clock_rate);
+ GPTP_LOG_VERBOSE( "Device Time = %llu,System Time = %llu",
+ TIMESTAMP_TO_NS( device_time ),
+ TIMESTAMP_TO_NS( system_time ));
/* Adjust local_clock to correspond to sync_arrival */
- device_sync_time_offset =
- (uint32_t) (TIMESTAMP_TO_NS(device_time) - TIMESTAMP_TO_NS(sync_arrival));
+ device_sync_time_offset = (uint32_t)
+ ( TIMESTAMP_TO_NS( device_time ) -
+ TIMESTAMP_TO_NS( sync_arrival ));
GPTP_LOG_VERBOSE
- ("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);
+ ( "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);
/*Update information on local status structure.*/
- scaledLastGmFreqChange = (int32_t)((1.0/local_clock_adjustment -1.0) * (1ULL << 41));
- scaledLastGmPhaseChange.setLSB( tlv.getRateOffset() );
- port->getClock()->getFUPStatus()->setScaledLastGmFreqChange( scaledLastGmFreqChange );
- port->getClock()->getFUPStatus()->setScaledLastGmPhaseChange( scaledLastGmPhaseChange );
+ scaledLastGmFreqChange = (int32_t)
+ ((1.0 / local_clock_adjustment - 1.0) * (1ULL << 41));
+ scaledLastGmPhaseChange.setLSB(tlv.getRateOffset( ));
+ port->getClock()->getFUPStatus()->setScaledLastGmFreqChange
+ ( scaledLastGmFreqChange );
+ port->getClock()->getFUPStatus()->setScaledLastGmPhaseChange
+ ( scaledLastGmPhaseChange );
if( port->getPortState() == PTP_SLAVE )
{
- /* The sync_count counts the number of sync messages received
- that influence the time on the device. Since adjustments are only
- made in the PTP_SLAVE state, increment it here */
+ /*
+ * The sync_count counts the number of sync messages received
+ * that influence the time on the device. Since adjustments are
+ * only made in the PTP_SLAVE state, increment it here
+ */
port->incSyncCount();
- /* Do not call calcLocalSystemClockRateDifference it updates state
- global to the clock object and if we are master then the network
- is transitioning to us not being master but the master process
- is still running locally */
- local_system_freq_offset =
- port->getClock()
+ /*
+ * Do not call calcLocalSystemClockRateDifference it updates
+ * state global to the clock object and if we are master then
+ * the network is transitioning to us not being master but
+ * the master process is still running locally
+ */
+ local_system_freq_offset = port->getClock()
->calcLocalSystemClockRateDifference
( device_time, system_time );
TIMESTAMP_SUB_NS
- ( system_time, (uint64_t)
- (((FrequencyRatio) device_sync_time_offset)/
- local_system_freq_offset) );
+ (system_time, (uint64_t)
+ (((FrequencyRatio)device_sync_time_offset) /
+ local_system_freq_offset));
local_system_offset =
- TIMESTAMP_TO_NS(system_time) - TIMESTAMP_TO_NS(sync_arrival);
+ TIMESTAMP_TO_NS( system_time ) -
+ TIMESTAMP_TO_NS( sync_arrival );
port->getClock()->setMasterOffset
- ( port, scalar_offset, sync_arrival, local_clock_adjustment,
- local_system_offset, system_time, local_system_freq_offset,
- port->getSyncCount(), port->getPdelayCount(),
- port->getPortState(), port->getAsCapable() );
+ ( port, scalar_offset, sync_arrival, local_clock_adjustment,
+ local_system_offset, system_time, local_system_freq_offset,
+ port->getSyncCount(), port->getPdelayCount(),
+ port->getPortState(), port->getAsCapable( ));
+
port->syncDone();
// Restart the SYNC_RECEIPT timer
port->startSyncReceiptTimer((unsigned long long)
- (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
- ((double) pow((double)2, port->getSyncInterval()) *
- 1000000000.0)));
+ (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
+ ((double)pow((double)2, port->getSyncInterval()) *
+ 1000000000.0)));
}
uint16_t lastGmTimeBaseIndicator;
lastGmTimeBaseIndicator = port->getLastGmTimeBaseIndicator();
- if ((lastGmTimeBaseIndicator > 0) && (tlv.getGmTimeBaseIndicator() != lastGmTimeBaseIndicator)) {
- GPTP_LOG_EXCEPTION("Sync discontinuity");
+ if (( lastGmTimeBaseIndicator > 0 ) &&
+ ( tlv.getGmTimeBaseIndicator( ) != lastGmTimeBaseIndicator ))
+ {
+ GPTP_LOG_EXCEPTION( "Sync discontinuity" );
}
- port->setLastGmTimeBaseIndicator(tlv.getGmTimeBaseIndicator());
+ port->setLastGmTimeBaseIndicator( tlv.getGmTimeBaseIndicator( ));
done:
_gc = true;
- port->setLastSync(NULL);
- delete sync;
return;
}
+void PTPMessageFollowUp::processMessage( CommonPort *port )
+{
+ Timestamp sync_arrival;
+ EtherPort *eport = dynamic_cast <EtherPort *> (port);
+ if (eport == NULL)
+ {
+ GPTP_LOG_ERROR
+ ( "Discarding followup message on wrong port type" );
+ return;
+ }
+
+ GPTP_LOG_DEBUG("Processing a follow-up message");
+
+ // Expire any SYNC_RECEIPT timers that exist
+ port->stopSyncReceiptTimer();
+
+ if (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
+ eport->recoverPort();
+ return;
+ }
+
+ PTPMessageSync *sync = eport->getLastSync();
+ {
+ PortIdentity sync_id;
+ if( sync == NULL )
+ {
+ GPTP_LOG_ERROR("Received Follow Up but there is no "
+ "sync message");
+ return;
+ }
+ sync->getPortIdentity(&sync_id);
+
+ if( sync->getSequenceId() != sequenceId ||
+ sync_id != *sourcePortIdentity )
+ {
+ unsigned int cnt = 0;
+
+ if( !port->incWrongSeqIDCounter( &cnt ))
+ {
+ port->becomeMaster( true );
+ port->setWrongSeqIDCounter(0);
+ }
+ GPTP_LOG_ERROR
+ ( "Received Follow Up %d times but cannot "
+ "find corresponding Sync", cnt );
+ goto done;
+ }
+ }
+
+ if( sync->getTimestamp()._version != port->getTimestampVersion( ))
+ {
+ GPTP_LOG_ERROR( "Received Follow Up but timestamp version "
+ "indicates Sync is out of date" );
+ goto done;
+ }
+
+ sync_arrival = sync->getTimestamp();
+
+ processMessage(port, sync_arrival);
+
+done:
+ eport->setLastSync(NULL);
+ delete sync;
+}
+
PTPMessagePathDelayReq::PTPMessagePathDelayReq
( EtherPort *port ) : PTPMessageCommon( port )
{
@@ -1170,7 +1239,7 @@ PTPMessagePathDelayReq::PTPMessagePathDelayReq
return;
}
-void PTPMessagePathDelayReq::processMessage( EtherPort *port )
+void PTPMessagePathDelayReq::processMessage( CommonPort *port )
{
OSTimer *timer = port->getTimerFactory()->createTimer();
PortIdentity resp_fwup_id;
@@ -1179,6 +1248,13 @@ void PTPMessagePathDelayReq::processMessage( EtherPort *port )
PortIdentity resp_id;
PTPMessagePathDelayRespFollowUp *resp_fwup;
+ EtherPort *eport = dynamic_cast <EtherPort *> (port);
+ if (eport == NULL)
+ {
+ GPTP_LOG_ERROR( "Received Pdelay Request on wrong port type" );
+ goto done;
+ }
+
if (port->getPortState() == PTP_DISABLED) {
// Do nothing all messages should be ignored when in this state
goto done;
@@ -1186,14 +1262,14 @@ void PTPMessagePathDelayReq::processMessage( EtherPort *port )
if (port->getPortState() == PTP_FAULTY) {
// According to spec recovery is implementation specific
- port->recoverPort();
+ eport->recoverPort();
goto done;
}
port->incCounter_ieee8021AsPortStatRxPdelayRequest();
/* Generate and send message */
- resp = new PTPMessagePathDelayResp(port);
+ resp = new PTPMessagePathDelayResp(eport);
port->getPortIdentity(resp_id);
resp->setPortIdentity(&resp_id);
resp->setSequenceId(sequenceId);
@@ -1211,7 +1287,7 @@ void PTPMessagePathDelayReq::processMessage( EtherPort *port )
resp->setRequestReceiptTimestamp(_timestamp);
port->getTxLock();
- resp->sendPort(port, sourcePortIdentity);
+ resp->sendPort(eport, sourcePortIdentity);
GPTP_LOG_DEBUG("*** Sent PDelay Response message");
port->putTxLock();
@@ -1224,7 +1300,7 @@ void PTPMessagePathDelayReq::processMessage( EtherPort *port )
#endif
}
- resp_fwup = new PTPMessagePathDelayRespFollowUp(port);
+ resp_fwup = new PTPMessagePathDelayRespFollowUp(eport);
port->getPortIdentity(resp_fwup_id);
resp_fwup->setPortIdentity(&resp_fwup_id);
resp_fwup->setSequenceId(sequenceId);
@@ -1248,7 +1324,7 @@ void PTPMessagePathDelayReq::processMessage( EtherPort *port )
GPTP_LOG_VERBOSE("#3 Correction Field: %Ld", turnaround);
resp_fwup->setCorrectionField(0);
- resp_fwup->sendPort(port, sourcePortIdentity);
+ resp_fwup->sendPort(eport, sourcePortIdentity);
GPTP_LOG_DEBUG("*** Sent PDelay Response FollowUp message");
@@ -1306,21 +1382,29 @@ PTPMessagePathDelayResp::~PTPMessagePathDelayResp()
delete requestingPortIdentity;
}
-void PTPMessagePathDelayResp::processMessage( EtherPort *port )
+void PTPMessagePathDelayResp::processMessage( CommonPort *port )
{
+ EtherPort *eport = dynamic_cast <EtherPort *> (port);
+ if (eport == NULL)
+ {
+ GPTP_LOG_ERROR( "Received Pdelay Resp on wrong port type" );
+ _gc = true;
+ return;
+ }
+
if (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();
+ eport->recoverPort();
return;
}
port->incCounter_ieee8021AsPortStatRxPdelayResponse();
- if (port->tryPDelayRxLock() != true) {
+ if (eport->tryPDelayRxLock() != true) {
GPTP_LOG_ERROR("Failed to get PDelay RX Lock");
return;
}
@@ -1330,7 +1414,7 @@ void PTPMessagePathDelayResp::processMessage( EtherPort *port )
uint16_t resp_port_number;
uint16_t oldresp_port_number;
- PTPMessagePathDelayResp *old_pdelay_resp = port->getLastPDelayResp();
+ PTPMessagePathDelayResp *old_pdelay_resp = eport->getLastPDelayResp();
if( old_pdelay_resp == NULL ) {
goto bypass_verify_duplicate;
}
@@ -1349,36 +1433,36 @@ void PTPMessagePathDelayResp::processMessage( EtherPort *port )
{
/*If the duplicates are in sequence and from different sources*/
if( (resp_port_number != oldresp_port_number ) && (
- (port->getLastInvalidSeqID() + 1 ) == getSequenceId() ||
- port->getDuplicateRespCounter() == 0 ) ){
+ (eport->getLastInvalidSeqID() + 1 ) == getSequenceId() ||
+ eport->getDuplicateRespCounter() == 0 ) ){
GPTP_LOG_ERROR("Two responses for same Request. seqID %d. First Response Port# %hu. Second Port# %hu. Counter %d",
- getSequenceId(), oldresp_port_number, resp_port_number, port->getDuplicateRespCounter());
+ getSequenceId(), oldresp_port_number, resp_port_number, eport->getDuplicateRespCounter());
- if( port->incrementDuplicateRespCounter() ) {
+ if( eport->incrementDuplicateRespCounter() ) {
GPTP_LOG_ERROR("Remote misbehaving. Stopping PDelay Requests for 5 minutes.");
- port->stopPDelay();
- port->getClock()->addEventTimerLocked
+ eport->stopPDelay();
+ eport->getClock()->addEventTimerLocked
(port, PDELAY_RESP_PEER_MISBEHAVING_TIMEOUT_EXPIRES, (int64_t)(300 * 1000000000.0));
}
}
else {
- port->setDuplicateRespCounter(0);
+ eport->setDuplicateRespCounter(0);
}
- port->setLastInvalidSeqID(getSequenceId());
+ eport->setLastInvalidSeqID(getSequenceId());
}
else
{
- port->setDuplicateRespCounter(0);
+ eport->setDuplicateRespCounter(0);
}
bypass_verify_duplicate:
- port->setLastPDelayResp(this);
+ eport->setLastPDelayResp(this);
if (old_pdelay_resp != NULL) {
delete old_pdelay_resp;
}
- port->putPDelayRxLock();
+ eport->putPDelayRxLock();
_gc = false;
return;
@@ -1467,40 +1551,41 @@ PTPMessagePathDelayRespFollowUp::~PTPMessagePathDelayRespFollowUp()
#define US_PER_SEC 1000000
void PTPMessagePathDelayRespFollowUp::processMessage
-( EtherPort *port )
+( CommonPort *port )
{
+ PTPMessagePathDelayReq *req;
+ PTPMessagePathDelayResp *resp;
+
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);
+ EtherPort *eport = dynamic_cast <EtherPort *> (port);
+ if (eport == NULL)
+ {
+ GPTP_LOG_ERROR( "Received Pdelay Response FollowUp on wrong "
+ "port type" );
+ goto abort;
+ }
+
if (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();
+ eport->recoverPort();
return;
}
port->incCounter_ieee8021AsPortStatRxPdelayResponseFollowUp();
- if (port->tryPDelayRxLock() != true)
+ if (eport->tryPDelayRxLock() != true)
return;
- PTPMessagePathDelayReq *req = port->getLastPDelayReq();
- PTPMessagePathDelayResp *resp = port->getLastPDelayResp();
-
- PortIdentity req_id;
- PortIdentity resp_id;
- PortIdentity fup_sourcePortIdentity;
- PortIdentity resp_sourcePortIdentity;
- ClockIdentity req_clkId;
- ClockIdentity resp_clkId;
-
- uint16_t resp_port_number;
- uint16_t req_port_number;
+ req = eport->getLastPDelayReq();
+ resp = eport->getLastPDelayResp();
if (req == NULL) {
/* Shouldn't happen */
@@ -1517,63 +1602,81 @@ void PTPMessagePathDelayRespFollowUp::processMessage
goto abort;
}
- req->getPortIdentity(&req_id);
- resp->getRequestingPortIdentity(&resp_id);
- req_clkId = req_id.getClockIdentity();
- resp_clkId = resp_id.getClockIdentity();
- resp_id.getPortNumber(&resp_port_number);
- requestingPortIdentity->getPortNumber(&req_port_number);
- resp->getPortIdentity(&resp_sourcePortIdentity);
- getPortIdentity(&fup_sourcePortIdentity);
-
if( req->getSequenceId() != sequenceId ) {
GPTP_LOG_ERROR
- (">>> Received PDelay FUP has different seqID than the PDelay request (%d/%d)",
- sequenceId, req->getSequenceId() );
+ ( "Received PDelay FUP has different seqID than the "
+ "PDelay request (%d/%d)",
+ sequenceId, req->getSequenceId() );
goto abort;
}
- /*
- * IEEE 802.1AS, Figure 11-8, subclause 11.2.15.3
- */
- if (resp->getSequenceId() != sequenceId) {
- GPTP_LOG_ERROR
+ {
+ PortIdentity req_id;
+ PortIdentity resp_id;
+ uint16_t resp_port_number;
+ uint16_t req_port_number;
+
+ ClockIdentity resp_clkId = resp_id.getClockIdentity();
+ ClockIdentity req_clkId = req_id.getClockIdentity();
+ PortIdentity fup_sourcePortIdentity;
+ PortIdentity resp_sourcePortIdentity;
+
+ req->getPortIdentity(&req_id);
+ resp->getRequestingPortIdentity(&resp_id);
+
+ resp_id.getPortNumber(&resp_port_number);
+ requestingPortIdentity->getPortNumber(&req_port_number);
+
+ resp->getPortIdentity(&resp_sourcePortIdentity);
+ getPortIdentity(&fup_sourcePortIdentity);
+
+ /*
+ * IEEE 802.1AS, Figure 11-8, subclause 11.2.15.3
+ */
+ if (resp->getSequenceId() != sequenceId) {
+ GPTP_LOG_ERROR
("Received PDelay Response Follow Up but cannot find "
- "corresponding response");
- GPTP_LOG_ERROR("%hu, %hu, %hu, %hu", resp->getSequenceId(),
- sequenceId, resp_port_number, req_port_number);
+ "corresponding response");
+ GPTP_LOG_ERROR( "%hu, %hu, %hu, %hu",
+ resp->getSequenceId(), sequenceId,
+ resp_port_number, req_port_number );
- goto abort;
- }
+ goto abort;
+ }
- /*
- * IEEE 802.1AS, Figure 11-8, subclause 11.2.15.3
- */
- if (req_clkId != resp_clkId ) {
- GPTP_LOG_ERROR
- ("ClockID Resp/Req differs. PDelay Response ClockID: %s PDelay Request ClockID: %s",
- req_clkId.getIdentityString().c_str(), resp_clkId.getIdentityString().c_str() );
- goto abort;
- }
+ /*
+ * IEEE 802.1AS, Figure 11-8, subclause 11.2.15.3
+ */
+ if (req_clkId != resp_clkId) {
+ GPTP_LOG_ERROR
+ ( "ClockID Resp/Req differs. PDelay Response ClockID: "
+ "%s PDelay Request ClockID: %s",
+ req_clkId.getIdentityString().c_str(),
+ resp_clkId.getIdentityString().c_str( ));
+ goto abort;
+ }
- /*
- * IEEE 802.1AS, Figure 11-8, subclause 11.2.15.3
- */
- if ( resp_port_number != req_port_number ) {
- GPTP_LOG_ERROR
- ("Request port number (%hu) is different from Response port number (%hu)",
- resp_port_number, req_port_number);
+ /*
+ * IEEE 802.1AS, Figure 11-8, subclause 11.2.15.3
+ */
+ if (resp_port_number != req_port_number) {
+ GPTP_LOG_ERROR
+ ( "Request port number (%hu) is different from "
+ "Response port number (%hu)",
+ req_port_number, resp_port_number );
- goto abort;
- }
+ goto abort;
+ }
- /*
- * IEEE 802.1AS, Figure 11-8, subclause 11.2.15.3
- */
- if ( fup_sourcePortIdentity != resp_sourcePortIdentity ) {
- GPTP_LOG_ERROR("Source port identity from PDelay Response/FUP differ");
+ /*
+ * IEEE 802.1AS, Figure 11-8, subclause 11.2.15.3
+ */
+ if (fup_sourcePortIdentity != resp_sourcePortIdentity) {
+ GPTP_LOG_ERROR( "Source port identity from "
+ "PDelay Response/FUP differ" );
- goto abort;
+ goto abort;
+ }
}
port->getClock()->deleteEventTimerLocked
@@ -1589,20 +1692,22 @@ void PTPMessagePathDelayRespFollowUp::processMessage
/* Assume that we are a two step clock, otherwise originTimestamp
may be used */
request_tx_timestamp = req->getTimestamp();
- if( request_tx_timestamp.nanoseconds == INVALID_TIMESTAMP.nanoseconds ) {
+ if( request_tx_timestamp.nanoseconds == INVALID_TIMESTAMP.nanoseconds )
+ {
/* Stop processing the packet */
goto abort;
}
+
if (request_tx_timestamp.nanoseconds ==
PDELAY_PENDING_TIMESTAMP.nanoseconds) {
// Defer processing
if(
- port->getLastPDelayRespFollowUp() != NULL &&
- port->getLastPDelayRespFollowUp() != this )
+ eport->getLastPDelayRespFollowUp() != NULL &&
+ eport->getLastPDelayRespFollowUp() != this )
{
- delete port->getLastPDelayRespFollowUp();
+ delete eport->getLastPDelayRespFollowUp();
}
- port->setLastPDelayRespFollowUp(this);
+ eport->setLastPDelayRespFollowUp(this);
port->getClock()->addEventTimerLocked
(port, PDELAY_DEFERRED_PROCESSING, 1000000);
goto defer;
@@ -1646,7 +1751,8 @@ void PTPMessagePathDelayRespFollowUp::processMessage
if
( port->getPeerRateOffset() > .998 &&
port->getPeerRateOffset() < 1.002 ) {
- turn_around = (int64_t) (turn_around * port->getPeerRateOffset());
+ turn_around = (int64_t)
+ (turn_around * port->getPeerRateOffset());
}
GPTP_LOG_VERBOSE
@@ -1671,42 +1777,52 @@ void PTPMessagePathDelayRespFollowUp::processMessage
FrequencyRatio rate_offset;
if( port->getPeerOffset( prev_peer_ts_mine, prev_peer_ts_theirs )) {
FrequencyRatio upper_ratio_limit, lower_ratio_limit;
- upper_ratio_limit = PPM_OFFSET_TO_RATIO(UPPER_LIMIT_PPM);
- lower_ratio_limit = PPM_OFFSET_TO_RATIO(LOWER_LIMIT_PPM);
-
- 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);
+ upper_ratio_limit =
+ PPM_OFFSET_TO_RATIO(UPPER_LIMIT_PPM);
+ lower_ratio_limit =
+ PPM_OFFSET_TO_RATIO(LOWER_LIMIT_PPM);
+
+ 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);
theirs_elapsed -= port->getLinkDelay();
theirs_elapsed += link_delay < 0 ? 0 : link_delay;
- rate_offset = ((FrequencyRatio) mine_elapsed)/theirs_elapsed;
+ rate_offset = ((FrequencyRatio) mine_elapsed)
+ / theirs_elapsed;
- if( rate_offset < upper_ratio_limit && rate_offset > lower_ratio_limit ) {
+ if( rate_offset < upper_ratio_limit &&
+ rate_offset > lower_ratio_limit )
port->setPeerRateOffset(rate_offset);
- }
}
}
- if( !port->setLinkDelay( link_delay ) ) {
- if (!port->getAutomotiveProfile()) {
- GPTP_LOG_ERROR("Link delay %ld beyond neighborPropDelayThresh; not AsCapable", link_delay);
+ if( !port->setLinkDelay( link_delay ))
+ {
+ if( !eport->getAutomotiveProfile( ))
+ {
+ GPTP_LOG_ERROR( "Link delay %ld beyond "
+ "neighborPropDelayThresh; "
+ "not AsCapable", link_delay );
port->setAsCapable( false );
}
- } else {
- if (!port->getAutomotiveProfile()) {
+ } else
+ {
+ if( !eport->getAutomotiveProfile( ))
port->setAsCapable( true );
- }
}
port->setPeerOffset( request_tx_timestamp, remote_req_rx_timestamp );
abort:
delete req;
- port->setLastPDelayReq(NULL);
+ eport->setLastPDelayReq(NULL);
delete resp;
- port->setLastPDelayResp(NULL);
+ eport->setLastPDelayResp(NULL);
_gc = true;
defer:
- port->putPDelayRxLock();
+ eport->putPDelayRxLock();
return;
}
@@ -1821,7 +1937,7 @@ bool PTPMessageSignalling::sendPort
return true;
}
-void PTPMessageSignalling::processMessage( EtherPort *port )
+void PTPMessageSignalling::processMessage( CommonPort *port )
{
long long unsigned int waitTime;
@@ -1834,7 +1950,7 @@ void PTPMessageSignalling::processMessage( EtherPort *port )
char announceInterval = tlv.getAnnounceInterval();
if (linkDelayInterval == PTPMessageSignalling::sigMsgInterval_Initial) {
- port->setInitPDelayInterval();
+ port->resetInitPDelayInterval();
waitTime = ((long long) (pow((double)2, port->getPDelayInterval()) * 1000000000.0));
waitTime = waitTime > EVENT_TIMER_GRANULARITY ? waitTime : EVENT_TIMER_GRANULARITY;
diff --git a/daemons/gptp/common/wireless_port.cpp b/daemons/gptp/common/wireless_port.cpp
new file mode 100644
index 00000000..40db5015
--- /dev/null
+++ b/daemons/gptp/common/wireless_port.cpp
@@ -0,0 +1,242 @@
+/******************************************************************************
+
+Copyright (c) 2009-2015, 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 <wireless_port.hpp>
+#include <wireless_tstamper.hpp>
+#include <avbts_clock.hpp>
+
+WirelessPort::~WirelessPort()
+{
+ // Intentionally left blank
+}
+
+WirelessPort::WirelessPort( PortInit_t *portInit, LinkLayerAddress peer_addr )
+: CommonPort( portInit )
+{
+ this->peer_addr = peer_addr;
+
+ setAsCapable( true );
+ if ( getInitSyncInterval() == LOG2_INTERVAL_INVALID )
+ setInitSyncInterval (-3 ); // 125 ms
+ if ( getInitPDelayInterval() == LOG2_INTERVAL_INVALID )
+ setInitPDelayInterval( 127 ); // 1 second
+
+ prev_dialog.dialog_token = 0;
+}
+
+bool WirelessPort::_init_port(void)
+{
+ port_ready_condition = condition_factory->createCondition();
+
+ return true;
+}
+
+bool WirelessPort::_processEvent( Event e )
+{
+ bool ret;
+
+ switch (e)
+ {
+ default:
+ GPTP_LOG_ERROR
+ ("Unhandled event type in "
+ "WirelessPort::processEvent(), %d", e);
+ ret = false;
+ break;
+
+ case POWERUP:
+ case INITIALIZE:
+ {
+ port_ready_condition->wait_prelock();
+
+ if ( !linkOpen(_openPort, (void *)this ))
+ {
+ GPTP_LOG_ERROR( "Error creating port thread" );
+ ret = false;
+ break;
+ }
+
+ port_ready_condition->wait();
+
+ ret = true;
+ break;
+ }
+
+ case SYNC_INTERVAL_TIMEOUT_EXPIRES:
+ {
+ WirelessTimestamper *timestamper =
+ dynamic_cast<WirelessTimestamper *>( _hw_timestamper );
+ PTPMessageFollowUp *follow_up;
+ PortIdentity dest_id;
+ uint16_t seq;
+ uint8_t buffer[128];
+ size_t length;
+
+ memset(buffer, 0, sizeof( buffer ));
+
+ if( prev_dialog.dialog_token != 0 )
+ {
+ follow_up = new PTPMessageFollowUp( this );
+
+ getPortIdentity(dest_id);
+ follow_up->setPortIdentity(&dest_id);
+ follow_up->setSequenceId(prev_dialog.fwup_seq);
+ follow_up->setPreciseOriginTimestamp
+ ( prev_dialog.action );
+ length = follow_up->buildMessage
+ (this, buffer + timestamper->getFwUpOffset());
+
+ delete follow_up;
+ }
+
+ seq = getNextSyncSequenceId();
+ ret = timestamper->requestTimingMeasurement
+ ( &peer_addr, seq, &prev_dialog, buffer, (int)length )
+ == net_succeed;
+
+ ret = true;
+ break;
+ }
+
+ case ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES:
+ case SYNC_RECEIPT_TIMEOUT_EXPIRES:
+ ret = false;
+ break;
+
+ case STATE_CHANGE_EVENT:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+bool WirelessPort::openPort()
+{
+ port_ready_condition->signal();
+
+ while (true)
+ {
+ uint8_t buf[128];
+ LinkLayerAddress remote;
+ net_result rrecv;
+ size_t length = sizeof(buf);
+ uint32_t link_speed;
+
+ if(( rrecv = recv( &remote, buf, length, link_speed ))
+ == net_succeed )
+ {
+ processMessage
+ ((char *)buf, (int)length, &remote, link_speed );
+ }
+ else if( rrecv == net_fatal )
+ {
+ GPTP_LOG_ERROR( "read from network interface failed" );
+ this->processEvent( FAULT_DETECTED );
+ break;
+ }
+ }
+
+ return false;
+}
+
+void WirelessPort::sendGeneralPort
+(uint16_t etherType, uint8_t * buf, int len, MulticastType mcast_type,
+ PortIdentity * destIdentity)
+{
+ net_result rtx = send( &peer_addr, etherType, buf, len, false);
+ if( rtx != net_succeed )
+ GPTP_LOG_ERROR( "sendGeneralPort(): failure" );
+
+ return;
+}
+
+void WirelessPort::processMessage
+(char *buf, int length, LinkLayerAddress *remote, uint32_t link_speed)
+{
+ GPTP_LOG_VERBOSE( "Processing network buffer" );
+
+ PTPMessageCommon *msg =
+ buildPTPMessage( buf, (int)length, remote, this );
+
+ if( msg == NULL )
+ {
+ GPTP_LOG_ERROR( "Discarding invalid message" );
+ return;
+ }
+ GPTP_LOG_VERBOSE( "Processing message" );
+
+ if( !msg->isEvent( ))
+ {
+ msg->processMessage( this );
+ } else
+ {
+ GPTP_LOG_ERROR( "Received event message on port "
+ "incapable of processing" );
+ msg->PTPMessageCommon::processMessage( this );
+ }
+
+ if (msg->garbage())
+ delete msg;
+}
+
+void WirelessPort::becomeSlave(bool restart_syntonization)
+{
+ clock->deleteEventTimerLocked(this, ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES);
+ clock->deleteEventTimerLocked( this, SYNC_INTERVAL_TIMEOUT_EXPIRES );
+
+ setPortState( PTP_SLAVE );
+
+ GPTP_LOG_STATUS("Switching to Slave");
+ if( restart_syntonization ) clock->newSyntonizationSetPoint();
+
+ getClock()->updateFUPInfo();
+}
+
+void WirelessPort::becomeMaster(bool annc)
+{
+ setPortState( PTP_MASTER );
+ // Stop announce receipt timeout timer
+ clock->deleteEventTimerLocked( this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES);
+
+ // Stop sync receipt timeout timer
+ stopSyncReceiptTimer();
+
+ if (annc)
+ startAnnounce();
+
+ startSyncIntervalTimer( 16000000 );
+ GPTP_LOG_STATUS( "Switching to Master" );
+
+ clock->updateFUPInfo();
+}
diff --git a/daemons/gptp/common/wireless_port.hpp b/daemons/gptp/common/wireless_port.hpp
new file mode 100644
index 00000000..bfffbd47
--- /dev/null
+++ b/daemons/gptp/common/wireless_port.hpp
@@ -0,0 +1,179 @@
+/******************************************************************************
+
+Copyright (c) 2009-2015, 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 WIRELESS_PORT_HPP
+#define WIRELESS_PORT_HPP
+
+#include <common_port.hpp>
+#include <avbts_oscondition.hpp>
+
+class WirelessDialog
+{
+public:
+ Timestamp action;
+ uint64_t action_devclk;
+ Timestamp ack;
+ uint64_t ack_devclk;
+ uint8_t dialog_token;
+ uint16_t fwup_seq;
+
+ WirelessDialog( uint32_t action, uint32_t ack, uint8_t dialog_token )
+ {
+ this->action_devclk = action; this->ack_devclk = ack;
+ this->dialog_token = dialog_token;
+ }
+
+ WirelessDialog() { dialog_token = 0; }
+
+ WirelessDialog & operator=( const WirelessDialog & a )
+ {
+ if (this != &a)
+ {
+ this->ack = a.ack;
+ this->ack_devclk = a.ack_devclk;
+ this->action = a.action;
+ this->action_devclk = a.action_devclk;
+ this->dialog_token = a.dialog_token;
+ this->fwup_seq = a.fwup_seq;
+ }
+ return *this;
+ }
+};
+
+class WirelessPort : public CommonPort
+{
+private:
+ OSCondition *port_ready_condition;
+ LinkLayerAddress peer_addr;
+ WirelessDialog prev_dialog;
+
+public:
+ WirelessPort( PortInit_t *portInit, LinkLayerAddress peer_addr );
+ virtual ~WirelessPort();
+
+ /**
+ * @brief Media specific port initialization
+ * @return true on success
+ */
+ bool _init_port( void );
+
+ /**
+ * @brief Perform media specific event handling action
+ * @return true if event is handled without errors
+ */
+ bool _processEvent( Event e );
+
+ /**
+ * @brief Process message
+ * @param buf [in] Pointer to the data buffer
+ * @param length Size of the message
+ * @param remote [in] source address of message
+ * @param link_speed [in] for receive operation
+ * @return void
+ */
+ void processMessage
+ (char *buf, int length, LinkLayerAddress *remote, uint32_t link_speed);
+
+ /**
+ * @brief Sends a general message to a port. No timestamps
+ * @param buf [in] Pointer to the data buffer
+ * @param len Size of the message
+ * @param mcast_type Enumeration
+ * MulticastType (pdelay, none or other). Depracated.
+ * @param destIdentity Destination port identity
+ * @return void
+ */
+ void sendGeneralPort
+ ( uint16_t etherType, uint8_t * buf, int len, MulticastType mcast_type,
+ PortIdentity * destIdentity );
+
+ /**
+ * @brief Nothing required for wireless port
+ */
+ void syncDone() {}
+
+ /**
+ * @brief Switches port to a gPTP master
+ * @param annc If TRUE, starts announce event timer.
+ * @return void
+ */
+ void becomeMaster( bool annc );
+
+ /**
+ * @brief Switches port to a gPTP slave.
+ * @param restart_syntonization if TRUE, restarts the syntonization
+ * @return void
+ */
+ void becomeSlave( bool restart_syntonization );
+
+ /**
+ * @brief Receives messages from the network interface
+ * @return Its an infinite loop. Returns false in case of error.
+ */
+ bool openPort();
+
+ /**
+ * @brief Wraps open port method for argument to thread
+ * @param larg pointer to WirelessPort object
+ * @return thread exit code
+ */
+ static OSThreadExitCode _openPort( void *larg )
+ {
+ WirelessPort *port = (decltype(port))larg;
+
+ if (!port->openPort())
+ return osthread_error;
+
+ return osthread_ok;
+ }
+
+ /**
+ * @brief Sets previous dialog
+ * @param dialog new value of prev_dialog
+ */
+ void setPrevDialog( WirelessDialog *dialog )
+ {
+ prev_dialog = *dialog;
+ }
+
+ /**
+ * @brief Sets previous dialog
+ * @return reference to prev_dialog
+ */
+ WirelessDialog *getPrevDialog( void )
+ {
+ return &prev_dialog;
+ }
+};
+
+#endif/*WIRELESS_PORT_HPP*/
diff --git a/daemons/gptp/common/wireless_tstamper.cpp b/daemons/gptp/common/wireless_tstamper.cpp
new file mode 100644
index 00000000..10c3be06
--- /dev/null
+++ b/daemons/gptp/common/wireless_tstamper.cpp
@@ -0,0 +1,127 @@
+/******************************************************************************
+
+Copyright (c) 2009-2015, 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 <wireless_tstamper.hpp>
+#include <wireless_port.hpp>
+
+net_result WirelessTimestamper::requestTimingMeasurement
+( LinkLayerAddress *dest, uint16_t seq, WirelessDialog *prev_dialog,
+ uint8_t *follow_up, int followup_length )
+{
+ WirelessDialog next_dialog;
+ net_result retval;
+ TIMINGMSMT_REQUEST *req;
+
+ // Valid dialog token > 0 && < 256
+ next_dialog.dialog_token = (seq % MAX_DIALOG_TOKEN) + 1;
+ next_dialog.fwup_seq = seq;
+ next_dialog.action_devclk = 0;
+ req = (TIMINGMSMT_REQUEST *)follow_up;
+
+ // File in request
+ req->DialogToken = next_dialog.dialog_token;
+ req->FollowUpDialogToken = prev_dialog->dialog_token;
+ req->Category = 0x0;
+ req->Action = 0x0;
+ req->WiFiVSpecHdr.ElementId = FWUP_VDEF_TAG;
+ req->WiFiVSpecHdr.Length = 0;
+ if( req->FollowUpDialogToken != 0 && prev_dialog->action_devclk != 0 )
+ {
+ req->T1 = (uint32_t)prev_dialog->action_devclk;
+ req->T4 = (uint32_t)prev_dialog->ack_devclk;
+ req->WiFiVSpecHdr.Length = followup_length +
+ (uint8_t)sizeof(FwUpLabel); // 1 byte type
+ req->PtpSpec.FwUpLabel = FwUpLabel;
+ }
+ dest->toOctetArray(req->PeerMACAddress);
+
+ retval = _requestTimingMeasurement( req );
+ port->setPrevDialog(&next_dialog);
+
+ return retval;
+}
+
+void WirelessTimestamper::timingMeasurementConfirmCB
+( LinkLayerAddress addr, WirelessDialog *dialog )
+{
+ WirelessDialog *prev_dialog = port->getPrevDialog();
+
+ // Translate action dev clock to Timestamp
+ // ACK timestamp isn't needed
+ dialog->action.set64(dialog->action_devclk*10);
+
+ if (dialog->dialog_token == prev_dialog->dialog_token)
+ {
+ dialog->fwup_seq = prev_dialog->fwup_seq;
+ port->setPrevDialog(dialog);
+ }
+}
+
+void WirelessTimestamper::timeMeasurementIndicationCB
+( LinkLayerAddress addr, WirelessDialog *current, WirelessDialog *previous,
+ uint8_t *buf, size_t buflen )
+{
+ uint64_t link_delay;
+ WirelessDialog *prev_local;
+ PTPMessageCommon *msg;
+ PTPMessageFollowUp *fwup;
+ // Translate devclk scalar to Timestamp
+
+ msg = buildPTPMessage((char *)buf, (int)buflen, &addr, port);
+ fwup = dynamic_cast<PTPMessageFollowUp *> (msg);
+ current->action_devclk *= 10;
+ current->ack_devclk *= 10;
+ current->action.set64(current->action_devclk);
+ prev_local = port->getPrevDialog();
+ if ( previous->dialog_token == prev_local->dialog_token &&
+ fwup != NULL && previous->action_devclk != 0)
+ {
+ previous->action_devclk *= 10;
+ previous->ack_devclk *= 10;
+ unsigned round_trip = (unsigned)
+ (previous->ack_devclk - previous->action_devclk);
+ unsigned turn_around = (unsigned)
+ (prev_local->ack_devclk - prev_local->action_devclk);
+ link_delay = (round_trip - turn_around) / 2;
+ port->setLinkDelay(link_delay);
+ GPTP_LOG_VERBOSE( "Link Delay = %llu(RT=%u,TA=%u,"
+ "T4=%llu,T1=%llu,DT=%hhu)",
+ link_delay, round_trip, turn_around,
+ previous->ack_devclk,
+ previous->action_devclk,
+ previous->dialog_token);
+ fwup->processMessage(port, prev_local->action);
+ }
+
+ port->setPrevDialog(current);
+}
diff --git a/daemons/gptp/common/wireless_tstamper.hpp b/daemons/gptp/common/wireless_tstamper.hpp
new file mode 100644
index 00000000..79413d0d
--- /dev/null
+++ b/daemons/gptp/common/wireless_tstamper.hpp
@@ -0,0 +1,221 @@
+/******************************************************************************
+
+Copyright (c) 2009-2015, 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 WIRELESS_TSTAMPER_HPP
+#define WIRELESS_TSTAMPER_HPP
+
+#include <common_tstamper.hpp>
+#include <wireless_port.hpp>
+
+#define MAX_DIALOG_TOKEN 255
+#define OUI_8021AS_OCTETS { 0x00, 0x80, 0xC2 }
+static const uint8_t OUI_8021AS[] = OUI_8021AS_OCTETS;
+#define FWUP_TYPE 0
+#define FWUP_VDEF_TAG 0xDD /* Vendor Defined Tag */
+
+typedef enum _WIRELESS_EVENT_TYPE
+{
+ TIMINGMSMT_EVENT = 0,
+ TIMINGMSMT_CONFIRM_EVENT,
+ TIMINGMSMT_CORRELATEDTIME_EVENT,
+} WIRELESS_EVENT_TYPE;
+
+#pragma pack(push, 1)
+typedef struct
+{
+ uint8_t oui[sizeof(OUI_8021AS)];
+ uint8_t type;
+} FwUpLabel_t;
+
+typedef struct _PTP_SPEC
+{
+ FwUpLabel_t FwUpLabel;
+ uint8_t fwup_data[1];
+} PTP_SPEC;
+
+static const FwUpLabel_t FwUpLabel = { OUI_8021AS_OCTETS, FWUP_TYPE };
+
+typedef struct _WIFI_VENDOR_SPEC_HDR
+{
+ uint8_t ElementId;
+ uint8_t Length;
+} WIFI_VENDOR_SPEC_HDR;
+#pragma pack(pop)
+
+typedef struct _TIMINGMSMT_REQUEST
+{
+ uint8_t PeerMACAddress[ETHER_ADDR_OCTETS];
+ uint8_t Category;
+ uint8_t Action;
+ uint8_t DialogToken;
+ uint8_t FollowUpDialogToken;
+ uint32_t T1;
+ uint32_t T4;
+ uint8_t MaxT1Error;
+ uint8_t MaxT4Error;
+
+ WIFI_VENDOR_SPEC_HDR WiFiVSpecHdr;
+ PTP_SPEC PtpSpec;
+} TIMINGMSMT_REQUEST;
+
+typedef struct _TIMINGMSMT_EVENT_DATA
+{
+ uint8_t PeerMACAddress[ETHER_ADDR_OCTETS];
+ uint32_t DialogToken;
+ uint32_t FollowUpDialogToken;
+ uint64_t T1;
+ uint32_t MaxT1Error;
+ uint64_t T4;
+ uint32_t MaxT4Error;
+ uint64_t T2;
+ uint32_t MaxT2Error;
+ uint64_t T3;
+ uint32_t MaxT3Error;
+
+ WIFI_VENDOR_SPEC_HDR WiFiVSpecHdr;
+ PTP_SPEC PtpSpec;
+} TIMINGMSMT_EVENT_DATA;
+
+typedef struct _TIMINGMSMT_CONFIRM_EVENT_DATA
+{
+ uint8_t PeerMACAddress[ETHER_ADDR_OCTETS];
+ uint32_t DialogToken;
+ uint64_t T1;
+ uint32_t MaxT1Error;
+ uint64_t T4;
+ uint32_t MaxT4Error;
+} TIMINGMSMT_CONFIRM_EVENT_DATA;
+
+typedef struct _WIRELESS_CORRELATEDTIME
+{
+ uint64_t TSC;
+ uint64_t LocalClk;
+} WIRELESS_CORRELATEDTIME;
+
+struct S8021AS_Indication {
+ TIMINGMSMT_EVENT_DATA indication;
+ uint8_t followup[75]; // (34 header + 10 followup + 32 TLV) - 1 byte contained in indication struct = 75
+};
+
+union TimeSyncEventData
+{
+ TIMINGMSMT_CONFIRM_EVENT_DATA confirm;
+ S8021AS_Indication indication;
+ WIRELESS_CORRELATEDTIME ptm_wa;
+};
+
+class WirelessTimestamper : public CommonTimestamper
+{
+private:
+ WirelessPort *port;
+public:
+ virtual ~WirelessTimestamper() {}
+
+ /**
+ * @brief attach timestamper to port
+ * @param port port to attach
+ */
+ void setPort( WirelessPort *port )
+ {
+ this->port = port;
+ }
+
+ /**
+ * @brief return reference to attached port
+ * @return reference to attached port
+ */
+ WirelessPort *getPort(void) const
+ {
+ return port;
+ }
+
+ /**
+ * @brief Return buffer offset where followup message should be placed
+ * @return byte offset
+ */
+ uint8_t getFwUpOffset(void)
+ {
+ // Subtract 1 to compensate for 'bogus' vendor specific buffer
+ // length
+ return (uint8_t)((size_t) &((TIMINGMSMT_REQUEST *) 0)->
+ PtpSpec.fwup_data );
+ }
+
+ /**
+ * @brief Request transmission of TM frame
+ * @param dest [in] MAC destination the frame should be sent to
+ * @param seq [in] 802.1AS sequence number
+ * @param prev_dialog [in] last dialog message
+ * @param follow_up [in] buffer containing followup message
+ * @param followup_length [in] fw-up message length in bytes
+ */
+ virtual net_result requestTimingMeasurement
+ ( LinkLayerAddress *dest, uint16_t seq, WirelessDialog *prev_dialog,
+ uint8_t *follow_up, int followup_length );
+
+ /**
+ * @brief abstract method for driver/os specific TM transmit code
+ * @param timingmsmt_req fully formed TM message
+ */
+ virtual net_result _requestTimingMeasurement
+ ( TIMINGMSMT_REQUEST *timingmsmt_req ) = 0;
+
+ /**
+ * @brief Asynchronous completion of TM transmit
+ * @param addr [in] MAC the message was transmitted to
+ * @param dialog [in] dialog filled with T1, T4 timestamps
+ */
+ void timingMeasurementConfirmCB( LinkLayerAddress addr,
+ WirelessDialog *dialog );
+
+ /**
+ * @brief Reception of TM frame
+ * @param addr [in] MAC the message was received from
+ * @param current [in] dialog filled with T2, T3 timestamps
+ * @param previous [in] dialog filled with T1, T4 timestamps
+ * @param buf [in] buffer containing followup message
+ * @param previous [in] length of followup message
+ */
+ void timeMeasurementIndicationCB
+ ( LinkLayerAddress addr, WirelessDialog *current,
+ WirelessDialog *previous, uint8_t *buf, size_t buflen );
+};
+
+struct WirelessTimestamperCallbackArg
+{
+ WIRELESS_EVENT_TYPE iEvent_type;
+ WirelessTimestamper *timestamper;
+ TimeSyncEventData event_data;
+};
+
+#endif/*WIRELESS_TSTAMPER_HPP*/
diff --git a/daemons/gptp/linux/src/daemon_cl.cpp b/daemons/gptp/linux/src/daemon_cl.cpp
index 86806783..3a6d95e5 100644
--- a/daemons/gptp/linux/src/daemon_cl.cpp
+++ b/daemons/gptp/linux/src/daemon_cl.cpp
@@ -37,6 +37,7 @@
#include "avbts_oslock.hpp"
#include "avbts_persist.hpp"
#include "gptp_cfg.hpp"
+#include "ether_port.hpp"
#ifdef ARCH_INTELCE
#include "linux_hal_intelce.hpp"
diff --git a/daemons/gptp/windows/daemon_cl/daemon_cl.cpp b/daemons/gptp/windows/daemon_cl/daemon_cl.cpp
index 5bb2f3c5..8da3ddfa 100644
--- a/daemons/gptp/windows/daemon_cl/daemon_cl.cpp
+++ b/daemons/gptp/windows/daemon_cl/daemon_cl.cpp
@@ -44,6 +44,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include <tchar.h>
#include <iphlpapi.h>
+#include <ether_port.hpp>
+#include <wireless_port.hpp>
+#include <intel_wireless.hpp>
+
/* Generic PCH delays */
#define PHY_DELAY_GB_TX_PCH 7750 //1G delay
#define PHY_DELAY_GB_RX_PCH 7750 //1G delay
@@ -125,9 +129,11 @@ int _tmain(int argc, _TCHAR* argv[])
CommonPort::NEIGHBOR_PROP_DELAY_THRESH;
bool syntonize = false;
+ bool wireless = false;
uint8_t priority1 = 248;
int i;
int phy_delays[4] = { -1, -1, -1, -1 };
+ uint8_t addr_ostr[ETHER_ADDR_OCTETS];
// Register default network interface
WindowsPCAPNetworkInterfaceFactory *default_factory = new WindowsPCAPNetworkInterfaceFactory();
@@ -140,6 +146,8 @@ int _tmain(int argc, _TCHAR* argv[])
portInit.condition_factory = new WindowsConditionFactory();
WindowsNamedPipeIPC *ipc = new WindowsNamedPipeIPC();
WindowsTimerQueueFactory *timerq_factory = new WindowsTimerQueueFactory();
+ CommonPort *port;
+ WindowsWirelessAdapter *wl_adapter = NULL;
if( !ipc->init() ) {
delete ipc;
@@ -155,49 +163,106 @@ int _tmain(int argc, _TCHAR* argv[])
/* Process optional arguments */
for( i = 1; i < argc; ++i ) {
- if( ispunct(argv[i][0]) ) {
- if( toupper( argv[i][1] ) == 'H' ) {
- print_usage( argv[0] );
+ if (ispunct(argv[i][0]))
+ {
+ if (toupper(argv[i][1]) == 'H') {
+ print_usage(argv[0]);
return -1;
}
- else if( toupper( argv[i][1] ) == 'R' ) {
- if( i+1 >= argc ) {
- printf( "Priority 1 value must be specified on "
- "command line, using default value\n" );
- } else {
- unsigned long tmp = strtoul( argv[i+1], NULL, 0 ); ++i;
- if( tmp > 254 ) {
- printf( "Invalid priority 1 value, using "
- "default value\n" );
- } else {
- priority1 = (uint8_t) tmp;
+ if (toupper(argv[i][1]) == 'W')
+ {
+ wireless = true;
+ }
+ else if (toupper(argv[i][1]) == 'R') {
+ if (i + 1 >= argc) {
+ printf("Priority 1 value must be specified on "
+ "command line, using default value\n");
+ }
+ else {
+ unsigned long tmp = strtoul(argv[i + 1], NULL, 0); ++i;
+ if (tmp > 255) {
+ printf("Invalid priority 1 value, using "
+ "default value\n");
+ }
+ else {
+ priority1 = (uint8_t)tmp;
}
}
}
+ } else
+ {
+ break;
}
}
- // the last argument is supposed to be a MAC address, so decrement argv index to read it
- i--;
+ // Parse local HW MAC address
+ if (i < argc)
+ {
+ parseMacAddr(argv[i++], addr_ostr);
+ portInit.net_label = new LinkLayerAddress(addr_ostr);
+ } else
+ {
+ printf("Local hardware MAC address required");
+ return -1;
+ }
+
+ if( wireless )
+ {
+ if (i < argc)
+ {
+ parseMacAddr(argv[i++], addr_ostr);
+ portInit.virtual_label = new LinkLayerAddress(addr_ostr);
+ } else
+ {
+ printf("Wireless operation requires local virtual MAC address");
+ return -1;
+ }
+ }
+
+ if (!wireless)
+ {
+ // Create HWTimestamper object
+ portInit.timestamper = new WindowsEtherTimestamper();
+ } else
+ {
+ portInit.timestamper = new WindowsWirelessTimestamper();
+ (static_cast<WindowsWirelessTimestamper *> (portInit.timestamper))->setAdapter(new IntelWirelessAdapter());
+ }
- // Create Low level network interface object
- uint8_t local_addr_ostr[ETHER_ADDR_OCTETS];
- parseMacAddr( argv[i], local_addr_ostr );
- LinkLayerAddress local_addr(local_addr_ostr);
- portInit.net_label = &local_addr;
- // Create HWTimestamper object
- portInit.timestamper = new WindowsTimestamper();
// Create Clock object
- portInit.clock = new IEEE1588Clock( false, false, priority1, timerq_factory, ipc, portInit.lock_factory ); // Do not force slave
- // Create Port Object linked to clock and low level
- portInit.phy_delay = &ether_phy_delay;
- EtherPort *port = new EtherPort( &portInit );
- port->setLinkSpeed(findLinkSpeed(&local_addr));
- if ( !port->init_port() ) {
- printf( "Failed to initialize port\n" );
- return -1;
+ portInit.clock = new IEEE1588Clock(false, false, priority1, timerq_factory, ipc, portInit.lock_factory); // Do not force slave
+
+ if (!wireless)
+ {
+ // Create Port Object linked to clock and low level
+ portInit.phy_delay = &ether_phy_delay;
+ EtherPort *eport = new EtherPort(&portInit);
+ eport->setLinkSpeed( findLinkSpeed( static_cast <LinkLayerAddress *> ( portInit.net_label )));
+ port = eport;
+ if (!eport->init_port()) {
+ printf("Failed to initialize port\n");
+ return -1;
+ }
+ port->processEvent(POWERUP);
+ } else
+ {
+ if (i < argc)
+ {
+ parseMacAddr(argv[i++], addr_ostr);
+ LinkLayerAddress peer_addr(addr_ostr);
+ port = new WirelessPort(&portInit, peer_addr);
+ (static_cast <WirelessTimestamper *> (portInit.timestamper))->setPort( static_cast<WirelessPort *> ( port ));
+ if (!port->init_port()) {
+ printf("Failed to initialize port\n");
+ return -1;
+ }
+ port->processEvent(POWERUP);
+ } else
+ {
+ printf("Wireless operation requires remote MAC address");
+ return -1;
+ }
}
- port->processEvent( POWERUP );
// Wait for Ctrl-C
if( !SetConsoleCtrlHandler( ctrl_handler, true )) {
diff --git a/daemons/gptp/windows/daemon_cl/intel_wireless.cpp b/daemons/gptp/windows/daemon_cl/intel_wireless.cpp
new file mode 100644
index 00000000..a6f8f99f
--- /dev/null
+++ b/daemons/gptp/windows/daemon_cl/intel_wireless.cpp
@@ -0,0 +1,424 @@
+/******************************************************************************
+
+Copyright (c) 2009-2015, 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 <intel_wireless.hpp>
+#include <windows_hal.hpp>
+#include <work_queue.hpp>
+#include <memory>
+#include <map>
+
+#define INTEL_EVENT_OFFSET 0x1141
+#define GP2_ROLLOVER 4294967296ULL
+
+GetAdapterList_t GetAdapterList;
+WifiCmdTimingMeasurementRequest_t WifiCmdTimingMeasurementRequest;
+WifiCmdTimingPtmWa_t WifiCmdTimingPtmWa;
+RegisterIntelCallback_t RegisterIntelCallback;
+DeregisterIntelCallback_t DeregisterIntelCallback;
+
+struct TimestamperContext
+{
+ WindowsWorkQueue work_queue;
+ WindowsWirelessTimestamper *timestamper;
+ ~TimestamperContext()
+ {
+ work_queue.stop();
+ }
+};
+
+typedef std::map< LinkLayerAddress, TimestamperContext > TimestamperContextMap;
+
+class LockedTimestamperContextMap
+{
+public:
+ LockedTimestamperContextMap()
+ {
+ InitializeSRWLock(&lock);
+ }
+ TimestamperContextMap map;
+ SRWLOCK lock;
+};
+
+LockedTimestamperContextMap timestamperContextMap;
+HANDLE IntelTimestamperThread;
+bool IntelTimestamperThreadStop = false;
+
+void IntelWirelessTimestamperEventHandler( INTEL_EVENT iEvent, void *pContext )
+{
+ WindowsWirelessTimestamper *timestamper;
+ IntelWirelessAdapter *adapter;
+ LockedTimestamperContextMap *timestamperContextMap =
+ (LockedTimestamperContextMap *)pContext;
+ WirelessTimestamperCallbackArg *arg =
+ new WirelessTimestamperCallbackArg();
+ int vendor_extension_copy_length;
+ bool error = false;
+ bool submit = false; // If true submit the event for later processing
+
+ // We share driver callback with other events, subtract the offset for
+ // timing measurement related events and check this is time sync event
+ iEvent.eType =
+ (WIRELESS_EVENT_TYPE) (iEvent.eType - INTEL_EVENT_OFFSET);
+ switch( iEvent.eType )
+ {
+ default:
+ return;
+ case TIMINGMSMT_CONFIRM_EVENT:
+ case TIMINGMSMT_EVENT:
+ case TIMINGMSMT_CORRELATEDTIME_EVENT:
+ break;
+ }
+
+ LinkLayerAddress event_source( iEvent.BtMacAddress );
+ arg->iEvent_type = (WIRELESS_EVENT_TYPE) iEvent.eType;
+ AcquireSRWLockShared( &timestamperContextMap->lock );
+ if( timestamperContextMap->map.find( event_source )
+ != timestamperContextMap->map.cend())
+ {
+ arg->timestamper =
+ timestamperContextMap->map[event_source].timestamper;
+ } else
+ {
+ goto bail;
+ }
+
+ timestamper = dynamic_cast <WindowsWirelessTimestamper *>
+ (arg->timestamper);
+ if( timestamper == NULL )
+ {
+ GPTP_LOG_ERROR( "Unexpected timestamper type encountered" );
+ goto bail;
+ }
+ adapter = dynamic_cast <IntelWirelessAdapter *>
+ (timestamper->getAdapter( ));
+ if( adapter == NULL )
+ {
+ GPTP_LOG_ERROR( "Unexpected adapter type encountered" );
+ goto bail;
+ }
+
+ // The driver implementation makes no guarantee of the lifetime of the
+ // iEvent object we make a copy and delete the copy when processing is
+ // complete
+ switch( arg->iEvent_type )
+ {
+ case TIMINGMSMT_CONFIRM_EVENT:
+ arg->event_data.confirm =
+ *(TIMINGMSMT_CONFIRM_EVENT_DATA *)iEvent.data;
+ arg->event_data.confirm.T1 =
+ adapter->calc_rollover( arg->event_data.confirm.T1 );
+ arg->event_data.confirm.T4 =
+ adapter->calc_rollover( arg->event_data.confirm.T4 );
+ submit = true;
+
+ break;
+
+ case TIMINGMSMT_EVENT:
+ arg->event_data.indication.indication =
+ *(TIMINGMSMT_EVENT_DATA *)iEvent.data;
+ arg->event_data.indication.indication.T2 =
+ adapter->calc_rollover
+ ( arg->event_data.indication.indication.T2/100 );
+ arg->event_data.indication.indication.T3 =
+ adapter->calc_rollover
+ ( arg->event_data.indication.indication.T3/100 );
+ // Calculate copy length, at most followup message
+ // (See S8021AS indication)
+ vendor_extension_copy_length = arg->event_data.
+ indication.indication.WiFiVSpecHdr.Length - 1;
+ vendor_extension_copy_length -= vendor_extension_copy_length -
+ sizeof(arg->event_data.indication.followup) > 0 ?
+ vendor_extension_copy_length -
+ sizeof(arg->event_data.indication.followup) : 0;
+ // Copy the rest of the vendor specific field
+ memcpy( arg->event_data.indication.followup,
+ ((BYTE *)iEvent.data) +
+ sizeof( arg->event_data.indication.indication ),
+ vendor_extension_copy_length );
+ submit = true;
+ break;
+ case TIMINGMSMT_CORRELATEDTIME_EVENT:
+ AcquireSRWLockExclusive(&adapter->ct_lock);
+ if (adapter->ct_miss > 0)
+ {
+ --adapter->ct_miss;
+ } else
+ {
+ arg->event_data.ptm_wa =
+ *(WIRELESS_CORRELATEDTIME *)iEvent.data;
+ arg->event_data.ptm_wa.LocalClk =
+ adapter->calc_rollover
+ (arg->event_data.ptm_wa.LocalClk);
+ adapter->ct_done = true;
+ // No need to schedule this, it returns immediately
+ WirelessTimestamperCallback(arg);
+ WakeAllConditionVariable(&adapter->ct_cond);
+ }
+ ReleaseSRWLockExclusive(&adapter->ct_lock);
+
+ break;
+ }
+
+ if (submit &&
+ !timestamperContextMap->map[event_source].work_queue.submit
+ ( WirelessTimestamperCallback, arg ))
+ GPTP_LOG_ERROR("Failed to submit WiFi event");
+bail:
+ ReleaseSRWLockShared(&timestamperContextMap->lock);
+}
+
+DWORD WINAPI IntelWirelessLoop(LPVOID arg)
+{
+ // Register for callback
+ INTEL_CALLBACK tempCallback;
+ tempCallback.fnIntelCallback = IntelWirelessTimestamperEventHandler;
+ tempCallback.pContext = arg;
+
+ if (RegisterIntelCallback(&tempCallback) != S_OK) {
+ GPTP_LOG_ERROR( "Failed to register WiFi callback" );
+ return 0;
+ }
+
+ while (!IntelTimestamperThreadStop)
+ {
+ SleepEx(320, true);
+ }
+
+ DeregisterIntelCallback(tempCallback.fnIntelCallback);
+
+ return 0;
+}
+
+bool IntelWirelessAdapter::initialize(void)
+{
+ HMODULE MurocApiDLL = LoadLibrary("MurocApi.dll");
+
+ GetAdapterList = (GetAdapterList_t)
+ GetProcAddress(MurocApiDLL, "GetAdapterList");
+ if( GetAdapterList == NULL )
+ return false;
+
+ RegisterIntelCallback = (RegisterIntelCallback_t)
+ GetProcAddress(MurocApiDLL, "RegisterIntelCallback");
+ if( RegisterIntelCallback == NULL )
+ return false;
+
+ DeregisterIntelCallback = (DeregisterIntelCallback_t)
+ GetProcAddress(MurocApiDLL, "DeregisterIntelCallback");
+ if( DeregisterIntelCallback == NULL )
+ return false;
+
+ WifiCmdTimingPtmWa = (WifiCmdTimingPtmWa_t)
+ GetProcAddress(MurocApiDLL, "WifiCmdTimingPtmWa");
+ if( WifiCmdTimingPtmWa == NULL )
+ return false;
+
+ WifiCmdTimingMeasurementRequest = (WifiCmdTimingMeasurementRequest_t)
+ GetProcAddress(MurocApiDLL, "WifiCmdTimingMeasurementRequest");
+ if (WifiCmdTimingMeasurementRequest == NULL)
+ return false;
+
+ // Initialize crosstimestamp condition
+ InitializeConditionVariable(&ct_cond);
+ InitializeSRWLock(&ct_lock);
+ ct_miss = 0;
+
+ // Spawn thread
+ IntelTimestamperThread = CreateThread
+ ( NULL, 0, IntelWirelessLoop, &timestamperContextMap, 0, NULL);
+ return true;
+}
+
+void IntelWirelessAdapter::shutdown(void) {
+ // Signal thread exit
+ IntelTimestamperThreadStop = true;
+ // Join thread
+ WaitForSingleObject(IntelTimestamperThread, INFINITE);
+}
+
+bool IntelWirelessAdapter::refreshCrossTimestamp(void) {
+ INTEL_WIFI_HEADER header;
+ WIRELESS_CORRELATEDTIME ptm_wa;
+ DWORD wait_return = TRUE;
+ DWORD start = 0;
+
+ AcquireSRWLockExclusive(&ct_lock);
+ ct_done = false;
+ header.dwSize = sizeof(ptm_wa);
+ header.dwStructVersion = INTEL_STRUCT_VER_LATEST;
+ HRESULT hres = WifiCmdTimingPtmWa(hAdapter, &header, &ptm_wa);
+ if (hres != S_OK)
+ return false;
+
+ while (!ct_done && wait_return == TRUE) {
+ DWORD now = GetTickCount();
+ start = start == 0 ? now : start;
+ DWORD wait = now - start < CORRELATEDTIME_TRANSACTION_TIMEOUT ?
+ CORRELATEDTIME_TRANSACTION_TIMEOUT -
+ (now - start) : 0;
+ wait_return = SleepConditionVariableSRW
+ ( &ct_cond, &ct_lock, wait, 0 );
+ }
+ ct_miss += wait_return != TRUE ? 1 : 0;
+ ReleaseSRWLockExclusive(&ct_lock);
+
+ return wait_return == TRUE ? true : false;
+}
+
+bool IntelWirelessAdapter::initiateTimingRequest
+( TIMINGMSMT_REQUEST *tm_request )
+{
+ INTEL_WIFI_HEADER header;
+ HRESULT err;
+
+ memset(&header, 0, sizeof(header));
+ // Proset wants an equivalent, but slightly different struct definition
+ header.dwSize = sizeof(*tm_request) - sizeof(PTP_SPEC) + 1;
+ header.dwStructVersion = INTEL_STRUCT_VER_LATEST;
+ if(( err = WifiCmdTimingMeasurementRequest
+ (hAdapter, &header, tm_request)) != S_OK )
+ return false;
+
+ return true;
+}
+
+// Find Intel adapter given MAC address and return adapter ID
+//
+// @adapter(out): Adapter identifier used for all driver interaction
+// @mac_addr: HW address of the adapter
+// @return: *false* if adapter is not found or driver communication failure
+// occurs, otherwise *true*
+//
+bool IntelWirelessAdapter::attachAdapter(uint8_t *mac_addr)
+{
+ PINTEL_ADAPTER_LIST adapter_list;
+ int i;
+
+ if (GetAdapterList(&adapter_list) != S_OK)
+ return false;
+
+ GPTP_LOG_VERBOSE("Driver query returned %d adapters\n",
+ adapter_list->count);
+ for (i = 0; i < adapter_list->count; ++i) {
+ if( memcmp(adapter_list->adapter[i].btMACAddress,
+ mac_addr, ETHER_ADDR_OCTETS) == 0 )
+ break;
+ }
+
+ if (i == adapter_list->count)
+ {
+ GPTP_LOG_ERROR("Driver failed to find the requested adapter");
+ return false;
+ }
+ hAdapter = adapter_list->adapter[i].hAdapter;
+
+ return true;
+}
+
+// Register timestamper with Intel wireless subsystem.
+//
+// @timestamper: timestamper object that should receive events
+// @source: MAC address of local interface
+// @return: *false* if the MAC address has already been registered, *true* if
+//
+bool IntelWirelessAdapter::registerTimestamper
+(WindowsWirelessTimestamper *timestamper)
+{
+ bool ret = false;
+
+ AcquireSRWLockExclusive(&timestamperContextMap.lock);
+ // Do not "re-add" the same timestamper
+ if( timestamperContextMap.map.find
+ ( *timestamper->getPort()->getLocalAddr() )
+ == timestamperContextMap.map.cend())
+ {
+ // Initialize per timestamper context and add
+ timestamperContextMap.map
+ [*timestamper->getPort()->getLocalAddr()].
+ work_queue.init(0);
+ timestamperContextMap.map
+ [*timestamper->getPort()->getLocalAddr()].
+ timestamper = timestamper;
+ ret = true;
+ }
+ ReleaseSRWLockExclusive(&timestamperContextMap.lock);
+
+ return ret;
+}
+
+bool IntelWirelessAdapter::deregisterTimestamper
+( WindowsWirelessTimestamper *timestamper )
+{
+ bool ret;
+
+ TimestamperContextMap::iterator iter;
+ AcquireSRWLockExclusive(&timestamperContextMap.lock);
+ // Find timestamper
+ iter = timestamperContextMap.map.find
+ ( *timestamper->getPort()->getLocalAddr( ));
+ if( iter != timestamperContextMap.map.end( ))
+ {
+ // Shutdown work queue
+ iter->second.work_queue.stop();
+ // Remove timestamper from list
+ timestamperContextMap.map.erase(iter);
+ ret = true;
+ }
+ ReleaseSRWLockExclusive(&timestamperContextMap.lock);
+
+ return ret;
+}
+
+uint64_t IntelWirelessAdapter::calc_rollover( uint64_t gp2 )
+{
+ gp2 = gp2 & 0xFFFFFFFF;
+ uint64_t l_gp2_ext;
+
+ if (gp2_last == ULLONG_MAX)
+ {
+ gp2_last = gp2;
+
+ return gp2;
+ }
+
+ if (gp2 < GP2_ROLLOVER/4 && gp2_last > (GP2_ROLLOVER*3)/4)
+ ++gp2_ext;
+
+ l_gp2_ext = gp2_ext;
+ if( gp2_last < GP2_ROLLOVER / 4 && gp2 >(GP2_ROLLOVER * 3) / 4 )
+ --l_gp2_ext;
+ else
+ gp2_last = gp2;
+
+ return gp2 + ( l_gp2_ext * GP2_ROLLOVER );
+}
diff --git a/daemons/gptp/windows/daemon_cl/intel_wireless.hpp b/daemons/gptp/windows/daemon_cl/intel_wireless.hpp
new file mode 100644
index 00000000..bad97d71
--- /dev/null
+++ b/daemons/gptp/windows/daemon_cl/intel_wireless.hpp
@@ -0,0 +1,187 @@
+/******************************************************************************
+
+Copyright (c) 2009-2015, 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 INTEL_WIRELESS_HPP
+#define INTEL_WIRELESS_HPP
+
+#include <windows_hal.hpp>
+#include <Windows.h>
+#include <stdint.h>
+
+#define INTEL_MAC_ADDR_LENGTH 6
+#define INTEL_MAX_ADAPTERS 20
+#define CORRELATEDTIME_TRANSACTION_TIMEOUT 110/*ms*/
+
+enum _WIRELESS_EVENT_TYPE;
+
+typedef struct INTEL_EVENT
+{
+ BYTE BtMacAddress[INTEL_MAC_ADDR_LENGTH + 1];
+ ///< Source of event (MAC address)
+ _WIRELESS_EVENT_TYPE eType; ///< Event type
+ HRESULT hErrCode; ///< Error code
+ DWORD dwSize;
+ BYTE* data;
+} INTEL_EVENT, *PINTEL_EVENT;
+
+typedef void(*INTEL_EVENT_CALLBACK) ( INTEL_EVENT iEvent, void *pContext );
+
+typedef struct INTEL_CALLBACK
+{
+ INTEL_EVENT_CALLBACK fnIntelCallback;
+ void *pContext;
+
+} INTEL_CALLBACK, *PINTEL_CALLBACK;
+
+/// Adapter handle
+typedef DWORD HADAPTER;
+
+//intel Header structure
+typedef struct _INTEL_WIFI_HEADER
+{
+ DWORD dwStructVersion;
+ //Structure version for which this header is created
+ DWORD dwSize;
+ //size of the structure for which this header is created
+ DWORD dwFlags; //For future use
+ DWORD dwReserved; //For future use
+} INTEL_WIFI_HEADER, *PINTEL_WIFI_HEADER;
+
+typedef enum INTEL_ADAPTER_TYPE
+{
+ eStone, // Stone Peak - without BT Support
+ eStoneBT, // Stone Peak - with BT Support
+ eSnowfield // Snowfield Peak
+} INTEL_ADAPTER_TYPE;
+
+#define INTEL_ADAPTER_NAME_SIZE 64
+#define INTEL_ADAPTER_DESCRIPTION_SIZE 64
+#define INTEL_ADAPTER_CLSGUID_SIZE 64
+#define INTEL_REGPATH_SIZE 512
+
+#define INTEL_STRUCT_VER_LATEST 156
+
+typedef enum INTEL_ADAPTER_PROTOCOL
+{
+ eUnknownProtocol, ///< Unknown adapter.
+ e802_11, ///< WiFi
+} INTEL_ADAPTER_PROTOCOL;
+
+typedef struct INTEL_ADAPTER_LIST_ENTRY
+{
+ HADAPTER hAdapter;
+ ///< Adapter handle
+ UCHAR btMACAddress[INTEL_MAC_ADDR_LENGTH];
+ ///< Adapter MAC address
+ CHAR szAdapterName[INTEL_ADAPTER_NAME_SIZE];
+ ///< Adapter OS CLSGUID
+ CHAR szAdapterDescription[INTEL_ADAPTER_DESCRIPTION_SIZE];
+ ///< Display name
+ CHAR szAdapterClsguid[INTEL_ADAPTER_CLSGUID_SIZE];
+ ///< Muroc CLSGUID
+ CHAR szRegistryPath[INTEL_REGPATH_SIZE];
+ ///< Adapter registry root
+ CHAR szPnPId[INTEL_REGPATH_SIZE]; ///< Plug-and-Play ID
+ BOOL bEnabled; ///< enabled in driver
+ INTEL_ADAPTER_TYPE eAdapterType; ///< Adapter type
+ INTEL_ADAPTER_PROTOCOL eAdapterProtocol; ///< Adapter type
+} INTEL_ADAPTER_LIST_ENTRY, *PINTEL_ADAPTER_LIST_ENTRY;
+
+typedef struct INTEL_ADAPTER_LIST
+{
+ int count; ///< Number of entries
+ INTEL_ADAPTER_LIST_ENTRY adapter[INTEL_MAX_ADAPTERS];
+ ///< Array of adapter entries
+} INTEL_ADAPTER_LIST, *PINTEL_ADAPTER_LIST;
+
+
+typedef HRESULT ( APIENTRY *GetAdapterList_t )
+ ( PINTEL_ADAPTER_LIST* ppAdapterList );
+typedef HRESULT ( APIENTRY *WifiCmdTimingMeasurementRequest_t )
+ ( HADAPTER, PINTEL_WIFI_HEADER, void * );
+typedef HRESULT ( APIENTRY *WifiCmdTimingPtmWa_t )
+ (HADAPTER, PINTEL_WIFI_HEADER, void *);
+typedef HRESULT ( APIENTRY *RegisterIntelCallback_t ) ( PINTEL_CALLBACK );
+typedef HRESULT ( APIENTRY *DeregisterIntelCallback_t )
+ ( INTEL_EVENT_CALLBACK );
+
+extern GetAdapterList_t GetAdapterList;
+extern WifiCmdTimingMeasurementRequest_t WifiCmdTimingMeasurementRequest;
+extern WifiCmdTimingPtmWa_t WifiCmdTimingPtmWa;
+extern RegisterIntelCallback_t RegisterIntelCallback;
+extern DeregisterIntelCallback_t DeregisterIntelCallback;
+
+typedef struct _TIMINGMSMT_REQUEST *tm_request_t;
+typedef struct WirelessTimestamperCallbackArg
+*WirelessTimestamperCallbackArg_t;
+typedef void( *WirelessTimestamperCallback_t )
+( WirelessTimestamperCallbackArg_t arg );
+
+class IntelWirelessAdapter : public WindowsWirelessAdapter
+{
+private:
+ HADAPTER hAdapter;
+
+ // Get correlated time operation may timeout
+ // Use condition wait to manage this
+ SRWLOCK ct_lock;
+ CONDITION_VARIABLE ct_cond;
+ bool ct_done;
+ int ct_miss;
+
+ uint64_t gp2_last;
+ unsigned gp2_ext;
+
+public:
+ bool initialize( void );
+ void shutdown( void );
+ bool refreshCrossTimestamp();
+ bool initiateTimingRequest( TIMINGMSMT_REQUEST *tm_request );
+ bool attachAdapter( uint8_t *mac_addr );
+ bool registerTimestamper( WindowsWirelessTimestamper *timestamper );
+ bool deregisterTimestamper( WindowsWirelessTimestamper *timestamper );
+ IntelWirelessAdapter();
+
+ uint64_t calc_rollover( uint64_t gp2 );
+
+ friend void IntelWirelessTimestamperEventHandler
+ ( INTEL_EVENT iEvent, void *pContext );
+};
+
+inline IntelWirelessAdapter::IntelWirelessAdapter()
+{
+ gp2_ext = 0;
+ gp2_last = ULLONG_MAX;
+}
+
+#endif
diff --git a/daemons/gptp/windows/daemon_cl/tsc.hpp b/daemons/gptp/windows/daemon_cl/tsc.hpp
index ed22752c..425205d3 100644
--- a/daemons/gptp/windows/daemon_cl/tsc.hpp
+++ b/daemons/gptp/windows/daemon_cl/tsc.hpp
@@ -95,13 +95,14 @@ inline uint32_t FindFrequencyByModel(uint8_t model_query) {
/**
* @brief Gets the TSC frequnecy
- * @param millis time in miliseconds
+ * @param builtin whether device is connected to the Intel bus (not PCIE)
* @return TSC frequency, or 0 on error
*/
-inline uint64_t getTSCFrequency( unsigned millis ) {
+inline uint64_t getTSCFrequency( bool builtin ) {
int max_cpuid_level;
int tmp[4];
BOOL is_windows_10;
+ LARGE_INTEGER freq;
// Find the max cpuid level, and if possible find clock info
__cpuid(tmp, 0);
@@ -124,9 +125,11 @@ inline uint64_t getTSCFrequency( unsigned millis ) {
// clock will be returned, *else* use QPC for everything else
//
// EAX (tmp[0]) must be >= 1, See Intel SDM 17.15.4 "Invariant Time-keeping"
- if (is_windows_10 &&
+ if (!is_windows_10 &&
max_cpuid_level >= CLOCK_INFO_CPUID_LEAF &&
- tmp[0] >= 1) {
+ tmp[0] >= 1 &&
+ builtin )
+ {
SYSTEM_INFO info;
GetSystemInfo(&info);
@@ -135,8 +138,6 @@ inline uint64_t getTSCFrequency( unsigned millis ) {
return FindFrequencyByModel(info.wProcessorRevision >> 8);
}
- LARGE_INTEGER freq;
-
if (QueryPerformanceFrequency(&freq))
return freq.QuadPart;
diff --git a/daemons/gptp/windows/daemon_cl/windows_hal.cpp b/daemons/gptp/windows/daemon_cl/windows_hal.cpp
index a05d473c..3d034e39 100644
--- a/daemons/gptp/windows/daemon_cl/windows_hal.cpp
+++ b/daemons/gptp/windows/daemon_cl/windows_hal.cpp
@@ -67,8 +67,184 @@ VOID CALLBACK WindowsTimerQueueHandler( PVOID arg_in, BOOLEAN ignore ) {
ReleaseSRWLockExclusive( &arg->queue->retiredTimersLock );
}
+inline uint64_t scale64(uint64_t i, uint32_t m, uint32_t n)
+{
+ uint64_t tmp, res, rem;
+
+ rem = i % n;
+ i /= n;
+
+ res = i * m;
+ tmp = rem * m;
+
+ tmp /= n;
+
+ return res + tmp;
+}
+
+void WirelessTimestamperCallback( LPVOID arg )
+{
+ WirelessTimestamperCallbackArg *larg =
+ (WirelessTimestamperCallbackArg *)arg;
+ WindowsWirelessTimestamper *timestamper =
+ dynamic_cast<WindowsWirelessTimestamper *> (larg->timestamper);
+ WirelessDialog tmp1, tmp2;
+ LinkLayerAddress *peer_addr = NULL;
+
+ if (timestamper == NULL)
+ {
+ GPTP_LOG_ERROR( "Wrong timestamper type: %p",
+ larg->timestamper );
+ return;
+ }
+
+ switch( larg->iEvent_type )
+ {
+ default:
+ case TIMINGMSMT_CONFIRM_EVENT:
+ tmp1.action_devclk = larg->event_data.confirm.T1;
+ tmp1.ack_devclk = larg->event_data.confirm.T4;
+ tmp1.dialog_token = (BYTE)larg->event_data.confirm.DialogToken;
+ GPTP_LOG_VERBOSE
+ ( "Got confirm, %hhu(%llu,%llu)", tmp1.dialog_token,
+ tmp1.action_devclk, tmp1.ack_devclk );
+ peer_addr = new LinkLayerAddress
+ ( larg->event_data.confirm.PeerMACAddress );
+ larg->timestamper->
+ timingMeasurementConfirmCB( *peer_addr, &tmp1 );
+
+ break;
+
+ case TIMINGMSMT_EVENT:
+ tmp1/*prev*/.action_devclk = larg->event_data.indication.
+ indication.T1;
+ tmp1/*prev*/.ack_devclk = larg->event_data.indication.
+ indication.T4;
+ tmp1/*prev*/.dialog_token = (BYTE)larg->event_data.indication.
+ indication.FollowUpDialogToken;
+ tmp2/*curr*/.action_devclk = larg->event_data.indication.
+ indication.T2;
+ tmp2/*curr*/.ack_devclk = larg->event_data.indication.
+ indication.T3;
+ tmp2/*curr*/.dialog_token = (BYTE)larg->event_data.indication.
+ indication.DialogToken;
+ GPTP_LOG_VERBOSE
+ ("Got indication, %hhu(%llu,%llu) %hhu(%llu,%llu)",
+ tmp1.dialog_token, tmp1.action_devclk,
+ tmp1.ack_devclk, tmp2.dialog_token,
+ tmp2.action_devclk, tmp2.ack_devclk);
+ peer_addr = new LinkLayerAddress(larg->event_data.indication.
+ indication.PeerMACAddress);
+
+ larg->timestamper->timeMeasurementIndicationCB
+ ( *peer_addr, &tmp2, &tmp1,
+ larg->event_data.indication.
+ indication.PtpSpec.fwup_data,
+ larg->event_data.indication.
+ indication.WiFiVSpecHdr.Length - (sizeof(PTP_SPEC) -
+ 1));
+
+ break;
+
+ case TIMINGMSMT_CORRELATEDTIME_EVENT:
+ timestamper->system_counter =
+ scale64( larg->event_data.ptm_wa.TSC, NS_PER_SECOND,
+ (uint32_t)timestamper->tsc_hz.QuadPart );
+ timestamper->system_time.set64(timestamper->system_counter);
+ // Scale from TM timescale to nanoseconds
+ larg->event_data.ptm_wa.LocalClk *= 10;
+ timestamper->device_time.set64
+ (larg->event_data.ptm_wa.LocalClk*10);
+
+ break;
+ }
+
+ delete peer_addr;
+}
+
+net_result WindowsWirelessTimestamper::_requestTimingMeasurement
+(TIMINGMSMT_REQUEST *timingmsmt_req)
+{
+ net_result ret = net_succeed;
+
+ if (!adapter->initiateTimingRequest(timingmsmt_req)) {
+ GPTP_LOG_ERROR("Failed to send timing measurement request\n");
+ ret = net_fatal;
+ }
+
+ return ret;
+}
+
+bool WindowsWirelessTimestamper::HWTimestamper_gettime
+( Timestamp *system_time,
+ Timestamp * device_time,
+ uint32_t * local_clock,
+ uint32_t * nominal_clock_rate ) const
+{
+ bool refreshed = adapter->refreshCrossTimestamp();
+ if (refreshed)
+ {
+ // We have a fresh cross-timestamp just use it
+ *system_time = this->system_time;
+ *device_time = this->device_time;
+ } else
+ {
+ // We weren't able to get a fresh timestamp,
+ // extrapolate from the last
+ LARGE_INTEGER tsc_now;
+ QueryPerformanceCounter(&tsc_now);
+ unsigned device_delta = (unsigned)
+ (((long double) (tsc_now.QuadPart - system_counter)) /
+ (((long double)tsc_hz.QuadPart) / 1000000000));
+ device_delta = (unsigned)(device_delta*getPort()->
+ getLocalSystemFreqOffset());
+ system_time->set64((uint64_t)
+ (((long double)tsc_now.QuadPart) /
+ ((long double)tsc_hz.QuadPart /
+ 1000000000)));
+ device_time->set64(device_delta);
+ *device_time = *device_time + this->device_time;
+ }
+
+ return true;
+}
+
+bool WindowsWirelessTimestamper::HWTimestamper_init
+(InterfaceLabel *iface_label, OSNetworkInterface *iface)
+{
+ uint8_t mac_addr_local[ETHER_ADDR_OCTETS];
+
+ if (!initialized) {
+ if (!adapter->initialize()) return false;
+ if (getPort()->getLocalAddr() == NULL)
+ return false;
+
+ getPort()->getLocalAddr()->toOctetArray(mac_addr_local);
+ if (!adapter->attachAdapter(mac_addr_local)) {
+ return false;
+ }
+
+ tsc_hz.QuadPart = getTSCFrequency(false);
+ if (tsc_hz.QuadPart == 0) {
+ return false;
+ }
+
+ if (!adapter->registerTimestamper(this))
+ return false;
+ }
+
+ initialized = true;
+ return true;
+}
+
+WindowsWirelessTimestamper::~WindowsWirelessTimestamper() {
+ if (adapter->deregisterTimestamper(this))
+ adapter->shutdown();
+ else
+ GPTP_LOG_INFO("Failed to shutdown time sync on adapter");
+}
-bool WindowsTimestamper::HWTimestamper_init( InterfaceLabel *iface_label, OSNetworkInterface *net_iface ) {
+bool WindowsEtherTimestamper::HWTimestamper_init( InterfaceLabel *iface_label, OSNetworkInterface *net_iface ) {
char network_card_id[64];
LinkLayerAddress *addr = dynamic_cast<LinkLayerAddress *>(iface_label);
if( addr == NULL ) return false;
@@ -112,7 +288,7 @@ bool WindowsTimestamper::HWTimestamper_init( InterfaceLabel *iface_label, OSNetw
NULL, OPEN_EXISTING, 0, NULL );
if( miniport == INVALID_HANDLE_VALUE ) return false;
- tsc_hz.QuadPart = getTSCFrequency( 1000 );
+ tsc_hz.QuadPart = getTSCFrequency( true );
if( tsc_hz.QuadPart == 0 ) {
return false;
}
diff --git a/daemons/gptp/windows/daemon_cl/windows_hal.hpp b/daemons/gptp/windows/daemon_cl/windows_hal.hpp
index f5192910..5f1a6f61 100644
--- a/daemons/gptp/windows/daemon_cl/windows_hal.hpp
+++ b/daemons/gptp/windows/daemon_cl/windows_hal.hpp
@@ -36,7 +36,6 @@
/**@file*/
-#include <minwindef.h>
#include <IPCListener.hpp>
#include "avbts_osnet.hpp"
#include "avbts_oslock.hpp"
@@ -47,6 +46,7 @@
#include "packet.hpp"
#include "ieee1588.hpp"
#include "ether_tstamper.hpp"
+#include "wireless_tstamper.hpp"
#include "iphlpapi.h"
#include "windows_ipc.hpp"
#include "tsc.hpp"
@@ -590,6 +590,114 @@ public:
}
};
+void WirelessTimestamperCallback(LPVOID arg);
+
+class WindowsWirelessAdapter;
+
+/**
+* @brief Windows Wireless (802.11) HWTimestamper implementation
+*/
+class WindowsWirelessTimestamper : public WirelessTimestamper
+{
+private:
+ WindowsWirelessAdapter *adapter;
+
+ uint64_t system_counter;
+ Timestamp system_time;
+ Timestamp device_time;
+ LARGE_INTEGER tsc_hz;
+ bool initialized;
+
+public:
+ WindowsWirelessTimestamper()
+ {
+ initialized = false;
+ }
+
+ net_result _requestTimingMeasurement
+ ( TIMINGMSMT_REQUEST *timingmsmt_req );
+
+ bool HWTimestamper_gettime
+ ( Timestamp *system_time, Timestamp * device_time,
+ uint32_t * local_clock, uint32_t * nominal_clock_rate ) const;
+
+ virtual bool HWTimestamper_init
+ ( InterfaceLabel *iface_label, OSNetworkInterface *iface );
+
+ /**
+ * @brief attach adapter to timestamper
+ * @param adapter [in] adapter to attach
+ */
+ void setAdapter( WindowsWirelessAdapter *adapter )
+ {
+ this->adapter = adapter;
+ }
+
+ /**
+ * @brief get attached adapter
+ * @return attached adapter
+ */
+ WindowsWirelessAdapter *getAdapter(void)
+ {
+ return adapter;
+ }
+
+ ~WindowsWirelessTimestamper();
+
+ friend void WirelessTimestamperCallback( LPVOID arg );
+};
+
+class WindowsWirelessAdapter
+{
+public:
+ /**
+ * @brief initiate wireless TM request (completion is asynchronous)
+ * @param tm_request [in] pointer to TM request object
+ * @return true on success
+ */
+ virtual bool initiateTimingRequest(TIMINGMSMT_REQUEST *tm_request) = 0;
+
+ /**
+ * @brief attempt to refresh cross timestamp (extrapolate on failure)
+ * @return true on success
+ */
+ virtual bool refreshCrossTimestamp() = 0;
+
+ /**
+ * @brief register timestamper with adapter
+ * @param timestamper [in] timestamper object
+ * @return true on success
+ */
+ virtual bool registerTimestamper
+ ( WindowsWirelessTimestamper *timestamper ) = 0;
+
+ /**
+ * @brief deregister timestamper
+ * @param timestamper [in] timestamper object
+ * @return true on success
+ */
+ virtual bool deregisterTimestamper
+ ( WindowsWirelessTimestamper *timestamper ) = 0;
+
+ /**
+ * @brief initialize adapter object
+ * @return true on success
+ */
+ virtual bool initialize() = 0;
+
+ /**
+ * @brief shutdown adapter
+ */
+ virtual void shutdown() = 0;
+
+ /**
+ * @brief attach adapter to MAC address
+ * @param mac_addr [in] MAC address to attach to
+ * @return true on success
+ */
+ virtual bool attachAdapter( uint8_t *mac_addr ) = 0;
+};
+
#define I217_DESC "I217-LM"
#define I219_DESC "I219-V"
@@ -616,9 +724,9 @@ static DeviceClockRateMapping DeviceClockRateMap[] =
};
/**
- * @brief Windows HWTimestamper implementation
+ * @brief Windows Ethernet HWTimestamper implementation
*/
-class WindowsTimestamper : public EtherTimestamper {
+class WindowsEtherTimestamper : public EtherTimestamper {
private:
// No idea whether the underlying implementation is thread safe
HANDLE miniport;
diff --git a/daemons/gptp/windows/daemon_cl/work_queue.cpp b/daemons/gptp/windows/daemon_cl/work_queue.cpp
new file mode 100644
index 00000000..461d6923
--- /dev/null
+++ b/daemons/gptp/windows/daemon_cl/work_queue.cpp
@@ -0,0 +1,106 @@
+/******************************************************************************
+
+Copyright (c) 2009-2015, 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 <work_queue.hpp>
+#include <stdio.h>
+
+
+struct WWQueueThreadState {
+ bool running;
+ bool stop;
+ WWQueueCallback task;
+ LPVOID arg;
+};
+
+DWORD WINAPI WindowsWorkQueueLoop(LPVOID arg) {
+ WWQueueThreadState *state = (WWQueueThreadState *)arg;
+ state->running = true;
+ while (!state->stop) {
+ if (state->task != NULL) {
+ state->task(state->arg);
+ delete state->arg;
+ state->task = NULL;
+ }
+ Sleep(1);
+ }
+ state->running = false;
+
+ return 0;
+}
+
+bool WindowsWorkQueue::init(int number_threads)
+{
+ if (number_threads == 0) number_threads = DEFAULT_THREAD_COUNT;
+ state = new WWQueueThreadState[number_threads];
+ for (int i = 0; i < number_threads; ++i) {
+ state[i].running = false;
+ state[i].stop = false;
+ state[i].task = NULL;
+ }
+ workers = new HANDLE[number_threads];
+ for (int i = 0; i < number_threads; ++i) {
+ workers[i] = CreateThread(NULL, 0, WindowsWorkQueueLoop, state + i, 0, NULL);
+ if (workers[i] == INVALID_HANDLE_VALUE)
+ return false;
+ while (!state[i].running)
+ Sleep(1);
+ }
+ this->number_threads = number_threads;
+ return true;
+}
+
+bool WindowsWorkQueue::submit(WWQueueCallback cb, LPVOID arg)
+{
+ int i;
+
+ for (i = 0; i < number_threads; ++i) {
+ if (state[i].task == NULL) {
+ state[i].arg = arg;
+ state[i].task = cb;
+ break;
+ }
+ }
+ if (i == number_threads)
+ return false;
+
+ return true;
+}
+
+void WindowsWorkQueue::stop()
+{
+ for (int i = 0; i < number_threads; ++i) {
+ state[i].stop = true;
+ while (state[i].running)
+ Sleep(1);
+ }
+}
diff --git a/daemons/gptp/windows/daemon_cl/work_queue.hpp b/daemons/gptp/windows/daemon_cl/work_queue.hpp
new file mode 100644
index 00000000..4ac750c5
--- /dev/null
+++ b/daemons/gptp/windows/daemon_cl/work_queue.hpp
@@ -0,0 +1,74 @@
+/******************************************************************************
+
+Copyright (c) 2009-2015, 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 WORK_QUEUE_HPP
+#define WORK_QUEUE_HPP
+
+#include <WTypesbase.h>
+
+#define DEFAULT_THREAD_COUNT (5)
+
+struct WWQueueThreadState;
+
+typedef void(*WWQueueCallback)(LPVOID arg);
+
+class WindowsWorkQueue
+{
+private:
+ HANDLE *workers;
+ WWQueueThreadState *state;
+ int number_threads;
+
+public:
+ /**
+ * @brief initialize work queue
+ * @param number_threads [in] number of threads (0 = default)
+ * @return true on success
+ */
+ bool init( int number_threads );
+
+ /**
+ * @brief submit job to work queue
+ * @param cb [in] function to call
+ * @param arg [in] parameter provided to callback
+ * @return true on success
+ */
+ bool submit( WWQueueCallback cb, LPVOID arg );
+
+ /**
+ * @brief stop work queue
+ */
+ void stop();
+};
+
+#endif/*WORK_QUEUE_HPP*/
diff --git a/daemons/gptp/windows/named_pipe_test/named_pipe_test.cpp b/daemons/gptp/windows/named_pipe_test/named_pipe_test.cpp
index 713a2b4a..9a34a4ef 100644
--- a/daemons/gptp/windows/named_pipe_test/named_pipe_test.cpp
+++ b/daemons/gptp/windows/named_pipe_test/named_pipe_test.cpp
@@ -60,7 +60,7 @@ int _tmain(int argc, _TCHAR* argv[])
strcpy_s( pipename, 64, PIPE_PREFIX );
strcat_s( pipename, 64-strlen(pipename), P802_1AS_PIPENAME );
HANDLE pipe;
- uint64_t tsc_frequency = getTSCFrequency( 1000 );
+ uint64_t tsc_frequency = getTSCFrequency( true );
// Wait for Ctrl-C
if( !SetConsoleCtrlHandler( ctrl_handler, true )) {