summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Fornal <jakub.fornal@intel.com>2018-01-25 11:32:41 +0100
committerGitHub <noreply@github.com>2018-01-25 11:32:41 +0100
commit2a901df04ae7a741581dbd28b7670340d2e32d44 (patch)
treee610c9ac022f6686c059d2a5515d7b3c7e55edf4
parentd6ff05c155ba2c3bde3e2a923ebd0335acf3f604 (diff)
parentd1ee5ba8a03a578c0b1aace651bbd84e0fc88d27 (diff)
downloadOpen-AVB-2a901df04ae7a741581dbd28b7670340d2e32d44.tar.gz
Merge pull request #21 from AVnu/open-avb-next
Open avb next
-rw-r--r--.gitmodules2
-rw-r--r--.travis.yml11
-rw-r--r--CMakeLists.txt37
-rw-r--r--README.rst11
-rw-r--r--appveyor.yml24
-rw-r--r--daemons/gptp/CMakeLists.txt12
-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.cpp12
-rw-r--r--daemons/gptp/common/common_port.hpp97
-rw-r--r--daemons/gptp/common/ether_port.cpp96
-rw-r--r--daemons/gptp/common/ether_port.hpp38
-rw-r--r--daemons/gptp/common/gptp_cfg.cpp2
-rw-r--r--daemons/gptp/common/ieee1588.hpp12
-rw-r--r--daemons/gptp/common/ptp_message.cpp624
-rw-r--r--daemons/gptp/common/ptptypes.hpp1
-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/linux/src/linux_hal_common.cpp29
-rw-r--r--daemons/gptp/linux/src/linux_hal_common.hpp2
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic.cpp21
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic_adj.cpp6
-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
-rw-r--r--daemons/maap/linux/src/maap_log_linux.c17
-rw-r--r--daemons/maap/windows/src/maap_main.c29
-rw-r--r--daemons/mrpd/mvrp.c3
-rw-r--r--daemons/shaper/src/shaper_log_linux.c16
-rw-r--r--examples/mrp_client/mrpdhelper.c4
-rw-r--r--kmod/igb/igb_main.c22
-rw-r--r--lib/avtp_pipeline/README.md64
-rw-r--r--lib/avtp_pipeline/avtp_avdecc.mk9
-rw-r--r--lib/avtp_pipeline/avtp_pipeline.mk7
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint_server.c4
-rw-r--r--lib/avtp_pipeline/include/openavb_audio_pub.h16
-rwxr-xr-xlib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c45
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c14
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c28
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c28
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c2
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c20
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/example_listener.ini135
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/example_talker.ini181
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal.c39
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c25
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c39
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h18
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_tasks.h10
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c2
-rw-r--r--lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c16
-rw-r--r--lib/avtp_pipeline/qmgr/openavb_qmgr.c16
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener_endpoint.c18
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c18
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker_endpoint.c8
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c3
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl_pub.h6
-rwxr-xr-xrun_avtp_pipeline.sh24
-rwxr-xr-xrun_daemons.sh34
-rwxr-xr-xstop_avtp_pipeline.sh19
-rwxr-xr-xstop_daemons.sh7
m---------thirdparty/cpputest0
73 files changed, 3451 insertions, 675 deletions
diff --git a/.gitmodules b/.gitmodules
index 3254bb8a..6494de60 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,6 @@
[submodule "thirdparty/cpputest"]
path = thirdparty/cpputest
- url = ../../cpputest/cpputest.git
+ url = ../../AVnu/cpputest.git
[submodule "avdecc-lib"]
path = avdecc-lib
url = ../../AVnu/avdecc-lib
diff --git a/.travis.yml b/.travis.yml
index 8eb91588..ecc2b9d6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,12 +21,19 @@ before_install:
- sudo update-alternatives --set c++ /usr/bin/g++
compiler:
- gcc
-env: BUILD_KERNEL=4.4.0-75-generic
+env:
+ - BUILD_KERNEL=4.4.0-75-generic
install:
- sudo apt-get update -qq
- - sudo apt-get install -y libpcap-dev libpci-dev libsndfile1-dev libjack-dev linux-headers-4.4.0-75-generic cmake
+ - sudo apt-get install -y libpcap-dev libpci-dev libsndfile1-dev libjack-dev linux-headers-4.4.0-75-generic
- sudo apt-get install -y libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libasound2-dev
- sudo cp /usr/src/linux-headers-4.4.0-75/include/uapi/linux/ethtool.h /usr/include/linux
- sudo cp /usr/src/linux-headers-4.4.0-75/include/uapi/linux/ptp_clock.h /usr/include/linux
+ - CMAKE_URL="https://cmake.org/files/v3.9/cmake-3.9.4-Linux-x86_64.tar.gz"
+ - mkdir -p ${TRAVIS_BUILD_DIR}/deps/cmake
+ - travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${TRAVIS_BUILD_DIR}/deps/cmake
+ - export PATH=${TRAVIS_BUILD_DIR}/deps/cmake/bin:${PATH}
+
+
script: ./travis.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 555d9db3..eccb62eb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,8 +2,43 @@ cmake_minimum_required (VERSION 2.8)
project (open-avb)
enable_testing()
-set(C++11 ON CACHE BOOL "Compile with C++11 support" FORCE)
+include(CheckCXXCompilerFlag)
+CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
+CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
+if(COMPILER_SUPPORTS_CXX11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+elseif(COMPILER_SUPPORTS_CXX0X)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+else()
+ message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
+endif()
+
add_subdirectory("thirdparty/cpputest")
add_subdirectory("daemons/common/tests")
add_subdirectory("daemons/mrpd")
add_subdirectory("daemons/maap")
+add_subdirectory("daemons/gptp")
+
+message("
+-------------------------------------------------------
+OpenAvnu Build information
+
+Current compiler options:
+ CC: ${CMAKE_C_COMPILER}
+ CXX: ${CMAKE_CXX_COMPILER}
+ OpenAvnu CFLAGS: ${CMAKE_C_FLAGS}
+ OpenAvnu CXXFLAGS: ${CMAKE_CXX_FLAGS}
+ OpenAvnu LDFLAGS: ${CMAKE_LD_FLAGS}
+
+Features configured in OpenAvnu root CMakeFile.txt:
+ Memory Leak Detection: ${MEMORY_LEAK_DETECTION}
+ Compiling Extensions: ${EXTENSIONS}
+ Support Long Long: ${LONGLONG}
+ Use OpenAvnu flags: ${CMAKE_FLAGS}
+
+ Using Standard C library: ${STD_C}
+ Using Standard C++ library: ${STD_CPP}
+ Using C++11 library: ${C++11}
+
+-------------------------------------------------------
+")
diff --git a/README.rst b/README.rst
index e9635b1b..f1c29cd4 100644
--- a/README.rst
+++ b/README.rst
@@ -98,6 +98,16 @@ Starting from the OpenAvnu dir, one would go::
to build in OpenAvnu/tmp
+Apple Vendor PTP Profile
+========================
+
+Support for the Apple Vendor PTP Profile can be found on the
+feature-aptp-experimental branch of the OpenAvnu repository.
+
+These changes allow interaction with Apple proprietary PTP clocks. This
+implementation has been tested with the Apple AirPlay SDK on a Raspberry Pi 3
+running within a group of devices playing the same music stream.
+
RELATED OPEN SOURCE PROJECTS
============================
@@ -119,4 +129,3 @@ XMOS
XMOS is a semiconductor company providing a reference design for AVB/TSN
endpoints in pro audio and automotive. XMOS endpoint source code is open source
and available on Github - https://github.com/xcore/sw_avb
-
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 00000000..be1355c1
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,24 @@
+version: '1.0.{build}'
+
+clone_folder: c:\oavb
+clone_depth: 20
+
+environment:
+ # Config for mrp Windows build
+ WPCAP_DIR: c:\oavb\WpdPack
+
+install:
+ - git submodule update --init --recursive
+ # download WinPcap developer module and unzip it
+ - ps: Start-FileDownload 'https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip'
+ - ps: 7z x WpdPack_4_1_2.zip
+
+before_build:
+ # cmake
+ - choco upgrade cmake
+ - set path=C:\Program Files\CMake\bin;%path%
+
+build_script:
+ - cd c:\oavb
+ - cmake CMakeLists.txt -G "Visual Studio 12 2013"
+ - cmake --build . --config Release
diff --git a/daemons/gptp/CMakeLists.txt b/daemons/gptp/CMakeLists.txt
index 4935e665..fb7d19b3 100644
--- a/daemons/gptp/CMakeLists.txt
+++ b/daemons/gptp/CMakeLists.txt
@@ -6,8 +6,16 @@ file(GLOB GPTP_COMMON "./common/*.cpp" "./common/*.c")
if(UNIX)
include_directories( include "./linux/src" )
- file(GLOB GPTP_OS "./linux/src/*.cpp")
- target_link_libraries(gptp pthread)
+ file(GLOB GPTP_OS
+ "./linux/src/daemon_cl.cpp"
+ "./linux/src/linux_ipc.cpp"
+ "./linux/src/platform.cpp"
+ "./linux/src/linux_hal_persist_file.cpp"
+ "./linux/src/linux_hal_generic.cpp"
+ "./linux/src/linux_hal_generic_adj.cpp"
+ "./linux/src/linux_hal_common.cpp")
+ add_executable (gptp ${GPTP_COMMON} ${GPTP_OS})
+ target_link_libraries(gptp pthread rt)
elseif(WIN32)
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
link_directories($ENV{WPCAP_DIR}/Lib/x64)
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 4d7977d4..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;
@@ -550,7 +552,7 @@ bool CommonPort::processEvent( Event e )
// If port has been configured as master or slave, run media
// specific configuration. If it hasn't been configured
- // start announce message time
+ // start listening for announce messages
if( clock->getPriority1() == 255 ||
port_state == PTP_SLAVE )
{
@@ -562,7 +564,8 @@ bool CommonPort::processEvent( Event e )
}
else
{
- startAnnounce();
+ clock->addEventTimerLocked(this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
+ (uint64_t) ( ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * pow(2.0, getAnnounceInterval()) * 1000000000.0 ));
}
// Do any media specific initialization
@@ -731,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 024531cc..56db3d22 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,13 +169,13 @@ bool EtherPort::_init_port( void )
void EtherPort::startPDelay()
{
if(!pdelayHalted()) {
- if (automotive_profile) {
- if (log_min_mean_pdelay_req_interval != PTPMessageSignalling::sigMsgInterval_NoSend) {
- long long unsigned int waitTime;
- waitTime = ((long long) (pow((double)2, log_min_mean_pdelay_req_interval) * 1000000000.0));
- waitTime = waitTime > EVENT_TIMER_GRANULARITY ? waitTime : EVENT_TIMER_GRANULARITY;
+ if( getAutomotiveProfile( ))
+ {
+ if( getPDelayInterval() !=
+ PTPMessageSignalling::sigMsgInterval_NoSend)
+ {
pdelay_started = true;
- startPDelayIntervalTimer(waitTime);
+ startPDelayIntervalTimer(EVENT_TIMER_GRANULARITY);
}
}
else {
@@ -194,7 +194,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 +326,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 +357,8 @@ bool EtherPort::_processEvent( Event e )
port_ready_condition->wait();
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
setStationState(STATION_STATE_ETHERNET_READY);
if (getTestMode())
{
@@ -387,7 +390,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 +399,8 @@ bool EtherPort::_processEvent( Event e )
case LINKUP:
haltPdelay(false);
startPDelay();
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
GPTP_LOG_EXCEPTION("LINKUP");
}
else {
@@ -408,10 +412,16 @@ bool EtherPort::_processEvent( Event e )
} else if( getPortState() == PTP_MASTER ) {
becomeMaster( true );
} else {
- startAnnounce();
+ 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);
@@ -426,7 +436,7 @@ bool EtherPort::_processEvent( Event e )
resetInitSyncInterval();
setAnnounceInterval( 0 );
- log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
+ resetInitPDelayInterval();
if (!isGM) {
// Send an initial signaling message
@@ -467,7 +477,8 @@ bool EtherPort::_processEvent( Event e )
break;
case LINKDOWN:
stopPDelay();
- if (automotive_profile) {
+ if( getAutomotiveProfile( ))
+ {
GPTP_LOG_EXCEPTION("LINK DOWN");
}
else {
@@ -483,7 +494,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;
@@ -567,8 +578,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--;
@@ -617,7 +628,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;
@@ -636,7 +648,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);
}
@@ -667,8 +680,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;
}
@@ -677,10 +691,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;
}
@@ -719,7 +733,8 @@ void EtherPort::becomeMaster( bool annc ) {
stopSyncReceiptTimer();
if( annc ) {
- if (!automotive_profile) {
+ if( !getAutomotiveProfile( ))
+ {
startAnnounce();
}
}
@@ -737,7 +752,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*
@@ -831,7 +847,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) {
@@ -848,7 +865,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/gptp_cfg.cpp b/daemons/gptp/common/gptp_cfg.cpp
index fae8e6c0..8b9db0dc 100644
--- a/daemons/gptp/common/gptp_cfg.cpp
+++ b/daemons/gptp/common/gptp_cfg.cpp
@@ -253,7 +253,7 @@ void GptpIniParser::print_phy_delay( void )
tx = i->second.get_tx_delay();
rx = i->second.get_rx_delay();
- snprintf( phy_delay_desc, PHY_DELAY_DESC_LEN+1,
+ PLAT_snprintf( phy_delay_desc, PHY_DELAY_DESC_LEN+1,
"TX: %hu | RX: %hu", tx, rx );
speed_name = findNameBySpeed( speed );
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..e8835570 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,205 @@ 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);
- goto done;
- }
-
- if (sync->getTimestamp()._version != port->getTimestampVersion())
+ if (!port->getLinkDelay(&delay))
{
- GPTP_LOG_ERROR("Received Follow Up but timestamp version indicates Sync is out of date");
+ GPTP_LOG_ERROR( "Received Follow up but "
+ "there is no valid link delay" );
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 +1243,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 +1252,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 +1266,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 +1291,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 +1304,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 +1328,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 +1386,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 +1418,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 +1437,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 +1555,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 +1606,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 +1696,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 +1755,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 +1781,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 +1941,7 @@ bool PTPMessageSignalling::sendPort
return true;
}
-void PTPMessageSignalling::processMessage( EtherPort *port )
+void PTPMessageSignalling::processMessage( CommonPort *port )
{
long long unsigned int waitTime;
@@ -1834,7 +1954,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/ptptypes.hpp b/daemons/gptp/common/ptptypes.hpp
index 03cd57be..f73c8f92 100644
--- a/daemons/gptp/common/ptptypes.hpp
+++ b/daemons/gptp/common/ptptypes.hpp
@@ -43,6 +43,7 @@ typedef double FrequencyRatio; /*!< Frequency Ratio */
typedef long double FrequencyRatio; /*!< Frequency Ratio */
#endif
+#define ETHER_HDR_LEN (14)
#define ETHER_ADDR_OCTETS 6 /*!< Number of octets in a link layer address*/
#define IP_ADDR_OCTETS 4 /*!< Number of octets in a ip address*/
#define PTP_ETHERTYPE 0x88F7 /*!< PTP ethertype */
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/linux/src/linux_hal_common.cpp b/daemons/gptp/linux/src/linux_hal_common.cpp
index cd880ba9..ab312c95 100644
--- a/daemons/gptp/linux/src/linux_hal_common.cpp
+++ b/daemons/gptp/linux/src/linux_hal_common.cpp
@@ -428,14 +428,19 @@ void *LinuxTimerQueueHandler( void *arg ) {
timeout.tv_sec = 0; timeout.tv_nsec = 100000000; /* 100 ms */
sigemptyset( &waitfor );
-
+ GPTP_LOG_DEBUG("Signal thread started");
while( !timerq->stop ) {
siginfo_t info;
LinuxTimerQueueMap_t::iterator iter;
sigaddset( &waitfor, SIGUSR1 );
if( sigtimedwait( &waitfor, &info, &timeout ) == -1 ) {
- if( errno == EAGAIN ) continue;
- else break;
+ if( errno == EAGAIN ) {
+ continue;
+ }
+ else {
+ GPTP_LOG_ERROR("Signal thread sigtimedwait error: %d", errno);
+ break;
+ }
}
if( timerq->lock->lock() != oslock_ok ) {
break;
@@ -456,7 +461,7 @@ void *LinuxTimerQueueHandler( void *arg ) {
break;
}
}
-
+ GPTP_LOG_DEBUG("Signal thread exit");
return NULL;
}
@@ -474,6 +479,9 @@ OSTimerQueue *LinuxTimerQueueFactory::createOSTimerQueue
return NULL;
}
+ ret->key = 0;
+ ret->stop = false;
+ ret->lock = clock->timerQLock();
if( pthread_create
( &(ret->_private->signal_thread),
NULL, LinuxTimerQueueHandler, ret ) != 0 ) {
@@ -481,10 +489,6 @@ OSTimerQueue *LinuxTimerQueueFactory::createOSTimerQueue
return NULL;
}
- ret->stop = false;
- ret->key = 0;
- ret->lock = clock->timerQLock();
-
return ret;
}
@@ -528,9 +532,7 @@ bool LinuxTimerQueue::addEvent
its.it_value.tv_nsec = (micros % 1000000) * 1000;
err = timer_settime( outer_arg->timer_handle, 0, &its, NULL );
if( err < 0 ) {
- fprintf
- ( stderr, "Failed to arm timer: %s\n",
- strerror( errno ));
+ GPTP_LOG_ERROR("Failed to arm timer: %s", strerror(errno));
return false;
}
}
@@ -704,9 +706,10 @@ bool LinuxLock::initialize( OSLockType type ) {
lock_c = pthread_mutex_init(&_private->mutex,&_private->mta);
if(lock_c != 0) {
GPTP_LOG_ERROR("Mutex initialization failed - %s",strerror(errno));
- return oslock_fail;
+ return false;
}
- return oslock_ok;
+
+ return true;
}
LinuxLock::~LinuxLock() {
diff --git a/daemons/gptp/linux/src/linux_hal_common.hpp b/daemons/gptp/linux/src/linux_hal_common.hpp
index 28332f01..9eb3ddc9 100644
--- a/daemons/gptp/linux/src/linux_hal_common.hpp
+++ b/daemons/gptp/linux/src/linux_hal_common.hpp
@@ -306,7 +306,7 @@ public:
OSLock * createLock( OSLockType type ) const
{
LinuxLock *lock = new LinuxLock();
- if (lock->initialize(type) != oslock_ok) {
+ if (!lock->initialize(type)) {
delete lock;
lock = NULL;
}
diff --git a/daemons/gptp/linux/src/linux_hal_generic.cpp b/daemons/gptp/linux/src/linux_hal_generic.cpp
index 5364fa6a..9eeba46f 100644
--- a/daemons/gptp/linux/src/linux_hal_generic.cpp
+++ b/daemons/gptp/linux/src/linux_hal_generic.cpp
@@ -30,9 +30,10 @@
POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
-
#include <linux_hal_generic.hpp>
#include <linux_hal_generic_tsprivate.hpp>
+#include <platform.hpp>
+#include <avbts_message.hpp>
#include <sys/select.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
@@ -285,6 +286,10 @@ int LinuxTimestamperGeneric::HWTimestamper_txtimestamp
struct cmsghdr *cmsg;
struct sockaddr_ll remote;
struct iovec sgentry;
+ PTPMessageId reflectedMessageId;
+ uint8_t reflected_bytes[ETHER_HDR_LEN + PTP_COMMON_HDR_LENGTH];
+ uint8_t *gptpCommonHeader;
+ uint16_t sequenceId;
struct {
struct cmsghdr cm;
char control[256];
@@ -296,8 +301,10 @@ int LinuxTimestamperGeneric::HWTimestamper_txtimestamp
msg.msg_iov = &sgentry;
msg.msg_iovlen = 1;
- sgentry.iov_base = NULL;
- sgentry.iov_len = 0;
+ sgentry.iov_base = reflected_bytes;
+ sgentry.iov_len = sizeof(reflected_bytes);
+
+ gptpCommonHeader = reflected_bytes + ETHER_HDR_LEN;
memset( &remote, 0, sizeof(remote));
msg.msg_name = (caddr_t) &remote;
@@ -316,6 +323,14 @@ int LinuxTimestamperGeneric::HWTimestamper_txtimestamp
goto done;
}
}
+ sequenceId = PLAT_ntohs(*((uint16_t*)(PTP_COMMON_HDR_SEQUENCE_ID(gptpCommonHeader))));
+ reflectedMessageId.setSequenceId(sequenceId);
+ reflectedMessageId.setMessageType((MessageType)(*PTP_COMMON_HDR_TRANSSPEC_MSGTYPE(gptpCommonHeader) & 0xF));
+ if (messageId != reflectedMessageId) {
+ GPTP_LOG_WARNING("Timestamp discarded due to wrong message id");
+ ret = GPTP_EC_EAGAIN;
+ goto done;
+ }
// Retrieve the timestamp
cmsg = CMSG_FIRSTHDR(&msg);
diff --git a/daemons/gptp/linux/src/linux_hal_generic_adj.cpp b/daemons/gptp/linux/src/linux_hal_generic_adj.cpp
index f722ac4a..7f1d59c8 100644
--- a/daemons/gptp/linux/src/linux_hal_generic_adj.cpp
+++ b/daemons/gptp/linux/src/linux_hal_generic_adj.cpp
@@ -31,10 +31,8 @@
******************************************************************************/
-#include <linux/timex.h>
- // avoid indirect inclusion of time.h since this will clash with linux/timex.h
-#define _TIME_H 1
-#define _STRUCT_TIMEVAL 1
+#include <sys/timex.h>
+#define ADJ_SETOFFSET 0x0100 // Missing from older header files
#include <linux_hal_generic.hpp>
#include <syscall.h>
#include <math.h>
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 )) {
diff --git a/daemons/maap/linux/src/maap_log_linux.c b/daemons/maap/linux/src/maap_log_linux.c
index 2d6f02b3..35dcfcbc 100644
--- a/daemons/maap/linux/src/maap_log_linux.c
+++ b/daemons/maap/linux/src/maap_log_linux.c
@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
#include <string.h>
#include <inttypes.h>
+#include <limits.h>
#include "platform.h"
#include "maap_log_queue.h"
@@ -74,7 +75,14 @@ extern void *loggingThreadFn(void *pv);
THREAD_TYPE(loggingThread);
THREAD_DEFINITON(loggingThread);
-#define THREAD_STACK_SIZE 65536
+#if !defined(PTHREAD_STACK_MIN)
+#error "PTHREAD_STACK_MIN variable not defined"
+#elif (PTHREAD_STACK_MIN > 65536)
+#define THREAD_STACK_SIZE PTHREAD_STACK_MIN
+#else
+#define THREAD_STACK_SIZE 65536
+#endif
+
#define loggingThread_THREAD_STK_SIZE THREAD_STACK_SIZE
static MUTEX_HANDLE_ALT(gLogMutex);
@@ -211,13 +219,16 @@ void maapLogInit(void)
loggingThreadRunning = TRUE;
THREAD_CREATE(loggingThread, loggingThread, NULL, loggingThreadFn, NULL);
THREAD_CHECK_ERROR(loggingThread, "Thread / task creation failed", errResult);
- if (errResult); // Already reported
+ if (errResult) {
+ loggingThreadRunning = FALSE;
+ MAAP_LOG_ERROR("Could not log data: loggingThread create failure");
+ }
}
}
void maapLogExit()
{
- if (MAAP_LOG_FROM_THREAD) {
+ if (MAAP_LOG_FROM_THREAD && loggingThreadRunning ) {
loggingThreadRunning = FALSE;
THREAD_JOIN(loggingThread, NULL);
}
diff --git a/daemons/maap/windows/src/maap_main.c b/daemons/maap/windows/src/maap_main.c
index 6c817d71..dce75312 100644
--- a/daemons/maap/windows/src/maap_main.c
+++ b/daemons/maap/windows/src/maap_main.c
@@ -1,3 +1,32 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+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.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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 LISTED 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.
+*************************************************************************************/
+
/*
* TODO: This code still needs to be added!
*/
+
+int main(int argc, char *argv[])
+{
+}
diff --git a/daemons/mrpd/mvrp.c b/daemons/mrpd/mvrp.c
index b36e3ace..fa14ac37 100644
--- a/daemons/mrpd/mvrp.c
+++ b/daemons/mrpd/mvrp.c
@@ -331,7 +331,8 @@ int mvrp_event(int event, struct mvrp_attribute *rattrib)
}
attrib = mvrp_conditional_reclaim(attrib);
#if LOG_MVRP
- mvrp_print_debug_info(event, attrib);
+ if (attrib != NULL)
+ mvrp_print_debug_info(event, attrib);
#endif
break;
default:
diff --git a/daemons/shaper/src/shaper_log_linux.c b/daemons/shaper/src/shaper_log_linux.c
index d68a79a2..38017c38 100644
--- a/daemons/shaper/src/shaper_log_linux.c
+++ b/daemons/shaper/src/shaper_log_linux.c
@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
#include <string.h>
#include <inttypes.h>
+#include <limits.h>
#include "platform.h"
#include "shaper_log_queue.h"
@@ -74,7 +75,13 @@ extern void *loggingThreadFn(void *pv);
THREAD_TYPE(loggingThread);
THREAD_DEFINITON(loggingThread);
-#define THREAD_STACK_SIZE 65536
+#if !defined(PTHREAD_STACK_MIN)
+#error "PTHREAD_STACK_MIN variable not defined"
+#elif (PTHREAD_STACK_MIN > 65536)
+#define THREAD_STACK_SIZE PTHREAD_STACK_MIN
+#else
+#define THREAD_STACK_SIZE 65536
+#endif
#define loggingThread_THREAD_STK_SIZE THREAD_STACK_SIZE
static MUTEX_HANDLE_ALT(gLogMutex);
@@ -217,13 +224,16 @@ void shaperLogInit(void)
loggingThreadRunning = TRUE;
THREAD_CREATE(loggingThread, loggingThread, NULL, loggingThreadFn, NULL);
THREAD_CHECK_ERROR(loggingThread, "Thread / task creation failed", errResult);
- if (errResult) {} // Already reported
+ if (errResult) {
+ loggingThreadRunning = FALSE;
+ SHAPER_LOG_ERROR("Could not log data: loggingThread create failure");
+ }
}
}
void shaperLogExit()
{
- if (SHAPER_LOG_FROM_THREAD) {
+ if (SHAPER_LOG_FROM_THREAD && loggingThreadRunning) {
loggingThreadRunning = FALSE;
THREAD_JOIN(loggingThread, NULL);
}
diff --git a/examples/mrp_client/mrpdhelper.c b/examples/mrp_client/mrpdhelper.c
index ddd5a958..a4026903 100644
--- a/examples/mrp_client/mrpdhelper.c
+++ b/examples/mrp_client/mrpdhelper.c
@@ -301,8 +301,8 @@ static int parse_mmrp(char *sz, size_t len, struct mrpdhelper_notify *n)
if (parse_state(&sz[5], n) < 0)
return -1;
- n->attrib = mrpdhelper_attribtype_mvrp;
- if (sscanf(&sz[8], "M=%" SCNx64, &n->u.m.mac) != 1)
+ n->attrib = mrpdhelper_attribtype_mmrp;
+ if (sscanf(&sz[4], "M=%" SCNx64, &n->u.m.mac) != 1)
return -1;
return parse_registrar(sz, n, NULL);
}
diff --git a/kmod/igb/igb_main.c b/kmod/igb/igb_main.c
index 3310680d..c8a4a7e3 100644
--- a/kmod/igb/igb_main.c
+++ b/kmod/igb/igb_main.c
@@ -181,8 +181,14 @@ static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
static void igb_process_mdd_event(struct igb_adapter *);
#ifdef IFLA_VF_MAX
static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac);
+#ifdef IFLA_VF_VLAN_INFO_MAX
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+ int vf, u16 vlan, u8 qos, __be16 vlan_proto);
+#else
static int igb_ndo_set_vf_vlan(struct net_device *netdev,
int vf, u16 vlan, u8 qos);
+#endif /*IFLA_VF_VLAN_INFO_MAX*/
+
#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
static int igb_ndo_set_vf_spoofchk(struct net_device *netdev, int vf,
bool setting);
@@ -6648,9 +6654,15 @@ static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
else
E1000_WRITE_REG(hw, E1000_VMVIR(vf), 0);
}
+#ifdef IFLA_VF_VLAN_INFO_MAX
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+ int vf, u16 vlan, u8 qos, __be16 vlan_proto)
+#else
static int igb_ndo_set_vf_vlan(struct net_device *netdev,
- int vf, u16 vlan, u8 qos)
+ int vf, u16 vlan, u8 qos)
+#endif /*IFLA_VF_VLAN_INFO_MAX*/
+
{
int err = 0;
struct igb_adapter *adapter = netdev_priv(netdev);
@@ -6659,6 +6671,7 @@ static int igb_ndo_set_vf_vlan(struct net_device *netdev,
if ((vf >= adapter->vfs_allocated_count) || (vlan > VLAN_VID_MASK-1)
|| (qos > 7))
return -EINVAL;
+
if (vlan || qos) {
err = igb_vlvf_set(adapter, vlan, !!vlan, vf);
if (err)
@@ -6816,9 +6829,16 @@ static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
igb_clear_vf_vfta(adapter, vf);
#ifdef IFLA_VF_MAX
if (adapter->vf_data[vf].pf_vlan)
+#ifdef IFLA_VF_VLAN_INFO_MAX
+ igb_ndo_set_vf_vlan(adapter->netdev, vf,
+ adapter->vf_data[vf].pf_vlan,
+ adapter->vf_data[vf].pf_qos, 0);
+#else
+
igb_ndo_set_vf_vlan(adapter->netdev, vf,
adapter->vf_data[vf].pf_vlan,
adapter->vf_data[vf].pf_qos);
+#endif
else
igb_clear_vf_vfta(adapter, vf);
#endif
diff --git a/lib/avtp_pipeline/README.md b/lib/avtp_pipeline/README.md
index 23e6e525..62aba7da 100644
--- a/lib/avtp_pipeline/README.md
+++ b/lib/avtp_pipeline/README.md
@@ -6,8 +6,7 @@
- gPTP
- MAAP
- MSRP
- - igb direct for packet TX.
- - igb credit based shaper
+ - credit based shaper
- build system
- Credit-based shaper algorithm is not used for individual streams.
- Testing of various mappings and benchmarking has been performed. Look at the end of this file for benchmark results.
@@ -25,15 +24,17 @@
- $ sudo apt-get install linux-headers-generic
- linux-headers (same version as the kernel you're building for)
-- Install dependencies for AVTP pipeline
+- Additional install dependencies for AVTP pipeline
- $ sudo apt-get install libglib2.0-dev
+ - $ sudo apt-get install libasound2-dev
+
+- Additional install dependencies for AVTP pipeline if GStreamer support is enabled
- $ sudo apt-get install libgstreamer0.10-dev
- $ sudo apt-get install libgstreamer-plugins-base0.10-dev
- - $ sudo apt-get install libasound2-dev
### Building everything
- Building from the repo root
-- $ ARCH=I210 make all
+- $ make all
### Building just AVTP pipeline
- $ make avtp_pipeline
@@ -51,7 +52,8 @@ Make sure to call `make avtp_pipeline_clean` before.
### Building just AVTP AVDECC support
- $ make avtp_avdecc
-Binaries will be installed in lib/avtp_pipeline/build_avdecc/bin.
+Binaries will be installed in lib/avtp_pipeline/build/bin.
+Build files will be in the lib/avtp_pipeline/build_avdecc directory, to avoid interfering with the AVTP Pipeline build files.
The openavb_avdecc binary needs to be run in addition to the AVTP pipeline binary (openavb_harness or openavb_host) for AVDECC to be supported.
@@ -61,30 +63,40 @@ The openavb_avdecc binary needs to be run in addition to the AVTP pipeline binar
## Running OpenAvnu daemons
- Helper scripts in the repo root.
- `$ sudo ./run_igb.sh eth1`
- - Load the igb driver. Supply the interface name (ethx) as parameter.
-- `$ sudo ./run_gptp.sh eth1`
- - Start gptp daemon. Supply the interface name (ethx) as parameter.
-- `$ sudo ./run_srp.sh eth1`
- - Start msrp daemon. Supply the interface name (ethx) as parameter.
-- `$ sudo ./run_maap.sh eth1`
- - Start maap daemon. Supply the interface name (ethx) as parameter.
-
-## Running OpenAvnu simple talker example
-- `$ sudo ./run_simple_talker.sh eth1`
- - Run the current OpenAvnu simple talker example. Supply the interface name (ethx) as parameter.
-
-## Running OpenAvnu Echo Talker
-- `$ sudo ./run_echo_talker.sh eth1`
- - Run the AVTP Echo talker test stream. Supply the interface name (ethx) as parameter.
-
-## Running OpenAvnu Echo Listener
-- `$ sudo ./run_echo_listener.sh eth1`
- - Run the AVTP Echo talker test stream. Supply the interface name (ethx) as parameter.
+ - Load the igb driver. Supply the interface name (ethx) as parameter. Only needed if using IGB support for the Intel i210 adapter.
+- `$ sudo ./run_daemons.sh eth1`
+ - Start the gptp, msrp, maap, and shaper daemons. Supply the interface name (ethx) as parameter.
+ - Daemons can also be started individually using the run_gptp.sh, run_srp.sh, run_maap.sh, and run_shaper.sh scripts.
+- `$ sudo ./stop_daemons.sh`
+ - Stop the gptp, msrp, maap, and shaper daemons. Don't use this command while AVTP Pipeline is running.
+
+## Running OpenAvnu AVTP Pipeline example
+- `$ sudo ./run_avtp_pipeline.sh eth1`
+ - Run the current OpenAvnu AVTP Pipeline example. Supply the interface name (ethx) as parameter.
+- `$ sudo ./stop_avtp_pipeline.sh eth1`
+ - Stop the current OpenAvnu AVTP Pipeline example. The script will also attempt to cleanly recover if the AVTP pipeline binaries crashed.
+
+The AVTP Pipeline example is expected to be run simultaneously on two or more different Linux computers,
+with the network interfaces connected using AVB-capable switches.
+(The daemons do not currently support using two different network interfaces on the same computer, so different computers must be used.)
+You can refer to the list of [Avnu Certified Products](http://avnu.org/certified-products/) for switches with AVB/TSN support.
+
+To connect the Talker and Listener with the example implementation, you need to use an AVDECC controller.
+(These are also referred to as 1722.1 or ATDECC controllers. AVDECC was renamed to ATDECC by the IEEE P1722.1 work group in 2017.)
+This will tell the Listener(s) which stream to listen to,
+and allow the Talker and Listener(s) to coordinate when they should start streaming.
+There are several AVDECC controllers available, including one in the OpenAvnu avdecc-lib/controller folder.
+
+The AVTP Pipeline example Talker and Listener should also be compatible with other AVB/TSN products that support 8-channel,
+48K/24-bit [IEC 61883-6](https://webstore.iec.ch/preview/info_iec61883-6%7Bed2.0%7Den.pdf) audio and AVDECC management.
+The list of [Avnu Certified Products](http://avnu.org/certified-products/) includes some of them.
+The example Talker and Listener has also been used successfully to stream audio to and from Apple Macbooks running macOS version 10.12 (Sierra) and later,
+and controlled with the Apple Macbook built-in AVDECC controller (avbutil).
## Benchmark results
-All test done on DELL Optiplex 755 with Intel Core 2 Duo CPU E8400 @ 3.00GHz
+All test done on DELL Optiplex 755 with Intel Core 2 Duo CPU E8400 @ 3.00GHz
| Type | Comment | Class | Streams | CPU Talker | CPU Listener |
|:-------:| -------------|:-----:| -------:| ----------:| ------------:|
diff --git a/lib/avtp_pipeline/avtp_avdecc.mk b/lib/avtp_pipeline/avtp_avdecc.mk
index 9a140c03..1331daf0 100644
--- a/lib/avtp_pipeline/avtp_avdecc.mk
+++ b/lib/avtp_pipeline/avtp_avdecc.mk
@@ -1,10 +1,12 @@
AVB_FEATURE_AVDECC ?= 1
-PLATFORM_TOOLCHAIN ?= x86_i210_linux
+PLATFORM_TOOLCHAIN ?= generic
.PHONY: all clean
all: build_avdecc/Makefile
$(MAKE) -s -C build_avdecc install
+ mkdir -p build/bin
+ cp build_avdecc/bin/* build/bin/.
doc: build_avdecc/Makefile
$(MAKE) -s -C build_avdecc doc
@@ -17,7 +19,8 @@ clean:
build_avdecc/Makefile:
mkdir -p build_avdecc && \
cd build_avdecc && \
- cmake -DCMAKE_TOOLCHAIN_FILE=../platform/Linux/$(PLATFORM_TOOLCHAIN).cmake \
+ cmake -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_TOOLCHAIN_FILE=../platform/Linux/$(PLATFORM_TOOLCHAIN).cmake \
-DAVB_FEATURE_AVDECC=$(AVB_FEATURE_AVDECC) \
- ..
+ ..
diff --git a/lib/avtp_pipeline/avtp_pipeline.mk b/lib/avtp_pipeline/avtp_pipeline.mk
index a3ed80e8..e08ac9b9 100644
--- a/lib/avtp_pipeline/avtp_pipeline.mk
+++ b/lib/avtp_pipeline/avtp_pipeline.mk
@@ -1,7 +1,7 @@
AVB_FEATURE_ENDPOINT ?= 1
IGB_LAUNCHTIME_ENABLED ?= 0
-AVB_FEATURE_GSTREAMER ?= 1
-PLATFORM_TOOLCHAIN ?= x86_i210_linux
+AVB_FEATURE_GSTREAMER ?= 0
+PLATFORM_TOOLCHAIN ?= generic
.PHONY: all clean
@@ -19,7 +19,8 @@ clean:
build/Makefile:
mkdir -p build && \
cd build && \
- cmake -DCMAKE_TOOLCHAIN_FILE=../platform/Linux/$(PLATFORM_TOOLCHAIN).cmake \
+ cmake -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_TOOLCHAIN_FILE=../platform/Linux/$(PLATFORM_TOOLCHAIN).cmake \
-DAVB_FEATURE_ENDPOINT=$(AVB_FEATURE_ENDPOINT) \
-DIGB_LAUNCHTIME_ENABLED=$(IGB_LAUNCHTIME_ENABLED) \
-DAVB_FEATURE_GSTREAMER=$(AVB_FEATURE_GSTREAMER) \
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c b/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
index 22208333..005d30d7 100644
--- a/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
@@ -138,7 +138,7 @@ void openavbEptSrvrNotifyTlkrOfSrpCb(int h,
memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
msgBuf.type = OPENAVB_ENDPOINT_TALKER_CALLBACK;
memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
- strncpy(msgBuf.params.talkerCallback.ifname, ifname, IFNAMSIZ - 1);
+ strncpy(msgBuf.params.talkerCallback.ifname, ifname, sizeof(msgBuf.params.talkerCallback.ifname) - 1);
memcpy(msgBuf.params.talkerCallback.destAddr, destAddr, ETH_ALEN);
msgBuf.params.talkerCallback.lsnrDecl = lsnrDecl;
msgBuf.params.talkerCallback.srClass = srClass;
@@ -174,7 +174,7 @@ void openavbEptSrvrNotifyLstnrOfSrpCb(int h,
memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
msgBuf.type = OPENAVB_ENDPOINT_LISTENER_CALLBACK;
memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
- strncpy(msgBuf.params.listenerCallback.ifname, ifname, IFNAMSIZ - 1);
+ strncpy(msgBuf.params.listenerCallback.ifname, ifname, sizeof(msgBuf.params.listenerCallback.ifname) - 1);
if (destAddr)
memcpy(msgBuf.params.listenerCallback.destAddr, destAddr, ETH_ALEN);
msgBuf.params.listenerCallback.tlkrDecl = tlkrDecl;
diff --git a/lib/avtp_pipeline/include/openavb_audio_pub.h b/lib/avtp_pipeline/include/openavb_audio_pub.h
index 46f3e03e..1e50d45a 100644
--- a/lib/avtp_pipeline/include/openavb_audio_pub.h
+++ b/lib/avtp_pipeline/include/openavb_audio_pub.h
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -51,6 +51,8 @@ typedef enum {
AVB_AUDIO_RATE_16KHZ = 16000,
/// 22050
AVB_AUDIO_RATE_22_05KHZ = 22050,
+ /// 24000
+ AVB_AUDIO_RATE_24KHZ = 24000,
/// 32000
AVB_AUDIO_RATE_32KHZ = 32000,
/// 44100
diff --git a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
index ef3b4a91..f9501750 100755
--- a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
+++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
@@ -82,6 +82,7 @@ typedef enum {
AAF_RATE_96K,
AAF_RATE_176K4,
AAF_RATE_192K,
+ AAF_RATE_24K,
} aaf_nominal_sample_rate_t;
typedef enum {
@@ -141,7 +142,8 @@ typedef struct {
aaf_sample_format_t aaf_format;
U8 aaf_bit_depth;
U32 payloadSize;
- U32 payloadSizeMax;
+ U32 payloadSizeMaxTalker, payloadSizeMaxListener;
+ bool isTalker;
U8 aaf_event_field;
@@ -174,6 +176,9 @@ static void x_calculateSizes(media_q_t *pMediaQ)
case AVB_AUDIO_RATE_16KHZ:
pPvtData->aaf_rate = AAF_RATE_16K;
break;
+ case AVB_AUDIO_RATE_24KHZ:
+ pPvtData->aaf_rate = AAF_RATE_24K;
+ break;
case AVB_AUDIO_RATE_32KHZ:
pPvtData->aaf_rate = AAF_RATE_32K;
break;
@@ -274,7 +279,7 @@ static void x_calculateSizes(media_q_t *pMediaQ)
// AAF packet size calculations
pPubMapInfo->packetFrameSizeBytes = pPubMapInfo->packetSampleSizeBytes * pPubMapInfo->audioChannels;
- pPvtData->payloadSize = pPvtData->payloadSizeMax =
+ pPvtData->payloadSize = pPvtData->payloadSizeMaxTalker = pPvtData->payloadSizeMaxListener =
pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes;
AVB_LOGF_INFO("packet: sampleSz=%d * channels=%d => frameSz=%d * %d => payloadSz=%d",
pPubMapInfo->packetSampleSizeBytes,
@@ -284,8 +289,8 @@ static void x_calculateSizes(media_q_t *pMediaQ)
pPvtData->payloadSize);
if (pPvtData->aaf_format >= AAF_FORMAT_INT_32 && pPvtData->aaf_format <= AAF_FORMAT_INT_16) {
// Determine the largest size we could receive before adjustments.
- pPvtData->payloadSizeMax = 4 * pPubMapInfo->audioChannels * pPubMapInfo->framesPerPacket;
- AVB_LOGF_DEBUG("packet: payloadSizeMax=%d", pPvtData->payloadSizeMax);
+ pPvtData->payloadSizeMaxListener = 4 * pPubMapInfo->audioChannels * pPubMapInfo->framesPerPacket;
+ AVB_LOGF_DEBUG("packet: payloadSizeMaxListener=%d", pPvtData->payloadSizeMaxListener);
}
// MediaQ item size calculations
@@ -384,8 +389,17 @@ U16 openavbMapAVTPAudioMaxDataSizeCB(media_q_t *pMediaQ)
return 0;
}
+ // Return the largest size a frame payload could be.
+ // If we don't yet know if we are a Talker or Listener, the larger Listener max will be returned.
+ U16 payloadSizeMax;
+ if (pPvtData->isTalker) {
+ payloadSizeMax = pPvtData->payloadSizeMaxTalker + TOTAL_HEADER_SIZE;
+ }
+ else {
+ payloadSizeMax = pPvtData->payloadSizeMaxListener + TOTAL_HEADER_SIZE;
+ }
AVB_TRACE_EXIT(AVB_TRACE_MAP);
- return pPvtData->payloadSizeMax + TOTAL_HEADER_SIZE;
+ return payloadSizeMax;
}
AVB_TRACE_EXIT(AVB_TRACE_MAP);
return 0;
@@ -433,6 +447,12 @@ void openavbMapAVTPAudioGenInitCB(media_q_t *pMediaQ)
void openavbMapAVTPAudioTxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (pPvtData) {
+ pPvtData->isTalker = TRUE;
+ }
+ }
AVB_TRACE_EXIT(AVB_TRACE_MAP);
}
@@ -481,16 +501,16 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
return TX_CB_RET_PACKET_NOT_READY;
}
+ U32 tmp32;
+ U8 *pHdrV0 = pData;
+ U32 *pHdr = (U32 *)(pData + AVTP_V0_HEADER_SIZE);
+ U8 *pPayload = pData + TOTAL_HEADER_SIZE;
+
U32 bytesProcessed = 0;
while (bytesProcessed < bytesNeeded) {
pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
if (pMediaQItem && pMediaQItem->pPubData && pMediaQItem->dataLen > 0) {
- U32 tmp32;
- U8 *pHdrV0 = pData;
- U32 *pHdr = (U32 *)(pData + AVTP_V0_HEADER_SIZE);
- U8 *pPayload = pData + TOTAL_HEADER_SIZE;
-
// timestamp set in the interface module, here just validate
// In sparse mode, the timestamp valid flag should be set every eighth AAF AVPTDU.
if (pPvtData->sparseMode == TS_SPARSE_MODE_ENABLED && (pHdrV0[HIDX_AVTP_SEQ_NUM] & 0x07) != 0) {
@@ -587,6 +607,7 @@ void openavbMapAVTPAudioRxInitCB(media_q_t *pMediaQ)
AVB_LOG_ERROR("Private mapping module data not allocated.");
return;
}
+ pPvtData->isTalker = FALSE;
if (pPvtData->audioMcr != AVB_MCR_NONE) {
HAL_INIT_MCR_V2(pPvtData->txInterval, pPvtData->packingFactor, pPvtData->mcrTimestampInterval, pPvtData->mcrRecoveryInterval);
}
@@ -858,8 +879,8 @@ void openavbMapAVTPAudioEndCB(media_q_t *pMediaQ)
void openavbMapAVTPAudioGenEndCB(media_q_t *pMediaQ)
{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ AVB_TRACE_ENTRY(AVB_TRACE_MAP);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP);
}
// Initialization entry point into the mapping module. Will need to be included in the .ini file.
diff --git a/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c b/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c
index 885b06ea..c1d9e9a8 100644
--- a/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c
+++ b/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c
@@ -77,6 +77,7 @@ void openavbAvdeccHostUsage(char *programName)
"\n"
"Usage: %s [options] file...\n"
" -I val Use given (val) interface globally, can be overriden by giving the ifname= option to the config line.\n"
+ " -l val Filename of the log file to use. If not specified, results will be logged to stderr.\n"
"\n"
"Examples:\n"
" %s talker.ini\n"
@@ -98,6 +99,7 @@ int main(int argc, char *argv[])
char *programName;
char *optIfnameGlobal = NULL;
+ char *optLogFileName = NULL;
programName = strrchr(argv[0], '/');
programName = programName ? programName + 1 : argv[0];
@@ -110,12 +112,15 @@ int main(int argc, char *argv[])
// Process command line
bool optDone = FALSE;
while (!optDone) {
- int opt = getopt(argc, argv, "hI:");
+ int opt = getopt(argc, argv, "hI:l:");
if (opt != EOF) {
switch (opt) {
case 'I':
optIfnameGlobal = strdup(optarg);
break;
+ case 'l':
+ optLogFileName = strdup(optarg);
+ break;
case 'h':
default:
openavbAvdeccHostUsage(programName);
@@ -130,7 +135,7 @@ int main(int argc, char *argv[])
int iniIdx = optind;
int tlCount = argc - iniIdx;
- if (!osalAvdeccInitialize(optIfnameGlobal, (const char **) (argv + iniIdx), tlCount)) {
+ if (!osalAvdeccInitialize(optLogFileName, optIfnameGlobal, (const char **) (argv + iniIdx), tlCount)) {
osalAvdeccFinalize();
exit(-1);
}
@@ -173,6 +178,11 @@ int main(int argc, char *argv[])
osalAvdeccFinalize();
+ if (optLogFileName) {
+ free(optLogFileName);
+ optLogFileName = NULL;
+ }
+
AVB_TRACE_EXIT(AVB_TRACE_HOST);
exit(0);
}
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
index 115d553b..4c89041d 100644
--- a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -122,6 +122,7 @@ void openavbTlHarnessUsage(char *programName)
" -s val Stream count. Starts 'val' number of streams for each configuration file. stream_uid will be overriden.\n"
" -d val Last byte of destination address from static pool. Full address will be 91:e0:f0:00:fe:val.\n"
" -I val Use given (val) interface globally, can be overriden by giving the ifname= option to the config line.\n"
+ " -l val Filename of the log file to use. If not specified, results will be logged to stderr.\n"
"\n"
"Examples:\n"
" %s talker.ini\n"
@@ -172,6 +173,7 @@ int main(int argc, char *argv[])
bool optDestAddrSet = FALSE;
U8 destAddr[ETH_ALEN] = {0x91, 0xe0, 0xf0, 0x00, 0xfe, 0x00};
char *optIfnameGlobal = NULL;
+ char *optLogFileName = NULL;
// Talker listener vars
int iniIdx = 0;
@@ -229,7 +231,7 @@ int main(int argc, char *argv[])
bool optDone = FALSE;
while (!optDone) {
- int opt = getopt(argc, argv, "a:his:d:I:");
+ int opt = getopt(argc, argv, "a:his:d:I:l:");
if (opt != EOF) {
switch (opt) {
case 'a':
@@ -249,6 +251,9 @@ int main(int argc, char *argv[])
case 'I':
optIfnameGlobal = strdup(optarg);
break;
+ case 'l':
+ optLogFileName = strdup(optarg);
+ break;
case '?':
default:
openavbTlHarnessUsage(programName);
@@ -260,7 +265,7 @@ int main(int argc, char *argv[])
}
}
- osalAVBInitialize(optIfnameGlobal);
+ osalAVBInitialize(optLogFileName, optIfnameGlobal);
// Setup the talker listener counts and lists
iniIdx = optind;
@@ -554,6 +559,11 @@ int main(int argc, char *argv[])
optStreamAddr = NULL;
}
+ if (optLogFileName) {
+ free(optLogFileName);
+ optLogFileName = NULL;
+ }
+
#ifdef AVB_FEATURE_GSTREAMER
// If we're supporting the interface modules which use GStreamer,
// De-initialize GStreamer to clean up resources.
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
index 324f54d2..dd03f4a8 100644
--- a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -111,6 +111,7 @@ void openavbTlHostUsage(char *programName)
"\n"
"Usage: %s [options] file...\n"
" -I val Use given (val) interface globally, can be overriden by giving the ifname= option to the config line.\n"
+ " -l val Filename of the log file to use. If not specified, results will be logged to stderr.\n"
"\n"
"Examples:\n"
" %s talker.ini\n"
@@ -135,6 +136,7 @@ int main(int argc, char *argv[])
int iniIdx = 0;
char *programName;
char *optIfnameGlobal = NULL;
+ char *optLogFileName = NULL;
programName = strrchr(argv[0], '/');
programName = programName ? programName + 1 : argv[0];
@@ -150,12 +152,15 @@ int main(int argc, char *argv[])
// Process command line
bool optDone = FALSE;
while (!optDone) {
- int opt = getopt(argc, argv, "hI:");
+ int opt = getopt(argc, argv, "hI:l:");
if (opt != EOF) {
switch (opt) {
case 'I':
optIfnameGlobal = strdup(optarg);
break;
+ case 'l':
+ optLogFileName = strdup(optarg);
+ break;
case 'h':
default:
openavbTlHostUsage(programName);
@@ -167,7 +172,7 @@ int main(int argc, char *argv[])
}
}
- osalAVBInitialize(optIfnameGlobal);
+ osalAVBInitialize(optLogFileName, optIfnameGlobal);
iniIdx = optind;
U32 tlCount = argc - iniIdx;
@@ -300,6 +305,11 @@ int main(int argc, char *argv[])
openavbTLCleanup();
+ if (optLogFileName) {
+ free(optLogFileName);
+ optLogFileName = NULL;
+ }
+
#ifdef AVB_FEATURE_GSTREAMER
// If we're supporting the interface modules which use GStreamer,
// De-initialize GStreamer to clean up resources.
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c
index cdf70181..9c22fc36 100644
--- a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c
@@ -79,7 +79,7 @@ static int cfgCallback(void *user, const char *section, const char *name, const
{
if_info_t ifinfo;
if (openavbCheckInterface(value, &ifinfo)) {
- strncpy(pCfg->ifname, value, IFNAMSIZ - 1);
+ strncpy(pCfg->ifname, value, sizeof(pCfg->ifname) - 1);
memcpy(pCfg->ifmac, &ifinfo.mac, ETH_ALEN);
valOK = TRUE;
}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
index 7e0b53c6..6794a84b 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -76,9 +76,9 @@ static int cfgCallback(void *user, const char *section, const char *name, const
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return 0;
}
-
+
openavb_endpoint_cfg_t *pCfg = (openavb_endpoint_cfg_t*)user;
-
+
AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);
bool valOK = FALSE;
@@ -90,7 +90,7 @@ static int cfgCallback(void *user, const char *section, const char *name, const
{
if_info_t ifinfo;
if (openavbCheckInterface(value, &ifinfo)) {
- strncpy(pCfg->ifname, value, IFNAMSIZ - 1);
+ strncpy(pCfg->ifname, value, sizeof(pCfg->ifname) - 1);
memcpy(pCfg->ifmac, &ifinfo.mac, ETH_ALEN);
pCfg->ifindex = ifinfo.index;
pCfg->mtu = ifinfo.mtu;
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/example_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/example_listener.ini
new file mode 100644
index 00000000..7b15b48c
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/example_listener.ini
@@ -0,0 +1,135 @@
+#####################################################################
+# General Talker Configuration for ALSA and
+# uncompressed 61883-6 audio mapping
+#####################################################################
+
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = listener
+
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+initial_state = stopped
+
+# stream_addr: Used on the listener and should be set to the
+# mac address of the talker.
+#stream_addr = 01:23:45:67:89:ab
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+#stream_uid = 0
+
+# dest_addr: When SRP is being used the destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set in both side the talker and listener.
+# The destination is a multicast address, not a real MAC address, so it
+# does not match the talker or listener's interface MAC. There are
+# several pools of those addresses for use by AVTP defined in 1722.
+# At this time they need to be locally administered and must be in the range
+# of 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically :00 for the first stream, :01 for the second, etc.
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+#max_interval_frames = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# On the talker this value is added to the PTP walltime to create the AVTP Timestamp.
+# On the listener this value is used to validate an expected valid timestamp range.
+# Note: For the listener the map_nv_item_count value must be set large enough to
+# allow buffering at least as many AVTP packets that can be transmitted during this
+# max transit time.
+max_transit_usec = 50000
+
+# raw_tx_buffers: The number of raw socket transmit buffers. Typically 4 - 8 are good values.
+# This is only used by the talker. If not set internal defaults are used.
+#raw_tx_buffers = 1
+
+# raw_rx_buffers: The number of raw socket receive buffers. Typically 50 - 100 are good values.
+# This is only used by the listener. If not set internal defaults are used.
+raw_rx_buffers = 200
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+#report_seconds = 1
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+ifname = pcap:eth0
+
+# Bit mask used for CPU pinning. Defaults to all cpus can be used (0xffffffff).
+#thread_affinity = 12
+
+# Enable real time scheduling with this priority. Defaults to not use RT sched (0).
+thread_rt_priority = 10
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. Comment out the map_lib name
+# and link in the .c file to the openavb_tl executable to embed the mapper
+# directly into the executable unit. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+map_lib = ./libopenavb_map_uncmp_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapUncmpAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 400
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the uncompressed audio mapping module.
+map_nv_tx_rate = 8000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# Note: Typically when decreasing the map_nv_tx_rate the packing factor will also be decreased since
+# the number of frames per packet will be increasing.
+map_nv_packing_factor = 256
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. Comment out the intf_lib name
+# and link in the .c file to the openavb_tl executable to embed the interface
+# directly into the executable unit. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+# intf_fn: The name of the initialize function in the interface.
+intf_lib = ./libopenavb_intf_alsa.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfAlsaInitialize
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+# intf_nv_device_name: ALSA device name. Commonly "default" or "plug:dmix"
+intf_nv_device_name = default
+
+# intf_nv_audio_rate: Sampling rate of the audio (samples/second)
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: Number of bits per audio sample. Typical values are 16, 24, and 32.
+intf_nv_audio_bit_depth = 24
+
+# intf_nv_audio_channels: Number of channels of audio.
+intf_nv_audio_channels = 8
+
+# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
+intf_nv_allow_resampling = 1
+
+# intf_nv_start_threshold_periods: The number of period to wait before starting playback. The larger the value to great
+# the latency. The small the number the great chance for a buffer underrun. A good range is 1 - 5.
+intf_nv_start_threshold_periods = 3
+
+# intf_nv_period_time: the number of microseconds which should be set to unify latency between different platforms.
+# This influence ALSA's period_time and period_size parameters and the result value should be the nearest possible.
+# Initial playback latency is equal intf_nv_start_threshold_periods * intf_nv_period_time. If not set internal defaults are used.
+# intf_nv_period_time = 0
+
+# Default PC audio is little-endian
+intf_nv_audio_endian = little
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/example_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/example_talker.ini
new file mode 100644
index 00000000..d301ea79
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/example_talker.ini
@@ -0,0 +1,181 @@
+#####################################################################
+# General Talker Configuration for ALSA and
+# uncompressed 61883-6 audio mapping
+#####################################################################
+
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+initial_state = stopped
+
+# stream_addr: Used on the listener and should be set to the
+# mac address of the talker.
+#stream_addr = 01:23:45:67:89:ab
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 0
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse addresses are in the range of:
+# 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically use :00 for the first stream, :01 for the second, etc.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# The destination is a multicast address, not a real MAC address, so it
+# does not match the talker or listener's interface MAC. There are
+# several pools of those addresses for use by AVTP defined in 1722.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = A
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# On the talker this value is added to the PTP walltime to create the AVTP Timestamp.
+# On the listener this value is used to validate an expected valid timestamp range.
+# Note: For the listener the map_nv_item_count value must be set large enough to
+# allow buffering at least as many AVTP packets that can be transmitted during this
+# max transit time.
+max_transit_usec = 4000
+
+# max_transmit_deficit_usec: Allows setting the maximum packet transmit rate deficit that will
+# be recovered when a talker falls behind. This is only used on a talker side. When a talker
+# can not keep up with the specified transmit rate it builds up a deficit and will attempt to
+# make up for this deficit by sending more packets. There is normally some variability in the
+# transmit rate because of other demands on the system so this is expected. However, without this
+# bounding value the deficit could grew too large in cases such where more streams are started
+# than the system can support and when the number of streams is reduced the remaining streams
+# will attempt to recover this deficit by sending packets at a higher rate. This can cause a problem
+# at the listener side and significantly delay the recovery time before media playback will return
+# to normal. Typically this value can be set to the expected buffer size (in usec) that listeners are
+# expected to be buffering. For low latency solutions this is normally a small value. For non-live
+# media playback such as video playback the listener side buffers can often be large enough to held many
+# seconds of data.
+max_transmit_deficit_usec = 50000
+
+# internal_latency: Allows manually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# max_stale: The number of microseconds beyond the presentation time that media queue items will be purged
+# because they are too old (past the presentation time). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# raw_tx_buffers: The number of raw socket transmit buffers. Typically 4 - 8 are good values.
+# This is only used by the talker. If not set internal defaults are used.
+#raw_tx_buffers = 4
+
+# raw_rx_buffers: The number of raw socket receive buffers. Typically 50 - 100 are good values.
+# This is only used by the listener. If not set internal defaults are used.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+#report_seconds = 1
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+ifname = pcap:eth0
+
+# vlan_id: VLAN Identifier (1-4094). Used in "no endpoint" builds. Defaults to 2.
+# vlan_id = 2
+
+# Enable fixed timestamping in interface. Defaults to disable (0).
+fixed_timestamp = 1
+
+# Tx packets to process per wake; for values > 1, traffic shaping must be enabled to evenly space the packets.
+#batch_factor = 1
+
+# Bit mask used for CPU pinning. Defaults to all cpus can be used (0xffffffff).
+#thread_affinity = 12
+
+# Enable real time scheduling with this priority. Defaults to not use RT sched (0).
+thread_rt_priority = 20
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. Comment out the map_lib name
+# and link in the .c file to the openavb_tl executable to embed the mapper
+# directly into the executable unit. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+map_lib = ./libopenavb_map_uncmp_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapUncmpAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the uncompressed audio mapping module.
+map_nv_tx_rate = 8000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# Note: Typically when decreasing the map_nv_tx_rate the packing factor will also be decreased since
+# the number of frames per packet will be increasing.
+map_nv_packing_factor = 1
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. Comment out the intf_lib name
+# and link in the .c file to the openavb_tl executable to embed the interface
+# directly into the executable unit. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+# intf_fn: The name of the initialize function in the interface.
+intf_lib = ./libopenavb_intf_alsa.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfAlsaInitialize
+
+# intf_nv_ignore_timestamp: If set the listener will ignore the timestamp on media queue items.
+# intf_nv_ignore_timestamp = 1
+
+# intf_nv_device_name: ALSA device name. Commonly "default" or "plug:dmix"
+intf_nv_device_name = default
+
+# intf_nv_audio_rate: Sampling rate of the audio (samples/second)
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: Number of bits per audio sample. Typical values are 16, 24, and 32.
+intf_nv_audio_bit_depth = 24
+
+# intf_nv_audio_channels: Number of channels of audio.
+intf_nv_audio_channels = 8
+
+# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
+intf_nv_allow_resampling = 1
+
+# Default PC audio is little-endian
+intf_nv_audio_endian = little
+
+# Clock skew between media clock and PTP clock in nanoseconds-per-second - adjust this to correct Fixed/Real TS Delta drift
+intf_nv_clock_skew_ppb = 0
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_osal.c
index 05259809..f2568c54 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal.c
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -37,9 +37,23 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_pub.h"
#include "openavb_log.h"
-extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
+static FILE *s_logfile = NULL;
+
+extern DLL_EXPORT bool osalAVBInitialize(const char* logfilename, const char* ifname)
{
- avbLogInit();
+ // Open the log file, if requested.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+ if (logfilename) {
+ s_logfile = fopen(logfilename, "w");
+ if (s_logfile == NULL) {
+ fprintf(stderr, "Error opening log file: %s\n", logfilename);
+ }
+ }
+
+ avbLogInitEx(s_logfile);
osalAVBTimeInit();
openavbQmgrInitialize(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
return TRUE;
@@ -50,6 +64,13 @@ extern DLL_EXPORT bool osalAVBFinalize(void)
openavbQmgrFinalize();
osalAVBTimeClose();
avbLogExit();
+
+ // Done with the log file.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+
return TRUE;
}
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c b/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c
index e566e1a2..b8f056a9 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c
@@ -38,9 +38,23 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_pub.h"
#include "openavb_log.h"
-extern DLL_EXPORT bool osalAvdeccInitialize(const char* ifname, const char **inifiles, int numfiles)
+static FILE *s_logfile = NULL;
+
+extern DLL_EXPORT bool osalAvdeccInitialize(const char* logfilename, const char* ifname, const char **inifiles, int numfiles)
{
- avbLogInit();
+ // Open the log file, if requested.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+ if (logfilename) {
+ s_logfile = fopen(logfilename, "w");
+ if (s_logfile == NULL) {
+ fprintf(stderr, "Error opening log file: %s\n", logfilename);
+ }
+ }
+
+ avbLogInitEx(s_logfile);
osalAVBTimeInit();
if (!osalAVBGrandmasterInit()) { return FALSE; }
if (!startAvdecc(ifname, inifiles, numfiles)) { return FALSE; }
@@ -53,6 +67,13 @@ extern DLL_EXPORT bool osalAvdeccFinalize(void)
osalAVBGrandmasterClose();
osalAVBTimeClose();
avbLogExit();
+
+ // Done with the log file.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+
return TRUE;
}
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c b/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
index ef204d32..5e661167 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -38,9 +38,23 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_pub.h"
#include "openavb_log.h"
-extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
+static FILE *s_logfile = NULL;
+
+extern DLL_EXPORT bool osalAVBInitialize(const char* logfilename, const char* ifname)
{
- avbLogInit();
+ // Open the log file, if requested.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+ if (logfilename) {
+ s_logfile = fopen(logfilename, "w");
+ if (s_logfile == NULL) {
+ fprintf(stderr, "Error opening log file: %s\n", logfilename);
+ }
+ }
+
+ avbLogInitEx(s_logfile);
osalAVBTimeInit();
startEndpoint(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
return TRUE;
@@ -51,6 +65,13 @@ extern DLL_EXPORT bool osalAVBFinalize(void)
stopEndpoint();
osalAVBTimeClose();
avbLogExit();
+
+ // Done with the log file.
+ if (s_logfile) {
+ fclose(s_logfile);
+ s_logfile = NULL;
+ }
+
return TRUE;
}
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
index fcb8e778..843d192e 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -37,12 +37,12 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_os_services_osal_pub.h"
-bool osalAVBInitialize(const char *ifname);
+bool osalAVBInitialize(const char* logfilename, const char *ifname);
bool osalAVBFinalize(void);
-bool osalAvdeccInitialize(const char *ifname, const char **inifiles, int numfiles);
+bool osalAvdeccInitialize(const char* logfilename, const char *ifname, const char **inifiles, int numfiles);
bool osalAvdeccFinalize(void);
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_tasks.h b/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
index 01969f09..387fd985 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
@@ -32,7 +32,15 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#ifndef _EAVBTASKS_H
#define _EAVBTASKS_H
-#define THREAD_STACK_SIZE 65536
+#include <limits.h>
+
+#if !defined(PTHREAD_STACK_MIN)
+#error "PTHREAD_STACK_MIN variable not defined"
+#elif (PTHREAD_STACK_MIN > 65536)
+#define THREAD_STACK_SIZE PTHREAD_STACK_MIN
+#else
+#define THREAD_STACK_SIZE 65536
+#endif
///////////////////////////
// Platform code Tasks values
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
index 18293a37..c903ae43 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
@@ -55,7 +55,7 @@ bool simpleAvbCheckInterface(const char *ifname, if_info_t *info)
memset(info, 0, sizeof(if_info_t));
AVB_LOGF_DEBUG("ifname=%s", ifname);
- strncpy(info->name, ifname, IFNAMSIZ - 1);
+ strncpy(info->name, ifname, sizeof(info->name) - 1);
// open a throw-away socket - used for our ioctls
int sk = socket(AF_INET, SOCK_STREAM, 0);
diff --git a/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c b/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
index f9e7d1f1..8f3cf82b 100644
--- a/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -317,7 +317,7 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
}
}
else if (MATCH(name, "ifname")) {
- strncpy(pCfg->ifname, value, IFNAMSIZ - 1);
+ strncpy(pCfg->ifname, value, sizeof(pCfg->ifname) - 1);
valOK = TRUE;
}
else if (MATCH(name, "vlan_id")) {
diff --git a/lib/avtp_pipeline/qmgr/openavb_qmgr.c b/lib/avtp_pipeline/qmgr/openavb_qmgr.c
index d3a9b84a..5c054eb2 100644
--- a/lib/avtp_pipeline/qmgr/openavb_qmgr.c
+++ b/lib/avtp_pipeline/qmgr/openavb_qmgr.c
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -275,7 +275,7 @@ bool openavbQmgrInitialize(int mode, int ifindex, const char* ifname, unsigned m
// Save the configuration
if (ifname)
- strncpy(qdisc_data.ifname, ifname, IFNAMSIZ - 1);
+ strncpy(qdisc_data.ifname, ifname, sizeof(qdisc_data.ifname) - 1);
qdisc_data.ifindex = ifindex;
qdisc_data.linkKbit = link_kbit;
qdisc_data.linkMTU = mtu;
diff --git a/lib/avtp_pipeline/tl/openavb_listener_endpoint.c b/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
index 95c2b215..6280266c 100644
--- a/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -91,9 +91,9 @@ void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
if (rc) {
// Save data provided by endpoint/SRP
if (!pCfg->ifname[0]) {
- strncpy(pListenerData->ifname, ifname, IFNAMSIZ);
+ strncpy(pListenerData->ifname, ifname, sizeof(pListenerData->ifname) - 1);
} else {
- strncpy(pListenerData->ifname, pCfg->ifname, IFNAMSIZ);
+ strncpy(pListenerData->ifname, pCfg->ifname, sizeof(pListenerData->ifname) - 1);
}
memcpy(&pListenerData->streamID, streamID, sizeof(AVBStreamID_t));
if (memcmp(destAddr, emptyMAC, ETH_ALEN) != 0) {
diff --git a/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c b/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
index d006b708..f7336f68 100644
--- a/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
@@ -2,16 +2,16 @@
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
Copyright (c) 2016-2017, Harman International Industries, Incorporated
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.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "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
@@ -22,10 +22,10 @@ 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.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -52,7 +52,7 @@ bool openavbTLRunListenerInit(int hnd, AVBStreamID_t *streamID)
openavb_tl_cfg_t *pCfg = &pTLState->cfg;
listener_data_t *pListenerData = pTLState->pPvtListenerData;
- strncpy(pListenerData->ifname, pCfg->ifname, IFNAMSIZ);
+ strncpy(pListenerData->ifname, pCfg->ifname, sizeof(pListenerData->ifname) - 1);
memcpy(&pListenerData->streamID.addr, &pCfg->stream_addr.mac->ether_addr_octet, ETH_ALEN);
pListenerData->streamID.uniqueID = pCfg->stream_uid;
memcpy(&pListenerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
@@ -62,7 +62,7 @@ bool openavbTLRunListenerInit(int hnd, AVBStreamID_t *streamID)
AVB_LOGF_INFO("Dest Addr: "ETH_FORMAT, ETH_OCTETS(pListenerData->destAddr));
AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID));
listenerStartStream(pTLState);
-
+
return TRUE;
}
diff --git a/lib/avtp_pipeline/tl/openavb_talker_endpoint.c b/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
index e3343e78..c1a5eb4e 100644
--- a/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
@@ -90,9 +90,9 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
// Save the data provided by endpoint/SRP
if (!pCfg->ifname[0]) {
- strncpy(pTalkerData->ifname, ifname, IFNAMSIZ);
+ strncpy(pTalkerData->ifname, ifname, sizeof(pTalkerData->ifname) - 1);
} else {
- strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
+ strncpy(pTalkerData->ifname, pCfg->ifname, sizeof(pTalkerData->ifname) - 1);
}
memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t));
memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN);
@@ -109,9 +109,9 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
else if (lsnrDecl == openavbSrp_LDSt_Stream_Info) {
// Stream information is available does NOT mean listener is ready. Stream not started yet.
if (!pCfg->ifname[0]) {
- strncpy(pTalkerData->ifname, ifname, IFNAMSIZ);
+ strncpy(pTalkerData->ifname, ifname, sizeof(pTalkerData->ifname) - 1);
} else {
- strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
+ strncpy(pTalkerData->ifname, pCfg->ifname, sizeof(pTalkerData->ifname) - 1);
}
memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t));
memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN);
diff --git a/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c b/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
index 03cb8ade..90476031 100644
--- a/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
@@ -62,11 +62,10 @@ bool openavbTLRunTalkerInit(tl_state_t *pTLState)
talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
//avtp_stream_t *pStream = (avtp_stream_t *)(pTalkerData->avtpHandle);
- strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
+ strncpy(pTalkerData->ifname, pCfg->ifname, sizeof(pTalkerData->ifname) - 1);
// CORE_TODO: It would be good to have some parts of endpoint moved into non-endpoint general code to handle some the stream
// configuration values.
- // strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
if (pCfg->stream_addr.mac) {
memcpy(pTalkerData->streamID.addr, pCfg->stream_addr.mac, ETH_ALEN);
}else {
diff --git a/lib/avtp_pipeline/tl/openavb_tl_pub.h b/lib/avtp_pipeline/tl/openavb_tl_pub.h
index d89729a1..a5f3da69 100755
--- a/lib/avtp_pipeline/tl/openavb_tl_pub.h
+++ b/lib/avtp_pipeline/tl/openavb_tl_pub.h
@@ -74,7 +74,9 @@ typedef enum {
/// Maximum size of interface name
-#define IFNAMSIZE 16
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
/// Maximum size of the friendly name
#define FRIENDLY_NAME_SIZE 64
@@ -139,7 +141,7 @@ typedef struct {
/// Is the interface module blocking in the TX CB.
bool tx_blocking_in_intf;
/// Network interface name. Not used on all platforms.
- char ifname[IFNAMSIZE];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
/// VLAN ID
U16 vlan_id;
/// When set incoming packets will trigger a signal to the stream task to wakeup.
diff --git a/run_avtp_pipeline.sh b/run_avtp_pipeline.sh
new file mode 100755
index 00000000..0a632bb0
--- /dev/null
+++ b/run_avtp_pipeline.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Script to start the AVTP Pipeline talker/listener with 8-channel, 48K/24-bit IEC 61883-6 audio.
+# For more details, refer to the lib/avtp_pipeline/README.md file.
+
+if [ "$#" -eq "0" ]; then
+ echo "Please enter network interface name as parameter. For example:"
+ echo "sudo $0 eth1"
+ echo ""
+ exit -1
+fi
+
+nic=$1
+echo "Starting AVTP Pipeline on "$nic
+
+scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+pushd .
+cd $scriptdir/lib/avtp_pipeline/build/bin
+./openavb_avdecc -I pcap:$nic example_talker.ini example_listener.ini &
+sleep 5
+./openavb_host -I pcap:$nic example_talker.ini example_listener.ini &
+popd
+
diff --git a/run_daemons.sh b/run_daemons.sh
index 30da552d..c8ed4996 100755
--- a/run_daemons.sh
+++ b/run_daemons.sh
@@ -1,33 +1,29 @@
#!/bin/bash
# Start all daemons
-nic=$1
-
if [ "$1" == "-h" ]; then
echo "Usage: $0 <network interface>"
echo " eg: $0 eth1"
+ echo ""
+ echo "If you are using IGB, call \"sudo ./run_igb.sh\" before running this script."
+ echo ""
exit
fi
if [ "$1" == "" ]; then
- nic="eth1" #edit as required
- echo "Network interface not specified, assuming: $nic"
+ echo "Please enter network interface name as parameter. For example:"
+ echo "sudo $0 eth1"
+ echo ""
+ echo "If you are using IGB, call \"sudo ./run_igb.sh\" before running this script."
+ echo ""
+ exit -1
fi
+nic=$1
echo "Starting daemons on "$nic
-#use false for silence
-if true; then
- sudo rmmod igb
- sudo insmod kmod/igb/igb_avb.ko
- sudo groupadd ptp
-else
- sudo rmmod igb > /dev/null 2>&1
- sudo insmod kmod/igb/igb_avb.ko > /dev/null 2>&1
- sudo groupadd ptp > /dev/null 2>&1
-fi
-
-sudo daemons/gptp/linux/build/obj/daemon_cl $nic &
-sudo daemons/mrpd/mrpd -mvs -i $nic &
-sudo daemons/maap/linux/maap_daemon -i $nic &
-
+groupadd ptp > /dev/null 2>&1
+daemons/gptp/linux/build/obj/daemon_cl $nic &
+daemons/mrpd/mrpd -mvs -i $nic &
+daemons/maap/linux/build/maap_daemon -i $nic -d /dev/null
+daemons/shaper/shaper_daemon -d &
diff --git a/stop_avtp_pipeline.sh b/stop_avtp_pipeline.sh
new file mode 100755
index 00000000..81f9ab3c
--- /dev/null
+++ b/stop_avtp_pipeline.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+killall -2 openavb_host
+sleep 1
+killall -2 openavb_avdecc
+
+# Code below this point is to recover in case one of the applications crashes.
+
+sleep 5
+
+killall -9 openavb_host
+killall -9 openavb_avdecc
+sleep 1
+
+scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+$scriptdir/lib/avtp_pipeline/build/bin/shutdown_openavb_endpoint.sh
+$scriptdir/lib/avtp_pipeline/build/bin/shutdown_openavb_avdecc.sh
+
diff --git a/stop_daemons.sh b/stop_daemons.sh
index 82598852..a1ae8bb0 100755
--- a/stop_daemons.sh
+++ b/stop_daemons.sh
@@ -1,9 +1,10 @@
#!/bin/bash
# Stop all daemons
-sudo killall maap_daemon
-sudo killall mrpd
-sudo killall daemon_cl
+killall shaper_daemon
+killall maap_daemon
+killall mrpd
+killall daemon_cl
# possibly add rmmod igb_avb here
diff --git a/thirdparty/cpputest b/thirdparty/cpputest
-Subproject 69d1b24fa92fc8c3cf5542bf44293c3e05cfbf0
+Subproject 1d95a3905413d99fddb5bcbd30be35a16dbf911