diff options
Diffstat (limited to 'daemons/gptp/windows')
-rw-r--r-- | daemons/gptp/windows/daemon_cl/daemon_cl.cpp | 129 | ||||
-rw-r--r-- | daemons/gptp/windows/daemon_cl/intel_wireless.cpp | 424 | ||||
-rw-r--r-- | daemons/gptp/windows/daemon_cl/intel_wireless.hpp | 187 | ||||
-rw-r--r-- | daemons/gptp/windows/daemon_cl/tsc.hpp | 13 | ||||
-rw-r--r-- | daemons/gptp/windows/daemon_cl/windows_hal.cpp | 180 | ||||
-rw-r--r-- | daemons/gptp/windows/daemon_cl/windows_hal.hpp | 114 | ||||
-rw-r--r-- | daemons/gptp/windows/daemon_cl/work_queue.cpp | 106 | ||||
-rw-r--r-- | daemons/gptp/windows/daemon_cl/work_queue.hpp | 74 | ||||
-rw-r--r-- | daemons/gptp/windows/named_pipe_test/named_pipe_test.cpp | 2 |
9 files changed, 1185 insertions, 44 deletions
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 = ðer_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 = ðer_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( ×tamperContextMap->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(×tamperContextMap->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, ×tamperContextMap, 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(×tamperContextMap.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(×tamperContextMap.lock); + + return ret; +} + +bool IntelWirelessAdapter::deregisterTimestamper +( WindowsWirelessTimestamper *timestamper ) +{ + bool ret; + + TimestamperContextMap::iterator iter; + AcquireSRWLockExclusive(×tamperContextMap.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(×tamperContextMap.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 )) { |