diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /sensors/Pedometer | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'sensors/Pedometer')
| -rw-r--r-- | sensors/Pedometer/Device.h | 209 | ||||
| -rw-r--r-- | sensors/Pedometer/Driver.h | 19 | ||||
| -rw-r--r-- | sensors/Pedometer/HardwareSimulator.h | 102 | ||||
| -rw-r--r-- | sensors/Pedometer/Pedometer.def | 6 | ||||
| -rw-r--r-- | sensors/Pedometer/Pedometer.inx | 95 | ||||
| -rw-r--r-- | sensors/Pedometer/Pedometer.sln | 28 | ||||
| -rw-r--r-- | sensors/Pedometer/Pedometer.vcxproj | 205 | ||||
| -rw-r--r-- | sensors/Pedometer/Pedometer.vcxproj.Filters | 46 | ||||
| -rw-r--r-- | sensors/Pedometer/ReadMe.md | 7 | ||||
| -rw-r--r-- | sensors/Pedometer/SensorsTrace.h | 93 | ||||
| -rw-r--r-- | sensors/Pedometer/client.cpp | 1224 | ||||
| -rw-r--r-- | sensors/Pedometer/device.cpp | 738 | ||||
| -rw-r--r-- | sensors/Pedometer/driver.cpp | 76 | ||||
| -rw-r--r-- | sensors/Pedometer/hardwaresimulator.cpp | 677 |
14 files changed, 3525 insertions, 0 deletions
diff --git a/sensors/Pedometer/Device.h b/sensors/Pedometer/Device.h new file mode 100644 index 00000000..26dcc7ad --- /dev/null +++ b/sensors/Pedometer/Device.h @@ -0,0 +1,209 @@ +//Copyright (C) Microsoft Corporation, All Rights Reserved +// +//Abstract: +// +// This module contains the type definitions for the client +// driver's device callback class. +// +//Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#pragma once + +#include <windows.h> +#include <wdf.h> +#include <math.h> + +#include <SensorsTrace.h> +#include <SensorsCx.h> +#include <SensorsUtils.h> + +#define SENSOR_POOL_TAG_PEDOMETER 'odeP' + +#define Pedometer_Default_MinDataInterval_Ms (100) // milliseconds +#define Pedometer_Default_Threshold_StepCount (1) // threshold in step counts +#define Pedometer_Default_Power_Milliwatts (2.0f) // milli watts +#define Pedometer_TimeoutForHistoryThread_Ms (1000) // milli seconds +#define Pedometer_Default_HistoryInterval_Ms (60000) // 1 minute in milli seconds +#define Pedometer_Default_MaxHistoryEntries (60) // max of 60 history entries + +// Sensor Common Properties +typedef enum +{ + SENSOR_PROPERTY_STATE = 0, + SENSOR_PROPERTY_MIN_INTERVAL, + SENSOR_PROPERTY_MAX_DATAFIELDSIZE, + SENSOR_PROPERTY_SENSOR_TYPE, + SENSOR_PROPERTY_SENSOR_POWER, + SENSOR_PROPERTY_MAX_HISTORYSIZE, + SENSOR_PROPERTY_HISTORY_INTERVAL, + SENSOR_PROPERTY_MAX_HISTROYRECORDSIZE, + SENSOR_PROPERTY_SUPPORTED_STEPTYPES, + SENSOR_COMMON_PROPERTIES_COUNT +} SENSOR_COMMON_PROPERTIES_INDEX; + +// Sensor Enumeration Properties +typedef enum +{ + SENSOR_TYPE_GUID = 0, + SENSOR_MANUFACTURER, + SENSOR_MODEL, + SENSOR_PERSISTENT_UNIQUEID, + SENSOR_CATEGORY, + + // These enumeration properties overlap with + // a subset of the common properties, and + // facilitate discovery without opening a sensor + SENSOR_POWER, + SENSOR_MAX_HISTORYSIZE, + SENSOR_SUPPORTED_STEPTYPES, + SENSOR_ENUMERATION_PROPERTIES_COUNT +} SENSOR_ENUMERATION_PROPERTIES_INDEX; + +// Data-field Properties +typedef enum +{ + SENSOR_RESOLUTION = 0, + SENSOR_MIN_RANGE, + SENSOR_MAX_RANGE, + SENSOR_DATA_FIELD_PROPERTY_COUNT +} SENSOR_DATA_FIELD_PROPERTY_INDEX; + +// Supported Data Fields +typedef enum +{ + PEDOMETER_DATAFIELD_TIMESTAMP = 0, + PEDOMETER_DATAFIELD_FIRST_AFTER_RESET, + PEDOMETER_DATAFIELD_STEP_TYPE, + PEDOMETER_DATAFIELD_STEP_COUNT, + PEDOMETER_DATAFIELD_STEP_DURATION, + PEDOMETER_DATAFIELD_COUNT +} PEDOMETER_DATAFIELD_INDEX; + +// Supported Data +typedef enum +{ + PEDOMETER_DATA_TIMESTAMP = 0, + PEDOMETER_DATA_FIRST_AFTER_RESET, + PEDOMETER_DATA_UNKNOWN_STEP_TYPE, + PEDOMETER_DATA_UNKNOWN_STEP_COUNT, + PEDOMETER_DATA_UNKNOWN_STEP_DURATION, + PEDOMETER_DATA_WALKING_STEP_TYPE, + PEDOMETER_DATA_WALKING_STEP_COUNT, + PEDOMETER_DATA_WALKING_STEP_DURATION, + PEDOMETER_DATA_RUNNING_STEP_TYPE, + PEDOMETER_DATA_RUNNING_STEP_COUNT, + PEDOMETER_DATA_RUNNING_STEP_DURATION, + PEDOMETER_DATA_COUNT +} PEDOMETER_DATA_INDEX; + +typedef enum +{ + PEDOMETER_THRESHOLD_STEP_COUNT = 0, + PEDOMETER_THRESHOLD_COUNT +} PEDOMETER_THRESHOLD_INDEX; + +typedef struct PedometerSample +{ + FILETIME Timestamp; + BOOL IsFirstAfterReset; + ULONG UnknownStepCount; + INT64 UnknownStepDurationMs; + ULONG WalkingStepCount; + INT64 WalkingStepDurationMs; + ULONG RunningStepCount; + INT64 RunningStepDurationMs; +} PedometerSample, *PPedometerSample; + +// History buffer +typedef struct +{ + PPedometerSample pData; + ULONG FirstElemIndex; // index of the oldest entry + ULONG LastElemIndex; // index of the latest entry + ULONG NumOfElems; // number of entries + ULONG BufferLength; // length of the buffer +} HistoryCircBuffer, *PHistoryCircBuffer; + + +typedef class PedometerDevice +{ +private: + // Simulator + WDFOBJECT m_SimulatorInstance; + + // WDF + WDFDEVICE m_FxDevice; + SENSOROBJECT m_SensorInstance; + WDFWAITLOCK m_Lock; + WDFTIMER m_Timer; + + // Sensor operation + BOOLEAN m_PoweredOn; + BOOLEAN m_Started; + ULONG m_Interval; + + BOOLEAN m_FirstSample; + ULONG m_StartTime; + + ULONG m_CachedThreshold; + PedometerSample m_LastSample; + + // History operation + BOOLEAN m_HistorySupported; + BOOLEAN m_HistoryRetrievalStarted; + ULONG m_HistoryMarshalledRecordSize; + HANDLE m_hThread; + + PSENSOR_COLLECTION_LIST m_ClientHistoryBuffer; + ULONG m_ClientHistoryBufferSize; + + // Sensor Specific Properties + PSENSOR_COLLECTION_LIST m_pEnumerationProperties; + PSENSOR_COLLECTION_LIST m_pProperties; + PSENSOR_PROPERTY_LIST m_pSupportedDataFields; + PSENSOR_COLLECTION_LIST m_pDataFieldProperties; + PSENSOR_COLLECTION_LIST m_pThresholds; + PSENSOR_COLLECTION_LIST m_pData; + +public: + // WDF callbacks + static EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; + static EVT_WDF_DEVICE_PREPARE_HARDWARE OnPrepareHardware; + static EVT_WDF_DEVICE_RELEASE_HARDWARE OnReleaseHardware; + static EVT_WDF_DEVICE_D0_ENTRY OnD0Entry; + static EVT_WDF_DEVICE_D0_EXIT OnD0Exit; + static EVT_WDF_TIMER OnTimerExpire; + + // CLX callbacks + static EVT_SENSOR_DRIVER_START_SENSOR OnStart; + static EVT_SENSOR_DRIVER_STOP_SENSOR OnStop; + static EVT_SENSOR_DRIVER_GET_SUPPORTED_DATA_FIELDS OnGetSupportedDataFields; + static EVT_SENSOR_DRIVER_GET_PROPERTIES OnGetProperties; + static EVT_SENSOR_DRIVER_GET_DATA_FIELD_PROPERTIES OnGetDataFieldProperties; + static EVT_SENSOR_DRIVER_GET_DATA_INTERVAL OnGetDataInterval; + static EVT_SENSOR_DRIVER_SET_DATA_INTERVAL OnSetDataInterval; + static EVT_SENSOR_DRIVER_GET_DATA_THRESHOLDS OnGetDataThresholds; + static EVT_SENSOR_DRIVER_SET_DATA_THRESHOLDS OnSetDataThresholds; + static EVT_SENSOR_DRIVER_DEVICE_IO_CONTROL OnIoControl; + static EVT_SENSOR_DRIVER_START_SENSOR_HISTORY OnStartHistory; + static EVT_SENSOR_DRIVER_STOP_SENSOR_HISTORY OnStopHistory; + static EVT_SENSOR_DRIVER_CLEAR_SENSOR_HISTORY OnClearHistory; + static EVT_SENSOR_DRIVER_START_HISTORY_RETRIEVAL OnStartHistoryRetrieval; + static EVT_SENSOR_DRIVER_CANCEL_HISTORY_RETRIEVAL OnCancelHistoryRetrieval; +private: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + VOID ResetPedometer(); + static ULONG WINAPI HistoryRetrievalThread(_In_ LPVOID lpParam); + +} PedometerDevice, *PPedometerDevice; + +// Set up accessor function to retrieve device context +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PedometerDevice, GetPedometerContextFromSensorInstance); + +#define PedometerDevice_StepCount_Resolution (1) +#define PedometerDevice_StepCount_Minimum (0) +#define PedometerDevice_StepCount_Maximum (0xFFFFFFFF) diff --git a/sensors/Pedometer/Driver.h b/sensors/Pedometer/Driver.h new file mode 100644 index 00000000..d7b8cbfb --- /dev/null +++ b/sensors/Pedometer/Driver.h @@ -0,0 +1,19 @@ +//Copyright (C) Microsoft Corporation, All Rights Reserved +// +//Abstract: +// +// This module contains the type definitions for the pedometer sample driver's +// driver callback class. +// +//Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#pragma once + +WDF_EXTERN_C_START + +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_UNLOAD OnDriverUnload; + +WDF_EXTERN_C_END
\ No newline at end of file diff --git a/sensors/Pedometer/HardwareSimulator.h b/sensors/Pedometer/HardwareSimulator.h new file mode 100644 index 00000000..3d9646b9 --- /dev/null +++ b/sensors/Pedometer/HardwareSimulator.h @@ -0,0 +1,102 @@ +//Copyright (C) Microsoft Corporation, All Rights Reserved +// +//Abstract: +// +// This module contains the type definitions for the pedometer sample driver +// hardware simulator. +// +//Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#pragma once + +#include <windows.h> +#include <wdf.h> + +#include <SensorsTrace.h> +#include <SensorsCx.h> + +#include "Device.h" + +#define SIMULATOR_HARDWARE_INTERVAL_MS (1000) // 1 second interval in milliseconds + +typedef enum SIMULATOR_STATE +{ + SimulatorState_NotInitialized = 0, + SimulatorState_Initialized, + SimulatorState_Started +} SIMULATOR_STATE; + +typedef class HistoryIterator +{ +public: + HistoryIterator(); + ~HistoryIterator(); + + NTSTATUS Next(_Out_ PedometerSample *Sample); + +}HistoryIterator, *PHistoryIterator; + +typedef class HardwareSimulator +{ +private: + WDFTIMER m_Timer; + ULONG m_Index; + WDFWAITLOCK m_Lock; + SIMULATOR_STATE m_State; + WDFOBJECT m_SimulatorInstance; + BOOLEAN m_HasReset; + + // History operation + WDFWAITLOCK m_HistoryLock; + WDFTIMER m_HistoryTimer; + HistoryCircBuffer m_History; + ULONG m_HistoryIntervalInMs; + BOOLEAN m_HistoryStarted; + HANDLE m_HistoryCancelReadEvt; + +public: + HardwareSimulator(); + ~HardwareSimulator(); + + // WDF callbacks + static EVT_WDF_TIMER OnTimerExpire; + + static NTSTATUS Initialize(_In_ WDFDEVICE Device, _Out_ WDFOBJECT *SimulatorInstance); + NTSTATUS Cleanup(); + NTSTATUS Start(); + NTSTATUS Stop(); + NTSTATUS GetSample(_Out_ PedometerSample *Sample); + NTSTATUS Reset(); + NTSTATUS ClearHistory(); + NTSTATUS StartHistory(); + NTSTATUS StopHistory(); + NTSTATUS ReadHistory(_Inout_ PULONG SamplesCount, _Out_writes_to_(*SamplesCount, *SamplesCount) PPedometerSample HistorySamplesBuffer); + NTSTATUS SignalReadCancellation(); + + static EVT_WDF_TIMER OnHistoryTimerExpire; + + ULONG GetHistorySizeInRecords() + { + return m_History.BufferLength; + } + + ULONG GetHistoryIntervalInMs() + { + return m_HistoryIntervalInMs; + } + +private: + NTSTATUS InitializeInternal(_In_ WDFOBJECT SimulatorInstance); + NTSTATUS AddHistoryEntry(_In_ PedometerSample& Sample); + _Requires_lock_held_(m_HistoryLock) + NTSTATUS AddDataElemToHistoryBuffer(_In_ PPedometerSample pData); + _Requires_lock_held_(m_HistoryLock) + NTSTATUS RemoveDataElemFromHistoryBuffer(_Out_ PPedometerSample pData); + +} HardwareSimulator, *PHardwareSimulator; + + +// Set up accessor function to retrieve device context +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(HardwareSimulator, GetHardwareSimulatorContextFromInstance); diff --git a/sensors/Pedometer/Pedometer.def b/sensors/Pedometer/Pedometer.def new file mode 100644 index 00000000..18a7149f --- /dev/null +++ b/sensors/Pedometer/Pedometer.def @@ -0,0 +1,6 @@ +; Pedometer.def : Declares the module parameters. + +LIBRARY Pedometer + +EXPORTS + diff --git a/sensors/Pedometer/Pedometer.inx b/sensors/Pedometer/Pedometer.inx new file mode 100644 index 00000000..5d8bc1e8 --- /dev/null +++ b/sensors/Pedometer/Pedometer.inx @@ -0,0 +1,95 @@ +/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +;Module Name: +; Pedometer.INF +; +;Abstract: +; INF file for installing the Sensors 2.0 Pedometer sample driver +; +;Installation Notes: +; Using Devcon: Type "devcon install Pedometer.inf umdf2\Pedometer" to install +; +;--*/ + +[Version] +Signature = "$WINDOWS NT$" +Class = Sensor +ClassGuid = {5175D334-C371-4806-B3BA-71FD53C9258D} +Provider = %MSFT% +CatalogFile = Pedometer.cat +DriverVer = 09/09/2014,2.00.00.01 + +[DestinationDirs] +;12 == Windows\System32\Drivers\UMDF +DefaultDestDir = 12,UMDF + +[SourceDisksNames] +1 = %MediaDescription%,,,"" + +[SourceDisksFiles] +Pedometer.dll = 1,, + +[Manufacturer] +%MSFT% = Pedometer_Device, NT$ARCH$ + +;******************************* +; Pedometer Install Section +;******************************* + +[Pedometer_Device.NT$ARCH$] +; DisplayName Section DeviceId +; ----------- ------- -------- +%Pedometer_DevDesc% = Pedometer_Inst, umdf2\Pedometer + +[Pedometer_Inst.NT] +CopyFiles = PedometerDriverCopy + +[PedometerDriverCopy] +Pedometer.dll + +[DestinationDirs] +PedometerDriverCopy = 12,UMDF + +;-------------- Service installation + +[Pedometer_Inst.NT.Services] +AddService = WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[Pedometer_Inst.NT.CoInstallers] +AddReg = CoInstallers_AddReg + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = %SERVICE_KERNEL_DRIVER% +StartType = %SERVICE_DEMAND_START% +ErrorControl = %SERVICE_ERROR_NORMAL% +ServiceBinary = %12%\WUDFRd.sys + +;-------------- WDF specific section + +[Pedometer_Inst.NT.Wdf] +UmdfService = Pedometer, Pedometer_Install +UmdfServiceOrder = Pedometer +UmdfDirectHardwareAccess = AllowDirectHardwareAccess +UmdfFileObjectPolicy = AllowNullAndUnknownFileObjects +UmdfFsContextUsePolicy = CannotUseFsContexts + +[Pedometer_Install] +UmdfLibraryVersion = $UMDFVERSION$ +ServiceBinary = %12%\UMDF\Pedometer.dll +UmdfExtensions = SensorsCx0102 + +[CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WudfCoinstaller.dll" + +[Strings] +MediaDescription = "Windows Pedometer Driver" +MSFT = "Microsoft" +Pedometer_DevDesc = "Pedometer" +WudfRdDisplayName = "Windows Driver Foundation - User-mode Driver Framework Reflector" + +SERVICE_KERNEL_DRIVER = 1 +SERVICE_DEMAND_START = 3 +SERVICE_ERROR_NORMAL = 1 diff --git a/sensors/Pedometer/Pedometer.sln b/sensors/Pedometer/Pedometer.sln new file mode 100644 index 00000000..2dd26c5d --- /dev/null +++ b/sensors/Pedometer/Pedometer.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Pedometer", "Pedometer.vcxproj", "{F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Debug|Win32.ActiveCfg = Debug|Win32 + {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Debug|Win32.Build.0 = Debug|Win32 + {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Release|Win32.ActiveCfg = Release|Win32 + {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Release|Win32.Build.0 = Release|Win32 + {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Debug|x64.ActiveCfg = Debug|x64 + {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Debug|x64.Build.0 = Debug|x64 + {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Release|x64.ActiveCfg = Release|x64 + {F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/sensors/Pedometer/Pedometer.vcxproj b/sensors/Pedometer/Pedometer.vcxproj new file mode 100644 index 00000000..50315746 --- /dev/null +++ b/sensors/Pedometer/Pedometer.vcxproj @@ -0,0 +1,205 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{F82B1ED1-FCD9-4DE5-8B5E-B9054AE4A9AC}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{4F24B4B2-7CA4-4BE0-BB9D-B4CC91C80B55}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="client.cpp; device.cpp; driver.cpp; hardwaresimulator.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppModuleName>Pedometer</WppModuleName> + <WppScanConfigurationData>sensorstrace.h</WppScanConfigurationData> + </ClCompile> + <Inf Include="Pedometer.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\Pedometer.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>Pedometer</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>Pedometer</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>Pedometer</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>Pedometer</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib;$(SDK_LIB_PATH)\propsys.lib;$(SDK_LIB_PATH)\sensors\1.1\sensorscxstub.lib;$(SDK_LIB_PATH)\sensorsutils.lib</AdditionalDependencies> + <ModuleDefinitionFile>Pedometer.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib;$(SDK_LIB_PATH)\propsys.lib;$(SDK_LIB_PATH)\sensors\1.1\sensorscxstub.lib;$(SDK_LIB_PATH)\sensorsutils.lib</AdditionalDependencies> + <ModuleDefinitionFile>Pedometer.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib;$(SDK_LIB_PATH)\propsys.lib;$(SDK_LIB_PATH)\sensors\1.1\sensorscxstub.lib;$(SDK_LIB_PATH)\sensorsutils.lib</AdditionalDependencies> + <ModuleDefinitionFile>Pedometer.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE;WPP_MACRO_USE_KM_VERSION_FOR_UM</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH)\sensors\1.1;$(SDK_INC_PATH)\sensors\1.1</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib;$(SDK_LIB_PATH)\propsys.lib;$(SDK_LIB_PATH)\sensors\1.1\sensorscxstub.lib;$(SDK_LIB_PATH)\sensorsutils.lib</AdditionalDependencies> + <ModuleDefinitionFile>Pedometer.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/sensors/Pedometer/Pedometer.vcxproj.Filters b/sensors/Pedometer/Pedometer.vcxproj.Filters new file mode 100644 index 00000000..b45b352a --- /dev/null +++ b/sensors/Pedometer/Pedometer.vcxproj.Filters @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{F3D96445-84BA-479E-83E8-22EC66AD5C7C}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{FDF8BD7D-FF71-4B97-AF7B-53FC2AC03D64}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{568E7CBB-7EE9-4E95-96A3-2BD5EEAC74B7}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{C8552346-5082-4BEA-9395-FD366C835F18}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="client.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="hardwaresimulator.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="Pedometer.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\Pedometer.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include="Pedometer.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/sensors/Pedometer/ReadMe.md b/sensors/Pedometer/ReadMe.md new file mode 100644 index 00000000..10349781 --- /dev/null +++ b/sensors/Pedometer/ReadMe.md @@ -0,0 +1,7 @@ +Pedometer +========= + +The Pedometer sample shows how to write a UMDF v2 driver to control a virtual Pedometer sensor. + +## Universal Compliant +This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. diff --git a/sensors/Pedometer/SensorsTrace.h b/sensors/Pedometer/SensorsTrace.h new file mode 100644 index 00000000..bc81e33f --- /dev/null +++ b/sensors/Pedometer/SensorsTrace.h @@ -0,0 +1,93 @@ +//Copyright (C) Microsoft Corporation, All Rights Reserved +// +//Abstract: +// +// Header file for the debug tracing related function defintions and macros. +// +//Environment: +// +// User mode + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// Define the tracing flags. +// +// Tracing GUID - 0E08A3BA-F045-44EE-B00C-292C91C5F95A + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + PedometerTraceGuid, (0E08A3BA,F045,44EE,B00C,292C91C5F95A), \ + WPP_DEFINE_BIT(EntryExit) \ + WPP_DEFINE_BIT(DataFlow) \ + WPP_DEFINE_BIT(Verbose) \ + WPP_DEFINE_BIT(Information) \ + WPP_DEFINE_BIT(Warning) \ + WPP_DEFINE_BIT(Error) \ + WPP_DEFINE_BIT(Fatal) \ + WPP_DEFINE_BIT(DriverStatus) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) (WPP_LEVEL_ENABLED(flag) && WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +#define WPP_LEVEL_FLAGS_LOGGER(level,flags) WPP_LEVEL_LOGGER(flags) + +#define WPP_LEVEL_FLAGS_ENABLED(level, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= level) + +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// +// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); +// +// FUNC TraceFatal{LEVEL=TRACE_LEVEL_FATAL,FLAGS=Fatal}(MSG,...); +// FUNC TraceError{LEVEL=TRACE_LEVEL_ERROR,FLAGS=Error}(MSG,...); +// FUNC TraceWarning{LEVEL=TRACE_LEVEL_WARNING,FLAGS=Warning}(MSG,...); +// FUNC TraceInformation{LEVEL=TRACE_LEVEL_INFORMATION,FLAGS=Information}(MSG,...); +// FUNC TraceVerbose{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=Verbose}(MSG,...); +// FUNC TracePerformance{PERF=DUMMY,LEVEL=TRACE_LEVEL_PERF}(FLAGS,MSG,...); +// +// FUNC TraceData{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=DataFlow}(MSG,...); +// +// FUNC TraceDriverStatus{LEVEL=TRACE_LEVEL_INFORMATION,FLAGS=DriverStatus}(MSG,...); +// +// end_wpp + + + +// SENSOR ------------------------------------------------------------------------------------------------ + +// MACRO: SENSOR_FunctionEnter +// +// begin_wpp config +// USEPREFIX (SENSOR_FunctionEnter, "%!STDPREFIX! SENSOR %!FUNC! FunctionEnter"); +// FUNC SENSOR_FunctionEnter{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=EntryExit}(...); +// end_wpp + + +// MACRO: SENSOR_FunctionExit +// +// begin_wpp config +// USEPREFIX (SENSOR_FunctionExit, "%!STDPREFIX! SENSOR %!FUNC! FunctionExit: %!STATUS!", __status); +// FUNC SENSOR_FunctionExit{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=EntryExit}(SENSOREXIT); +// end_wpp +#define WPP_LEVEL_FLAGS_SENSOREXIT_ENABLED(LEVEL, FLAGS, status) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_SENSOREXIT_LOGGER(LEVEL, FLAGS, status) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_SENSOREXIT_PRE(LEVEL, FLAGS, status) { \ + NTSTATUS __status = status; +#define WPP_LEVEL_FLAGS_SENSOREXIT_POST(LEVEL, FLAGS, status) /*TraceMessage()*/; \ + } + + +#ifdef __cplusplus +} +#endif + + diff --git a/sensors/Pedometer/client.cpp b/sensors/Pedometer/client.cpp new file mode 100644 index 00000000..1fc79a9d --- /dev/null +++ b/sensors/Pedometer/client.cpp @@ -0,0 +1,1224 @@ +//Copyright (C) Microsoft Corporation, All Rights Reserved. +// +//Abstract: +// +// This module contains the implementation of driver callback function +// from clx to pedometer. +// +//Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#include "Device.h" +#include "HardwareSimulator.h" + +#include <timeapi.h> +#include <Intsafe.h> + +#include "Client.tmh" + +// This routine is called by worker thread to read a single sample, compare threshold +// and push it back to CLX. It simulates hardware thresholding by only generating data +// when the change of data is greater than threshold. +NTSTATUS +PedometerDevice::GetData( +) +{ + PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance); + BOOLEAN DataReady = FALSE; + NTSTATUS Status = STATUS_SUCCESS; + ULONG CachedStepCountLimit = 0; + ULONG LastStepCountLimit = 0; + PedometerSample Sample = {}; + + SENSOR_FunctionEnter(); + + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + Status = pSimulator->GetSample(&Sample); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! GetSample failed %!STATUS!", Status); + goto Exit; + } + + if (FALSE != m_FirstSample) + { + Status = GetPerformanceTime(&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("PED %!FUNC! GetPerformanceTime failed %!STATUS!", Status); + } + + DataReady = TRUE; + } + else + { + if (0 == m_CachedThreshold || FALSE != Sample.IsFirstAfterReset) + { + // Streaming mode + DataReady = TRUE; + } + else + { + if (FAILED(ULongAdd(Sample.UnknownStepCount, Sample.WalkingStepCount, &CachedStepCountLimit)) || + FAILED(ULongAdd(Sample.RunningStepCount, CachedStepCountLimit, &CachedStepCountLimit))) + { + // If an overflow happened, we assume we reached the threshold + // in other words, there is no threshold value that can be larger + // than an overflowed value. + DataReady = TRUE; + } + else if (FAILED(ULongAdd(m_LastSample.UnknownStepCount, m_LastSample.WalkingStepCount, &LastStepCountLimit)) || + FAILED(ULongAdd(m_LastSample.RunningStepCount, LastStepCountLimit, &LastStepCountLimit))) + { + // If an overflow happened, we assume we reached the threshold + // in other words, there is no threshold value that can be larger + // than an overflowed value. + DataReady = TRUE; + } + else if ((LastStepCountLimit < m_CachedThreshold && CachedStepCountLimit >= m_CachedThreshold) || + (FALSE != Sample.IsFirstAfterReset)) + { + // Compare the change of data to threshold, and only push the data back to + // clx if the change exceeds threshold or if this is the first sample after reset. This is usually done in HW. + DataReady = TRUE; + } + } + } + + if (FALSE != DataReady) + { + // update last sample + m_LastSample = Sample; + + // push to clx + InitPropVariantFromBoolean(m_LastSample.IsFirstAfterReset, &(m_pData->List[PEDOMETER_DATA_FIRST_AFTER_RESET].Value)); + InitPropVariantFromUInt32(PedometerStepType_Unknown, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_TYPE].Value)); + InitPropVariantFromInt64(m_LastSample.UnknownStepDurationMs, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_DURATION].Value)); + InitPropVariantFromUInt32(m_LastSample.UnknownStepCount, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_COUNT].Value)); + InitPropVariantFromUInt32(PedometerStepType_Walking, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_TYPE].Value)); + InitPropVariantFromInt64(m_LastSample.WalkingStepDurationMs, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_DURATION].Value)); + InitPropVariantFromUInt32(m_LastSample.WalkingStepCount, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_COUNT].Value)); + InitPropVariantFromUInt32(PedometerStepType_Running, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_TYPE].Value)); + InitPropVariantFromInt64(m_LastSample.RunningStepDurationMs, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_DURATION].Value)); + InitPropVariantFromUInt32(m_LastSample.RunningStepCount, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_COUNT].Value)); + + // reset IsFirstAfterReset + m_LastSample.IsFirstAfterReset = FALSE; + + InitPropVariantFromFileTime(&m_LastSample.Timestamp, &(m_pData->List[PEDOMETER_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("PED %!FUNC! Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + +Exit: + return Status; +} + + + +// This callback is called when interval wait time has expired and driver is ready +// to collect new sample. The callback reads current value, compare value to threshold, +// pushes it up to CLX framework, and schedule next wake up time. +VOID +PedometerDevice::OnTimerExpire( + _In_ WDFTIMER Timer // WDF timer object + ) +{ + PPedometerDevice pDevice = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + pDevice = GetPedometerContextFromSensorInstance(WdfTimerGetParentObject(Timer)); + if (nullptr == pDevice) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetPedometerContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + // Get data and push to clx + WdfWaitLockAcquire(pDevice->m_Lock, NULL); + Status = pDevice->GetData(); + if (!NT_SUCCESS(Status) && Status != STATUS_DATA_NOT_ACCEPTED) + { + TraceError("PED %!FUNC! GetData Failed %!STATUS!", Status); + } + WdfWaitLockRelease(pDevice->m_Lock); + + // Schedule next wake up time + if (FALSE != pDevice->m_PoweredOn && + FALSE != pDevice->m_Started) + { + LONGLONG WaitTimeHundredNanoseconds = 0; // in unit of 100ns + + if (0 == pDevice->m_StartTime) + { + // in case we fail to get sensor start time, use static wait time + WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); + } + else + { + ULONG CurrentTimeMs = 0; + + // dynamically calculate wait time to avoid jitter + Status = GetPerformanceTime (&CurrentTimeMs); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! GetPerformanceTime %!STATUS!", Status); + WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); + } + else + { + WaitTimeHundredNanoseconds = pDevice->m_Interval - + ((CurrentTimeMs - pDevice->m_StartTime) % pDevice->m_Interval); + WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(WaitTimeHundredNanoseconds); + } + } + WdfTimerStart(pDevice->m_Timer, WaitTimeHundredNanoseconds); + } + +Exit: + + SENSOR_FunctionExit(Status); +} + + + +// Called by Sensor CLX to begin continuously sampling the sensor. +NTSTATUS +PedometerDevice::OnStart( + _In_ SENSOROBJECT SensorInstance // Sensor device object + ) +{ + PHardwareSimulator pSimulator = nullptr; + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT) SensorInstance, Status); + goto Exit; + } + + // Get the simulator context + pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + } + + if (NT_SUCCESS(Status)) + { + // Start the simulator + pSimulator->Start(); + + pDevice->m_FirstSample = TRUE; + + // Start polling + + pDevice->m_Started = TRUE; + + InitPropVariantFromUInt32(SensorState_Active, + &(pDevice->m_pProperties->List[SENSOR_PROPERTY_STATE].Value)); + + // Start the sample polling timer. + // + // Note: The polling timer is configured to allow for the first sample to be reported immediately. + // Some hardware may want to delay the first sample report a little to account for hardware start time. + WdfTimerStart(pDevice->m_Timer, WDF_REL_TIMEOUT_IN_MS(Pedometer_Default_MinDataInterval_Ms)); + } +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// Called by Sensor CLX to stop continuously sampling the sensor. +NTSTATUS +PedometerDevice::OnStop( + _In_ SENSOROBJECT SensorInstance // Sensor device object + ) +{ + PHardwareSimulator pSimulator = nullptr; + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT)SensorInstance, Status); + goto Exit; + } + + // Stop polling + pDevice->m_Started = FALSE; + + // Waiting for the callback to complete, then stopping the timer + WdfTimerStop(pDevice->m_Timer, TRUE); + + InitPropVariantFromUInt32(SensorState_Idle, + &(pDevice->m_pProperties->List[SENSOR_PROPERTY_STATE].Value)); + + // Stop the simulator + pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + pSimulator->Stop(); + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + +// Called by Sensor CLX to begin keeping history +NTSTATUS +PedometerDevice::OnStartHistory( + _In_ SENSOROBJECT SensorInstance // Sensor device object + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + PHardwareSimulator pSimulator = nullptr; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT)SensorInstance, Status); + goto Exit; + } + + if (FALSE == pDevice->m_HistorySupported) + { + Status = STATUS_NOT_SUPPORTED; + TraceError("PED %!FUNC! History is not supported by the HW"); + goto Exit; + } + + if (FALSE == pDevice->m_PoweredOn) + { + Status = STATUS_DEVICE_NOT_READY; + TraceError("PED %!FUNC! Sensor is not powered on! %!STATUS!", Status); + goto Exit; + } + + pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); + + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + // Start the pedometer history + Status = pSimulator->StartHistory(); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! Start History failed %!STATUS!", Status); + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// Called by Sensor CLX to stop keeping history. +NTSTATUS +PedometerDevice::OnStopHistory( + _In_ SENSOROBJECT SensorInstance // Sensor device object + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + PHardwareSimulator pSimulator = nullptr; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT)SensorInstance, Status); + goto Exit; + } + + if (FALSE == pDevice->m_HistorySupported) + { + Status = STATUS_NOT_SUPPORTED; + TraceError("PED %!FUNC! History is not supported by the HW"); + goto Exit; + } + + pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); + + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + // Stop the pedometer history + Status = pSimulator->StopHistory(); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! Stop History failed %!STATUS!", Status); + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + +// Resets the pedometer to its initial values. +VOID +PedometerDevice::ResetPedometer() +{ + NTSTATUS Status = STATUS_SUCCESS; + PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance); + + SENSOR_FunctionEnter(); + + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + } + else + { + // Reset the pedometer + pSimulator->Reset(); + } + + SENSOR_FunctionExit(Status); +} + +// Called by Sensor CLX to clear all history stored in the sensor. +NTSTATUS +PedometerDevice::OnClearHistory( + _In_ SENSOROBJECT SensorInstance // Sensor device object + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + PHardwareSimulator pSimulator; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT)SensorInstance, Status); + goto Exit; + } + + if (FALSE == pDevice->m_HistorySupported) + { + Status = STATUS_NOT_SUPPORTED; + TraceError("PED %!FUNC! History is not supported by the HW"); + goto Exit; + } + + pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); + + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + // Clear the pedometer history + Status = pSimulator->ClearHistory(); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! Clear History failed %!STATUS!", Status); + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// Called by Sensor CLX to start retrieving history. +// +// Arguments: +// SensorInstance: IN: +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +PedometerDevice::OnStartHistoryRetrieval( + _In_ SENSOROBJECT SensorInstance, // sensor device object + _Inout_updates_bytes_(HistorySizeInBytes) PSENSOR_COLLECTION_LIST pHistoryBuffer, // Pointer to a buffer containing the history elements + _In_ ULONG HistorySizeInBytes // Size of the pHistoryBuffer buffer in bytes + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + BOOLEAN IsLocked = FALSE; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT)SensorInstance, Status); + goto Exit; + } + + if (FALSE == pDevice->m_HistorySupported) + { + Status = STATUS_NOT_SUPPORTED; + TraceError("PED %!FUNC! History is not supported by the HW"); + goto Exit; + } + + // Check if the previously created history retrieval thread finished. + // When StartHistoryRetrieval is called again before we signal to CLX that history retrieval is + // completed, fail the second call. + WdfWaitLockAcquire(pDevice->m_Lock, NULL); + BOOLEAN IsStarted = pDevice->m_HistoryRetrievalStarted; + WdfWaitLockRelease(pDevice->m_Lock); + + if (FALSE != IsStarted) + { + Status = STATUS_DEVICE_BUSY; + TraceError("PED %!FUNC! StartHistoryRetrieval called again before the previous call" + "finishes retrieving history %!STATUS!", Status); + goto Exit; + } + + // check that the buffer is not null + if (NULL == pHistoryBuffer) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! History buffer cannot be NULL. %!STATUS!", Status); + goto Exit; + } + + // check that the buffer can hold at least one record + if (HistorySizeInBytes < pDevice->m_HistoryMarshalledRecordSize) + { + Status = STATUS_BUFFER_TOO_SMALL; + TraceError("PED %!FUNC! History buffer is too small to even fill one complete entry. %!STATUS!", Status); + goto Exit; + } + + // Before creating a new thread, close handle to the previously created thread. + if (NULL != pDevice->m_hThread) + { + CloseHandle(pDevice->m_hThread); + pDevice->m_hThread = NULL; + } + + pDevice->m_ClientHistoryBuffer = pHistoryBuffer; + pDevice->m_ClientHistoryBufferSize = HistorySizeInBytes; + + WdfWaitLockAcquire(pDevice->m_Lock, NULL); + IsLocked = TRUE; + + // Create a new thread to retrieve data from the driver's history buffer + pDevice->m_hThread = CreateThread(NULL, // thread attributes + 0, // default stack size + HistoryRetrievalThread, //start address + reinterpret_cast<void*>(SensorInstance), // pointer to variable to be passed + 0, // run immediately + NULL); // Thread ID + if (NULL == pDevice->m_hThread) + { + Status = STATUS_UNSUCCESSFUL; + TraceError("PED %!FUNC! CreateThread Failed %!STATUS!", Status); + goto Exit; + } + + pDevice->m_HistoryRetrievalStarted = TRUE; + WdfWaitLockRelease(pDevice->m_Lock); + IsLocked = FALSE; + +Exit: + SENSOR_FunctionExit(Status); + + if (nullptr != pDevice) + { + if (FALSE != IsLocked) + { + WdfWaitLockRelease(pDevice->m_Lock); + } + + if (!NT_SUCCESS(Status) && NULL != pDevice->m_hThread) + { + CloseHandle(pDevice->m_hThread); + pDevice->m_hThread = NULL; + } + } + + return Status; +} + + + +// Called by Sensor CLX to cancel history retrieval. +NTSTATUS +PedometerDevice::OnCancelHistoryRetrieval( + _In_ SENSOROBJECT SensorInstance, // sensor device object + _Out_ PULONG pBytesWritten // Upon exit, contains the number of bytes written to the history buffer + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + PHardwareSimulator pSimulator = nullptr; + + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || nullptr == pBytesWritten) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Invalid Parameters: Sensor(%08X), pBytesWritten (%08X). Failed %!STATUS!", (INT)SensorInstance, (INT)pBytesWritten, Status); + goto Exit; + } + + if (FALSE == pDevice->m_HistorySupported) + { + Status = STATUS_NOT_SUPPORTED; + TraceError("PED %!FUNC! History is not supported by the HW"); + goto Exit; + } + + *pBytesWritten = 0; + + // Check if history retrieval operation is in progress + WdfWaitLockAcquire(pDevice->m_Lock, NULL); + BOOLEAN IsStarted = pDevice->m_HistoryRetrievalStarted; + WdfWaitLockRelease(pDevice->m_Lock); + + if (FALSE == IsStarted) + { + Status = STATUS_INVALID_DEVICE_REQUEST; + TraceError("PED %!FUNC! History retrieval is not in progress %!STATUS!", Status); + goto Exit; + } + + // Get the simulator context + pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + } + + Status = pSimulator->SignalReadCancellation(); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! Failed to cancel history retrieval from HW %!STATUS!", Status); + } + + // Wait for the history retrieval thread to finish writing the entry since no partial entries are allowed. + DWORD result = WaitForSingleObjectEx(pDevice->m_hThread, Pedometer_TimeoutForHistoryThread_Ms, FALSE); + if (WAIT_OBJECT_0 != result) + { + TraceError("PED %!FUNC! WaitForSingleObjectEx failed with error %d", result); + Status = STATUS_DEVICE_BUSY; + goto Exit; + } + + *pBytesWritten = CollectionsListGetMarshalledSizeWithoutSerialization(pDevice->m_ClientHistoryBuffer); + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// Created on calling StartHistoryRetrieval function +ULONG +WINAPI +PedometerDevice::HistoryRetrievalThread( + _In_ LPVOID lpParam // sensor device object + ) +{ + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + PHardwareSimulator pSimulator = nullptr; + SENSOROBJECT SensorInstance = reinterpret_cast<SENSOROBJECT>(lpParam); + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + ULONG ReturnCode = ERROR_SUCCESS; + PPedometerSample HwHistoryBuffer = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + ULONG FillableCount = 0; + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. pDevice is null", (INT)SensorInstance); + goto Exit; + } + + // Get the simulator context + pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + // Get the number of elements that can actually fit into the provided client buffer. + FillableCount = (pDevice->m_ClientHistoryBufferSize - SENSOR_COLLECTION_LIST_HEADER_SIZE) / (pDevice->m_HistoryMarshalledRecordSize - SENSOR_COLLECTION_LIST_HEADER_SIZE); + + // Allocate enough memory to read the samples from HW + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSOR_POOL_TAG_PEDOMETER, + FillableCount * sizeof(PedometerSample), + &MemoryHandle, + reinterpret_cast<PVOID*>(&HwHistoryBuffer)); + if (!NT_SUCCESS(Status) || nullptr == HwHistoryBuffer) + { + TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + Status = pSimulator->ReadHistory(&FillableCount, HwHistoryBuffer); + if (STATUS_BUFFER_OVERFLOW == Status) + { + // It is okay to return as much as that fits in the buffer. + TraceWarning("PED %!FUNC! Buffer Overflow. More entries available than requested %!STATUS!", Status); + } + else if (STATUS_CANCELLED == Status) + { + TraceWarning("PED %!FUNC! Retrieval canceled. Filling the buffer with retrieved entries %!STATUS!", Status); + } + else if (STATUS_NO_MORE_ENTRIES == Status) + { + TraceInformation("PED %!FUNC! No history entries available %!STATUS!", Status); + goto Exit; + } + else if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! Failed to read history from the HW %!STATUS!", Status); + goto Exit; + } + + // All entries into the client's buffer must be complete i.e. no partial entries are allowed. + for (ULONG index = 0; index < FillableCount; index++) + { + ULONG ElementIndex = 0; + PedometerSample Data = HwHistoryBuffer[index]; + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_TIMESTAMP; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_Timestamp; + InitPropVariantFromFileTime(&(Data.Timestamp), &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_FIRST_AFTER_RESET; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerReset; + InitPropVariantFromBoolean(Data.IsFirstAfterReset, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_UNKNOWN_STEP_TYPE; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerStepType; + InitPropVariantFromUInt32(PedometerStepType_Unknown, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_UNKNOWN_STEP_COUNT; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerStepCount; + InitPropVariantFromUInt32(Data.UnknownStepCount, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_UNKNOWN_STEP_DURATION; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerStepDuration_Ms; + InitPropVariantFromInt64(Data.UnknownStepDurationMs, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_WALKING_STEP_TYPE; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerStepType; + InitPropVariantFromUInt32(PedometerStepType_Walking, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_WALKING_STEP_COUNT; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerStepCount; + InitPropVariantFromUInt32(Data.WalkingStepCount, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_WALKING_STEP_DURATION; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerStepDuration_Ms; + InitPropVariantFromInt64(Data.WalkingStepDurationMs, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_RUNNING_STEP_TYPE; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerStepType; + InitPropVariantFromUInt32(PedometerStepType_Running, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_RUNNING_STEP_COUNT; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerStepCount; + InitPropVariantFromUInt32(Data.RunningStepCount, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + ElementIndex = (index * PEDOMETER_DATA_COUNT) + PEDOMETER_DATA_RUNNING_STEP_DURATION; + pDevice->m_ClientHistoryBuffer->List[ElementIndex].Key = PKEY_SensorData_PedometerStepDuration_Ms; + InitPropVariantFromInt64(Data.RunningStepDurationMs, &(pDevice->m_ClientHistoryBuffer->List[ElementIndex].Value)); + + // Keep the count in the sensor collection list updated + // so that the count is valid even when exit is signaled. + pDevice->m_ClientHistoryBuffer->Count += PEDOMETER_DATA_COUNT; + } + +Exit: + + if (NULL != MemoryHandle) + { + // delete the memory handle and associated memory + WdfObjectDelete(MemoryHandle); + } + + // Update the state before we notify the Sensor CX as we are done with this request at this point + // It would also help should the CX invoke 'EvtSensorStartHistoryRetrieval' on the same thread + WdfWaitLockAcquire(pDevice->m_Lock, NULL); + pDevice->m_HistoryRetrievalStarted = FALSE; + WdfWaitLockRelease(pDevice->m_Lock); + + // call completed method only if retrieval was not canceled + if (STATUS_CANCELLED != Status) + { + SensorsCxSensorHistoryRetrievalCompleted(pDevice->m_SensorInstance, CollectionsListGetMarshalledSizeWithoutSerialization(pDevice->m_ClientHistoryBuffer), Status); + } + + return ReturnCode; +} + + + +// Called by Sensor CLX to get supported data fields. The typical usage is to call +// this function once with buffer pointer as NULL to acquire the required size +// for the buffer, allocate buffer, then call the function again to retrieve +// sensor information. +NTSTATUS +PedometerDevice::OnGetSupportedDataFields( + _In_ SENSOROBJECT SensorInstance, // Sensor device object + _Inout_opt_ PSENSOR_PROPERTY_LIST pFields, // Pointer to a list of supported properties + _Out_ PULONG pSize // Number of bytes for the list of supported properties + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || nullptr == pSize) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Invalid parameters! %!STATUS!", Status); + goto Exit; + } + + if (nullptr == pFields) + { + // Just return size + *pSize = pDevice->m_pSupportedDataFields->AllocatedSizeInBytes; + } + else + { + if (pFields->AllocatedSizeInBytes < pDevice->m_pSupportedDataFields->AllocatedSizeInBytes) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! Buffer is too small. Failed %!STATUS!", Status); + goto Exit; + } + + // Fill out data + Status = PropertiesListCopy(pFields, pDevice->m_pSupportedDataFields); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! PropertiesListCopy failed %!STATUS!", Status); + goto Exit; + } + + *pSize = pDevice->m_pSupportedDataFields->AllocatedSizeInBytes; + } + +Exit: + if (!NT_SUCCESS(Status)) + { + *pSize = 0; + } + SENSOR_FunctionExit(Status); + return Status; +} + + + +// Called by Sensor CLX to get sensor properties. The typical usage is to call +// this function once with buffer pointer as NULL to acquire the required size +// for the buffer, allocate buffer, then call the function again to retrieve +// sensor information. +NTSTATUS +PedometerDevice::OnGetProperties( + _In_ SENSOROBJECT SensorInstance, // Sensor device object + _Inout_opt_ PSENSOR_COLLECTION_LIST pProperties, // Pointer to a list of sensor properties + _Out_ PULONG pSize // Number of bytes for the list of sensor properties + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || nullptr == pSize) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Invalid parameters! %!STATUS!", Status); + goto Exit; + } + + if (nullptr == pProperties) + { + // Just return size + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pProperties); + } + else + { + if (pProperties->AllocatedSizeInBytes < + CollectionsListGetMarshalledSize(pDevice->m_pProperties)) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! Buffer is too small. Failed %!STATUS!", Status); + goto Exit; + } + + // Fill out all data + Status = CollectionsListCopyAndMarshall(pProperties, pDevice->m_pProperties); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status); + goto Exit; + } + + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pProperties); + } + +Exit: + if (!NT_SUCCESS(Status)) + { + *pSize = 0; + } + SENSOR_FunctionExit(Status); + return Status; +} + + +// Called by Sensor CLX to get data field properties. The typical usage is to call +// this function once with buffer pointer as NULL to acquire the required size +// for the buffer, allocate buffer, then call the function again to retrieve +// sensor information. +NTSTATUS +PedometerDevice::OnGetDataFieldProperties( + _In_ SENSOROBJECT SensorInstance, // Sensor device object + _In_ const PROPERTYKEY *DataField, // Pointer to the propertykey of requested property + _Inout_opt_ PSENSOR_COLLECTION_LIST pProperties, // Pointer to a list of sensor properties + _Out_ PULONG pSize // Number of bytes for the list of sensor properties + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || nullptr == pSize || nullptr == DataField) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Invalid parameters! %!STATUS!", Status); + goto Exit; + } + + if ((*DataField == PKEY_SensorData_PedometerStepCount)) + { + if (nullptr == pProperties) + { + // Just return size + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties); + } + else + { + if (pProperties->AllocatedSizeInBytes < + CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties)) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! Buffer is too small. Failed %!STATUS!", Status); + goto Exit; + } + + // Fill out all data + Status = CollectionsListCopyAndMarshall (pProperties, pDevice->m_pDataFieldProperties); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status); + goto Exit; + } + + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties); + } + } + else + { + Status = STATUS_NOT_SUPPORTED; + TraceError("PED %!FUNC! Ped does NOT have properties for this data field. Failed %!STATUS!", Status); + goto Exit; + } + +Exit: + if (!NT_SUCCESS(Status)) + { + *pSize = 0; + } + SENSOR_FunctionExit(Status); + return Status; +} + + + +// Called by Sensor CLX to get sampling rate of the sensor. +NTSTATUS +PedometerDevice::OnGetDataInterval( + _In_ SENSOROBJECT SensorInstance, // Sensor device object + _Out_ PULONG DataRateMs // Sampling rate in ms + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT) SensorInstance, Status); + goto Exit; + } + + if (nullptr == DataRateMs) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! DataRateMs(%08X) parameter is invalid. Failed %!STATUS!", (INT)DataRateMs, Status); + goto Exit; + } + + *DataRateMs = pDevice->m_Interval; + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// Called by Sensor CLX to set sampling rate of the sensor. +NTSTATUS +PedometerDevice::OnSetDataInterval( + _In_ SENSOROBJECT SensorInstance, // Sensor device object + _In_ ULONG DataRateMs // Sampling rate in ms + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || Pedometer_Default_MinDataInterval_Ms > DataRateMs) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT) SensorInstance, Status); + goto Exit; + } + + pDevice->m_Interval = DataRateMs; + + // reschedule sample to return as soon as possible if it's started + if (FALSE != pDevice->m_Started) + { + pDevice->m_Started = FALSE; + WdfTimerStop(pDevice->m_Timer, TRUE); + + pDevice->m_Started = TRUE; + pDevice->m_FirstSample = TRUE; + WdfTimerStart(pDevice->m_Timer, WDF_REL_TIMEOUT_IN_MS(Pedometer_Default_MinDataInterval_Ms)); + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// Called by Sensor CLX to get data thresholds. The typical usage is to call +// this function once with buffer pointer as NULL to acquire the required size +// for the buffer, allocate buffer, then call the function again to retrieve +// sensor information. +NTSTATUS +PedometerDevice::OnGetDataThresholds( + _In_ SENSOROBJECT SensorInstance, // Sensor device object + _Inout_opt_ PSENSOR_COLLECTION_LIST pThresholds, // Pointer to a list of sensor thresholds + _Out_ PULONG pSize // Number of bytes for the list of sensor thresholds + ) +{ + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || nullptr == pSize) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Invalid parameters! %!STATUS!", Status); + goto Exit; + } + + if (nullptr == pThresholds) + { + // Just return size + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pThresholds); + } + else + { + if (pThresholds->AllocatedSizeInBytes < + CollectionsListGetMarshalledSize(pDevice->m_pThresholds)) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! Buffer is too small. Failed %!STATUS!", Status); + goto Exit; + } + + // Fill out all data + Status = CollectionsListCopyAndMarshall(pThresholds, pDevice->m_pThresholds); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status); + goto Exit; + } + + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pThresholds); + } + +Exit: + if (!NT_SUCCESS(Status)) + { + *pSize = 0; + } + + SENSOR_FunctionExit(Status); + + return Status; +} + + + +// Called by Sensor CLX to set data thresholds. +NTSTATUS +PedometerDevice::OnSetDataThresholds( + _In_ SENSOROBJECT SensorInstance, // Sensor device object + _In_ PSENSOR_COLLECTION_LIST pThresholds // Pointer to a list of sensor thresholds + ) +{ + ULONG Element; + BOOLEAN IsLocked = FALSE; + PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (pDevice == nullptr) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT)SensorInstance, Status); + goto Exit; + } + + WdfWaitLockAcquire(pDevice->m_Lock, NULL); + IsLocked = TRUE; + + for (Element = 0; Element < pThresholds->Count; Element++) + { + Status = PropKeyFindKeySetPropVariant(pDevice->m_pThresholds, + &(pThresholds->List[Element].Key), + TRUE, + &(pThresholds->List[Element].Value)); + if (!NT_SUCCESS(Status)) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! Pedometer driver does NOT have threshold for this data field. Failed %!STATUS!", Status); + goto Exit; + } + } + + // Get data thresholds + Status = PropKeyFindKeyGetUlong(pDevice->m_pThresholds, + &PKEY_SensorData_PedometerStepCount, + &(pDevice->m_CachedThreshold)); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! PropKeyFindKeyGetUlong for PedometerStepCount failed! %!STATUS!", Status); + goto Exit; + } + +Exit: + if (FALSE != IsLocked) + { + WdfWaitLockRelease(pDevice->m_Lock); + IsLocked = FALSE; + } + SENSOR_FunctionExit(Status); + return Status; +} + + +// Called by Sensor CLX to handle IOCTLs that clx does not support +NTSTATUS +PedometerDevice::OnIoControl( + _In_ SENSOROBJECT /*SensorInstance*/, // WDF queue object + _In_ WDFREQUEST /*Request*/, // WDF request object + _In_ size_t /*OutputBufferLength*/, // number of bytes to retrieve from output buffer + _In_ size_t /*InputBufferLength*/, // number of bytes to retrieve from input buffer + _In_ ULONG /*IoControlCode*/ // IOCTL control code + ) +{ + NTSTATUS Status = STATUS_NOT_SUPPORTED; + + SENSOR_FunctionEnter(); + + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/Pedometer/device.cpp b/sensors/Pedometer/device.cpp new file mode 100644 index 00000000..8a3c003f --- /dev/null +++ b/sensors/Pedometer/device.cpp @@ -0,0 +1,738 @@ +//Copyright (C) Microsoft Corporation, All Rights Reserved. +// +//Abstract: +// +// This module contains the implementation of WDF callback functions +// for pedometer driver. +// +//Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#include "Device.h" +#include "HardwareSimulator.h" + +#include "Device.tmh" + +// Pedometer Unique ID +// {E3CF8012-53B7-4E3F-9F4E-86C1BCC1B938} +// +// TODO: The unique ID below must be set per sensor. A different GUID must be provided for each sensor. Please generate a new GUID. +DEFINE_GUID(GUID_PedometerDevice_UniqueID, + 0xe3cf8012, 0x53b7, 0x4e3f, 0x9f, 0x4e, 0x86, 0xc1, 0xbc, 0xc1, 0xb9, 0x38); + + +// This routine initializes the sensor to its default properties +NTSTATUS +PedometerDevice::Initialize( + _In_ WDFDEVICE Device, // WDFDEVICE object + _In_ SENSOROBJECT SensorInstance // SENSOROBJECT for each sensor instance + ) +{ + ULONG Size = 0; + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + FILETIME Time = {}; + WDF_OBJECT_ATTRIBUTES TimerAttributes; + WDF_TIMER_CONFIG TimerConfig; + NTSTATUS Status = STATUS_SUCCESS; + PHardwareSimulator pSimulator = nullptr; + ULONG HistorySizeInRecords = 0; + + SENSOR_FunctionEnter(); + + // Store device and instance + m_FxDevice = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + m_HistoryRetrievalStarted = FALSE; + + // Initialize the pedometer simulator + Status = HardwareSimulator::Initialize(Device, &m_SimulatorInstance); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! HardwareSimulator::Initialize failed %!STATUS!", Status); + goto Exit; + } + + pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance); + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + // Create Lock + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + // Create timer object for polling sensor samples + WDF_TIMER_CONFIG_INIT(&TimerConfig, PedometerDevice::OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + + // Supported Data-Fields + Size = SENSOR_PROPERTY_LIST_SIZE(PEDOMETER_DATAFIELD_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSOR_POOL_TAG_PEDOMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pSupportedDataFields)); + if (!NT_SUCCESS(Status) || nullptr == m_pSupportedDataFields) + { + TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = PEDOMETER_DATAFIELD_COUNT; + + m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_FIRST_AFTER_RESET] = PKEY_SensorData_PedometerReset; + m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_STEP_TYPE] = PKEY_SensorData_PedometerStepType; + m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_STEP_COUNT] = PKEY_SensorData_PedometerStepCount; + m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_STEP_DURATION] = PKEY_SensorData_PedometerStepDuration_Ms; + + // Data + Size = SENSOR_COLLECTION_LIST_SIZE(PEDOMETER_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSOR_POOL_TAG_PEDOMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pData)); + if (!NT_SUCCESS(Status) || nullptr == m_pData) + { + TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = PEDOMETER_DATA_COUNT; + + m_pData->List[PEDOMETER_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimeAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[PEDOMETER_DATA_TIMESTAMP].Value)); + + m_pData->List[PEDOMETER_DATA_FIRST_AFTER_RESET].Key = PKEY_SensorData_PedometerReset; + InitPropVariantFromBoolean(FALSE, &(m_pData->List[PEDOMETER_DATA_FIRST_AFTER_RESET].Value)); + + m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_TYPE].Key = PKEY_SensorData_PedometerStepType; + InitPropVariantFromUInt32(static_cast<ULONG>(PedometerStepType_Unknown), &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_TYPE].Value)); + + m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_COUNT].Key = PKEY_SensorData_PedometerStepCount; + InitPropVariantFromUInt32(600, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_COUNT].Value)); + + m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_DURATION].Key = PKEY_SensorData_PedometerStepDuration_Ms; + InitPropVariantFromInt64(123, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_DURATION].Value)); + + m_pData->List[PEDOMETER_DATA_WALKING_STEP_TYPE].Key = PKEY_SensorData_PedometerStepType; + InitPropVariantFromUInt32(static_cast<ULONG>(PedometerStepType_Walking), &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_TYPE].Value)); + + m_pData->List[PEDOMETER_DATA_WALKING_STEP_COUNT].Key = PKEY_SensorData_PedometerStepCount; + InitPropVariantFromUInt32(700, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_COUNT].Value)); + + m_pData->List[PEDOMETER_DATA_WALKING_STEP_DURATION].Key = PKEY_SensorData_PedometerStepDuration_Ms; + InitPropVariantFromInt64(456, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_DURATION].Value)); + + m_pData->List[PEDOMETER_DATA_RUNNING_STEP_TYPE].Key = PKEY_SensorData_PedometerStepType; + InitPropVariantFromUInt32(static_cast<ULONG>(PedometerStepType_Running), &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_TYPE].Value)); + + m_pData->List[PEDOMETER_DATA_RUNNING_STEP_COUNT].Key = PKEY_SensorData_PedometerStepCount; + InitPropVariantFromUInt32(800, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_COUNT].Value)); + + m_pData->List[PEDOMETER_DATA_RUNNING_STEP_DURATION].Key = PKEY_SensorData_PedometerStepDuration_Ms; + InitPropVariantFromInt64(789, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_DURATION].Value)); + + m_LastSample.Timestamp = Time; + m_LastSample.UnknownStepCount = 0; + m_LastSample.UnknownStepDurationMs = 0; + m_LastSample.WalkingStepCount = 0; + m_LastSample.WalkingStepDurationMs = 0; + m_LastSample.RunningStepCount = 0; + m_LastSample.RunningStepDurationMs = 0; + m_LastSample.IsFirstAfterReset = FALSE; + + // Get the History Size to populate 'PKEY_SensorHistory_MaxSize_Bytes' + // Typically the size needed to store a history record on the hardware is + // smaller than the size needed to represent a history record as a + // SENSOR_COLLECTION_LIST (collection of SENSOR_VALUE_PAIRs) + // To be able to accurately represent the size of the history on the + // hardware (simulator in this case), get the number of records that the HW + // can store and multiply it with the marshalled size of + // SENSOR_COLLECTION_LIST needed to represent a single record. + + HistorySizeInRecords = pSimulator->GetHistorySizeInRecords(); + m_HistorySupported = (HistorySizeInRecords > 0) ? TRUE : FALSE; + + // Pedometer History format is exactly same as it's data sample. + // so, we can simply reuse the 'm_pData' to compute the marshalled size + // History Retrieval is not WOW64 compatible and hence will not involve + // serializing the collections list. Should Use + // CollectionsListGetMarshalledSizeWithoutSerialization instead of + // CollectionsListGetMarshalledSize when dealing with History Collection list. + m_HistoryMarshalledRecordSize = CollectionsListGetMarshalledSizeWithoutSerialization(m_pData); + + // Sensor Enumeration Properties + Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ENUMERATION_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSOR_POOL_TAG_PEDOMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pEnumerationProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pEnumerationProperties) + { + TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); + m_pEnumerationProperties->Count = SENSOR_ENUMERATION_PROPERTIES_COUNT; + + m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_Pedometer, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Microsoft", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"PEDOMETER", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_PedometerDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_CATEGORY].Key = DEVPKEY_Sensor_Category; + InitPropVariantFromCLSID(GUID_SensorCategory_Motion, + &(m_pEnumerationProperties->List[SENSOR_CATEGORY].Value)); + + m_pEnumerationProperties->List[SENSOR_POWER].Key = PKEY_Sensor_Power_Milliwatts; + InitPropVariantFromFloat(Pedometer_Default_Power_Milliwatts, + &(m_pEnumerationProperties->List[SENSOR_POWER].Value)); + + m_pEnumerationProperties->List[SENSOR_MAX_HISTORYSIZE].Key = PKEY_SensorHistory_MaxSize_Bytes; + InitPropVariantFromUInt32(((FALSE != m_HistorySupported) ? + (SENSOR_COLLECTION_LIST_HEADER_SIZE + ((m_HistoryMarshalledRecordSize - SENSOR_COLLECTION_LIST_HEADER_SIZE) * HistorySizeInRecords)) : + 0), + &(m_pEnumerationProperties->List[SENSOR_MAX_HISTORYSIZE].Value)); + + m_pEnumerationProperties->List[SENSOR_SUPPORTED_STEPTYPES].Key = PKEY_SensorData_SupportedStepTypes; + InitPropVariantFromUInt32(PedometerStepType_Unknown | PedometerStepType_Walking | PedometerStepType_Running, + &(m_pEnumerationProperties->List[SENSOR_PROPERTY_SUPPORTED_STEPTYPES].Value)); + + // Sensor Properties + m_Interval = Pedometer_Default_MinDataInterval_Ms; + + Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSOR_POOL_TAG_PEDOMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pProperties) + { + TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_COMMON_PROPERTIES_COUNT; + + m_pProperties->List[SENSOR_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(Pedometer_Default_MinDataInterval_Ms, + &(m_pProperties->List[SENSOR_PROPERTY_MIN_INTERVAL].Value)); + + m_pProperties->List[SENSOR_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_PROPERTY_SENSOR_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_Pedometer, + &(m_pProperties->List[SENSOR_PROPERTY_SENSOR_TYPE].Value)); + + m_pProperties->List[SENSOR_PROPERTY_SENSOR_POWER].Key = PKEY_Sensor_Power_Milliwatts; + InitPropVariantFromFloat(Pedometer_Default_Power_Milliwatts, + &(m_pProperties->List[SENSOR_PROPERTY_SENSOR_POWER].Value)); + + m_pProperties->List[SENSOR_PROPERTY_MAX_HISTORYSIZE].Key = PKEY_SensorHistory_MaxSize_Bytes; + InitPropVariantFromUInt32(((FALSE != m_HistorySupported) ? + (SENSOR_COLLECTION_LIST_HEADER_SIZE + ((m_HistoryMarshalledRecordSize - SENSOR_COLLECTION_LIST_HEADER_SIZE) * HistorySizeInRecords)) : + 0), + &(m_pProperties->List[SENSOR_PROPERTY_MAX_HISTORYSIZE].Value)); + + m_pProperties->List[SENSOR_PROPERTY_HISTORY_INTERVAL].Key = PKEY_SensorHistory_Interval_Ms; + InitPropVariantFromUInt32(pSimulator->GetHistoryIntervalInMs(), + &(m_pProperties->List[SENSOR_PROPERTY_HISTORY_INTERVAL].Value)); + + m_pProperties->List[SENSOR_PROPERTY_MAX_HISTROYRECORDSIZE].Key = PKEY_SensorHistory_MaximumRecordSize_Bytes; + InitPropVariantFromUInt32(m_HistoryMarshalledRecordSize, + &(m_pProperties->List[SENSOR_PROPERTY_MAX_HISTROYRECORDSIZE].Value)); + + m_pProperties->List[SENSOR_PROPERTY_SUPPORTED_STEPTYPES].Key = PKEY_SensorData_SupportedStepTypes; + InitPropVariantFromUInt32(PedometerStepType_Unknown | PedometerStepType_Walking | PedometerStepType_Running, + &(m_pProperties->List[SENSOR_PROPERTY_SUPPORTED_STEPTYPES].Value)); + + // Data field properties + Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSOR_POOL_TAG_PEDOMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pDataFieldProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pDataFieldProperties) + { + TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); + m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; + + m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; + InitPropVariantFromInt64(PedometerDevice_StepCount_Resolution, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromUInt32(PedometerDevice_StepCount_Minimum, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromUInt32(PedometerDevice_StepCount_Maximum, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + + // Set default threshold + m_FirstSample = TRUE; + + Size = SENSOR_COLLECTION_LIST_SIZE(PEDOMETER_THRESHOLD_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSOR_POOL_TAG_PEDOMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pThresholds)); + if (!NT_SUCCESS(Status) || nullptr == m_pThresholds) + { + TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = PEDOMETER_THRESHOLD_COUNT; + + m_pThresholds->List[PEDOMETER_THRESHOLD_STEP_COUNT].Key = PKEY_SensorData_PedometerStepCount; + InitPropVariantFromUInt32(Pedometer_Default_Threshold_StepCount, + &(m_pThresholds->List[PEDOMETER_THRESHOLD_STEP_COUNT].Value)); + + m_CachedThreshold = Pedometer_Default_Threshold_StepCount; +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// This routine is the AddDevice entry point for the pedometer client +// driver. This routine is called by the framework in response to AddDevice +// call from the PnP manager. It will create and initialize the device object +// to represent a new instance of the sensor client. +NTSTATUS +PedometerDevice::OnDeviceAdd( + _In_ WDFDRIVER /*Driver*/, // Supplies a handle to the driver object created in DriverEntry + _Inout_ PWDFDEVICE_INIT pDeviceInit // Supplies a pointer to a framework-allocated WDFDEVICE_INIT structure + ) +{ + WDF_PNPPOWER_EVENT_CALLBACKS Callbacks; + WDFDEVICE Device = nullptr; + WDF_OBJECT_ATTRIBUTES FdoAttributes; + ULONG Flag = 0; + SENSOR_CONTROLLER_CONFIG SensorConfig; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + WDF_OBJECT_ATTRIBUTES_INIT(&FdoAttributes); + + // Initialize FDO attributes and set up file object with sensor extension + Status = SensorsCxDeviceInitConfig(pDeviceInit, &FdoAttributes, Flag); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! SensorsCxDeviceInitConfig failed %!STATUS!", Status); + goto Exit; + } + + // Register the PnP callbacks with the framework. + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks); + Callbacks.EvtDevicePrepareHardware = PedometerDevice::OnPrepareHardware; + Callbacks.EvtDeviceReleaseHardware = PedometerDevice::OnReleaseHardware; + Callbacks.EvtDeviceD0Entry = PedometerDevice::OnD0Entry; + Callbacks.EvtDeviceD0Exit = PedometerDevice::OnD0Exit; + + WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &Callbacks); + + // Call the framework to create the device + Status = WdfDeviceCreate(&pDeviceInit, &FdoAttributes, &Device); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! WdfDeviceCreate failed %!STATUS!", Status); + goto Exit; + } + + // Register CLX callback function pointers + SENSOR_CONTROLLER_CONFIG_INIT(&SensorConfig); + SensorConfig.DriverIsPowerPolicyOwner = WdfUseDefault; + + SensorConfig.EvtSensorStart = PedometerDevice::OnStart; + SensorConfig.EvtSensorStop = PedometerDevice::OnStop; + SensorConfig.EvtSensorGetSupportedDataFields = PedometerDevice::OnGetSupportedDataFields; + SensorConfig.EvtSensorGetDataInterval = PedometerDevice::OnGetDataInterval; + SensorConfig.EvtSensorSetDataInterval = PedometerDevice::OnSetDataInterval; + SensorConfig.EvtSensorGetDataFieldProperties = PedometerDevice::OnGetDataFieldProperties; + SensorConfig.EvtSensorGetDataThresholds = PedometerDevice::OnGetDataThresholds; + SensorConfig.EvtSensorSetDataThresholds = PedometerDevice::OnSetDataThresholds; + SensorConfig.EvtSensorGetProperties = PedometerDevice::OnGetProperties; + SensorConfig.EvtSensorDeviceIoControl = PedometerDevice::OnIoControl; + SensorConfig.EvtSensorStartHistory = PedometerDevice::OnStartHistory; + SensorConfig.EvtSensorStopHistory = PedometerDevice::OnStopHistory; + SensorConfig.EvtSensorClearHistory = PedometerDevice::OnClearHistory; + SensorConfig.EvtSensorStartHistoryRetrieval = PedometerDevice::OnStartHistoryRetrieval; + SensorConfig.EvtSensorCancelHistoryRetrieval = PedometerDevice::OnCancelHistoryRetrieval; + + // Set up power capabilities and IO queues + Status = SensorsCxDeviceInitialize(Device, &SensorConfig); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! SensorsCxDeviceInitialize failed %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// This routine is called by the framework when the PnP manager sends an +// IRP_MN_START_DEVICE request to the driver stack. This routine is +// responsible for performing operations that are necessary to make the +// driver's device operational (for e.g. mapping the hardware resources +// into memory). +NTSTATUS +PedometerDevice::OnPrepareHardware( + _In_ WDFDEVICE Device, // Supplies a handle to the framework device object + _In_ WDFCMRESLIST /*ResourcesRaw*/, // Supplies a handle to a collection of framework resource + // objects. This collection identifies the raw (bus-relative) hardware + // resources that have been assigned to the device. + _In_ WDFCMRESLIST /*ResourcesTranslated*/) // Supplies a handle to a collection of framework + // resource objects. This collection identifies the translated + // (system-physical) hardware resources that have been assigned to the + // device. The resources appear from the CPU's point of view. +{ + PPedometerDevice pDevice = nullptr; + WDF_OBJECT_ATTRIBUTES SensorAttr = {}; + SENSOR_CONFIG SensorConfig = {}; + SENSOROBJECT SensorInstance = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // Construct sensor instance + + // Create WDFOBJECT for the sensor + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&SensorAttr, PedometerDevice); + + // Register sensor instance with clx + + Status = SensorsCxSensorCreate(Device, &SensorAttr, &SensorInstance); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! SensorsCxSensorCreate failed %!STATUS!", Status); + goto Exit; + } + + pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + if (nullptr == pDevice) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetPedometerContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + // Device initialization + + Status = pDevice->Initialize(Device, SensorInstance); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! Initialize device object failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_CONFIG_INIT(&SensorConfig); + SensorConfig.pEnumerationList = pDevice->m_pEnumerationProperties; + Status = SensorsCxSensorInitialize(SensorInstance, &SensorConfig); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! SensorsCxSensorInitialize failed %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + + return Status; +} + + + +// This routine is called by the framework when the PnP manager is revoking +// ownership of our resources. This may be in response to either +// IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. This routine is responsible for +// performing cleanup of resources allocated in PrepareHardware callback. +// This callback is invoked before passing the request down to the lower driver. +// This routine will also be invoked by the framework if the prepare hardware +// callback returns a failure. +// +// Argument: +// Device: IN: Supplies a handle to the framework device object +// ResourcesTranslated: IN: Supplies a handle to a collection of framework +// resource objects. This collection identifies the translated +// (system-physical) hardware resources that have been assigned to the +// device. The resources appear from the CPU's point of view. +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +PedometerDevice::OnReleaseHardware( + _In_ WDFDEVICE Device, // Supplies a handle to the framework device object + _In_ WDFCMRESLIST /*ResourcesTranslated*/) // Supplies a handle to a collection of framework + // resource objects. This collection identifies the translated + // (system-physical) hardware resources that have been assigned to the + // device. The resources appear from the CPU's point of view. +{ + PHardwareSimulator pSimulator = nullptr; + PPedometerDevice pDevice = nullptr; + SENSOROBJECT SensorInstance = nullptr; + ULONG SensorInstanceCount = 1; // only expect 1 sensor instance + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // Get sensor instance + Status = SensorsCxDeviceGetSensorList(Device, &SensorInstance, &SensorInstanceCount); + if (!NT_SUCCESS(Status) || + 0 == SensorInstanceCount || + NULL == SensorInstance) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status); + goto Exit; + } + + pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! GetPedometerContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + // Close handle to history retrieval thread + if (NULL != pDevice->m_hThread) + { + pSimulator->SignalReadCancellation(); + + DWORD result = WaitForSingleObjectEx(pDevice->m_hThread, Pedometer_TimeoutForHistoryThread_Ms, FALSE); + if (WAIT_OBJECT_0 != result) + { + TraceError("PED %!FUNC! WaitForSingleObjectEx failed with error %d", result); + goto Exit; + } + + CloseHandle(pDevice->m_hThread); + pDevice->m_hThread = NULL; + } + + + // Delete lock + if (NULL != pDevice->m_Lock) + { + WdfObjectDelete(pDevice->m_Lock); + pDevice->m_Lock = NULL; + } + + // Cleanup the pedometer simulator + pSimulator->Cleanup(); + + // Delete hardware simulator instance + if (NULL != pDevice->m_SimulatorInstance) + { + WdfObjectDelete(pDevice->m_SimulatorInstance); + pDevice->m_SimulatorInstance = NULL; + } + + // Delete sensor instance + if (NULL != pDevice->m_SensorInstance) + { + WdfObjectDelete(pDevice->m_SensorInstance); + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// This routine is invoked by the framework to program the device to goto +// D0, which is the working state. The framework invokes callback every +// time the hardware needs to be (re-)initialized. This includes after +// IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE, +// and IRP_MN_SET_POWER-D0. +NTSTATUS +PedometerDevice::OnD0Entry( + _In_ WDFDEVICE Device, // Supplies a handle to the framework device object + _In_ WDF_POWER_DEVICE_STATE /*PreviousState*/) // WDF_POWER_DEVICE_STATE-typed enumerator that identifies + // the device power state that the device was in before this transition to D0 +{ + PPedometerDevice pDevice; + SENSOROBJECT SensorInstance = NULL; + ULONG SensorInstanceCount = 1; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // Get sensor instance + Status = SensorsCxDeviceGetSensorList(Device, &SensorInstance, &SensorInstanceCount); + if (!NT_SUCCESS(Status) || + 0 == SensorInstanceCount || + NULL == SensorInstance) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status); + goto Exit; + } + + pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! GetPedometerContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + // + // Power on sensor + // + pDevice->m_PoweredOn = TRUE; + InitPropVariantFromUInt32(SensorState_Idle, + &(pDevice->m_pProperties->List[SENSOR_PROPERTY_STATE].Value)); + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +// This routine is invoked by the framework to program the device to go into +// a certain Dx state. The framework invokes callback every the the device is +// leaving the D0 state, which happens when the device is stopped, when it is +// removed, and when it is powered off. +NTSTATUS +PedometerDevice::OnD0Exit( + _In_ WDFDEVICE Device, // Supplies a handle to the framework device object + _In_ WDF_POWER_DEVICE_STATE /*TargetState*/) // Supplies the device power state which the device will be put + // in once the callback is complete +{ + PPedometerDevice pDevice; + SENSOROBJECT SensorInstance = NULL; + ULONG SensorInstanceCount = 1; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // Get sensor instance + Status = SensorsCxDeviceGetSensorList(Device, &SensorInstance, &SensorInstanceCount); + if (!NT_SUCCESS(Status) || + 0 == SensorInstanceCount || + NULL == SensorInstance) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status); + goto Exit; + } + + pDevice = GetPedometerContextFromSensorInstance(SensorInstance); + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("PED %!FUNC! GetPedometerContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + // + // Power on sensor + // + pDevice->m_PoweredOn = FALSE; + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} diff --git a/sensors/Pedometer/driver.cpp b/sensors/Pedometer/driver.cpp new file mode 100644 index 00000000..d9fb3ca2 --- /dev/null +++ b/sensors/Pedometer/driver.cpp @@ -0,0 +1,76 @@ +//Copyright (C) Microsoft Corporation, All Rights Reserved. +// +//Abstract: +// +// This module contains the implementation of entry and exit point of pedometer sample driver. +// +//Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#include "Device.h" +#include "Driver.h" + +#include "Driver.tmh" + + + +// This routine is the driver initialization entry point. +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, // Pointer to the driver object created by the I/O manager + _In_ PUNICODE_STRING RegistryPath // Pointer to the driver specific registry key + ) +{ + WDF_DRIVER_CONFIG DriverConfig; + NTSTATUS Status = STATUS_SUCCESS; + + // Initialize WPP Tracing + WPP_INIT_TRACING(DriverObject, NULL); + + SENSOR_FunctionEnter(); + + DriverConfig.DriverPoolTag = SENSOR_POOL_TAG_PEDOMETER; + + // Initialize the driver configuration structure. + WDF_DRIVER_CONFIG_INIT(&DriverConfig, PedometerDevice::OnDeviceAdd); + DriverConfig.EvtDriverUnload = OnDriverUnload; + + // Create a framework driver object to represent our driver. + Status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &DriverConfig, + WDF_NO_HANDLE); + + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! WdfDriverCreate failed: %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + + return Status; +} + + + +// This routine is called when the driver unloads. +VOID +OnDriverUnload( + _In_ WDFDRIVER Driver // Driver object + ) +{ + SENSOR_FunctionEnter(); + + SENSOR_FunctionExit(STATUS_SUCCESS); + + // WPP_CLEANUP doesn't actually use the Driver parameter + // So we need to set it as unreferenced. + UNREFERENCED_PARAMETER(Driver); + WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver)); + + return; +}
\ No newline at end of file diff --git a/sensors/Pedometer/hardwaresimulator.cpp b/sensors/Pedometer/hardwaresimulator.cpp new file mode 100644 index 00000000..6328ea41 --- /dev/null +++ b/sensors/Pedometer/hardwaresimulator.cpp @@ -0,0 +1,677 @@ +//Copyright (C) Microsoft Corporation, All Rights Reserved. +// +//Abstract: +// +// This module contains the implementation of the pedometer sample driver +// hardware simulator. +// +//Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#include "HardwareSimulator.h" + +#include "HardwareSimulator.tmh" + +#include "Device.h" + +// Simulated pedometer data +// The simulation data represent the pedometer data for a user walking and running at different paces +// Since the simulator is designed to report a sample every second, +// each line in the table represents 1 second of data +const PedometerSample SimulatorData[] = { +// 1: Timestamp +// 2: IsFirstSample +// 3: Unknown step count +// 4: Unknown step duration in milliseconds +// 5: Walking step count +// 6: Walking step duration in milliseconds +// 7: Running step count +// 8: Running step duration in milliseconds +// +// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | + { {}, TRUE, 0, 0, 0, 0, 0, 0 }, // the pedometer is reset + { {}, FALSE, 0, 0, 0, 0, 0, 0 }, + { {}, FALSE, 0, 0, 1, 1000, 0, 0 }, // 3 seconds, The user starts walking + { {}, FALSE, 0, 0, 3, 2000, 0, 0 }, + { {}, FALSE, 0, 0, 5, 3000, 0, 0 }, + { {}, FALSE, 0, 0, 7, 4000, 0, 0 }, + { {}, FALSE, 0, 0, 9, 5000, 0, 0 }, + { {}, FALSE, 0, 0, 12, 6000, 0, 0 }, // 8 seconds, the user starts accelerating the foot pace, the sensor hasn't detected a running pace yet + { {}, FALSE, 0, 0, 12, 6000, 3, 1000 }, // 9 seconds, the sensors detects the user is running + { {}, FALSE, 0, 0, 12, 6000, 6, 2000 }, + { {}, FALSE, 0, 0, 12, 6000, 10, 3000 }, + { {}, FALSE, 0, 0, 12, 6000, 14, 4000 }, + { {}, FALSE, 0, 0, 12, 6000, 18, 5000 }, + { {}, FALSE, 0, 0, 12, 6000, 22, 6000 }, + { {}, FALSE, 0, 0, 12, 6000, 25, 7000 }, // 15 seconds, the user starts decelerating + { {}, FALSE, 0, 0, 12, 6000, 27, 8000 }, + { {}, FALSE, 0, 0, 12, 6000, 28, 9000 }, + { {}, FALSE, 0, 0, 13, 7000, 28, 9000 }, // 18 seconds, the user walks again + { {}, FALSE, 0, 0, 14, 8000, 28, 9000 }, + { {}, FALSE, 0, 0, 15, 9000, 28, 9000 }, + { {}, FALSE, 0, 0, 16, 10000, 28, 9000 }, + { {}, FALSE, 0, 0, 16, 10000, 28, 9000 }, // 22 seconds, the user stops walking + { {}, FALSE, 0, 0, 16, 10000, 28, 9000 }, + { {}, FALSE, 0, 0, 16, 10000, 28, 9000 }, +}; + +HardwareSimulator::HardwareSimulator() : + m_HasReset(TRUE), + m_Index(0), + m_Lock(NULL), + m_State(SimulatorState_NotInitialized), + m_SimulatorInstance(NULL), + m_Timer(NULL), + m_HistoryIntervalInMs(0), + m_History({}) +{ +} + +HardwareSimulator::~HardwareSimulator() +{ +} + +// This static routine performs simulator initialization. The routine creates a +// timer object that periodically updates the m_Index location +NTSTATUS +HardwareSimulator::Initialize( + _In_ WDFDEVICE Device, // WDF device representing the sensor + _Out_ WDFOBJECT *SimulatorInstance) // Instance of the WDF object for the simulator +{ + PHardwareSimulator pSimulator = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES HardwareSimulatorAttributes = {}; + + SENSOR_FunctionEnter(); + + // Create WDFOBJECT for the hardware simulator + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&HardwareSimulatorAttributes, HardwareSimulator); + HardwareSimulatorAttributes.ParentObject = Device; + + Status = WdfObjectCreate(&HardwareSimulatorAttributes, SimulatorInstance); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! WdfObjectCreate failed %!STATUS!", Status); + goto Exit; + } + + pSimulator = GetHardwareSimulatorContextFromInstance(*SimulatorInstance); + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + pSimulator->InitializeInternal(*SimulatorInstance); + +Exit: + + SENSOR_FunctionExit(Status); + + return Status; +} + + +// Internal routine to perform simulator initialization +NTSTATUS +HardwareSimulator::InitializeInternal( + _In_ WDFOBJECT SimulatorInstance) // Instance of the WDF object for the simulator +{ + NTSTATUS Status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES TimerAttributes = {}; + WDF_TIMER_CONFIG TimerConfig = {}; + + SENSOR_FunctionEnter(); + + // Only initialize the simulator if it is in the "not initialized" state + if (SimulatorState_NotInitialized == m_State) + { + // Create sample Lock + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + m_Lock = NULL; + + TraceError("PED %!FUNC! WdfWaitLockCreate for m_Lock failed %!STATUS!", Status); + goto Exit; + } + + // Create a timer object for simulation updates + WDF_TIMER_CONFIG_INIT(&TimerConfig, HardwareSimulator::OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SimulatorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + m_Timer = NULL; + + TraceError("PED %!FUNC! WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + + // Create history lock + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_HistoryLock); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + m_HistoryIntervalInMs = Pedometer_Default_HistoryInterval_Ms; + + // Initialize history buffer + m_History.pData = reinterpret_cast<PPedometerSample>(malloc(sizeof(PedometerSample) * Pedometer_Default_MaxHistoryEntries)); + if (nullptr == m_History.pData) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! Allocating circular buffer for history failed %!STATUS!", Status); + goto Exit; + } + m_History.FirstElemIndex = 0; + m_History.LastElemIndex = 0; + m_History.NumOfElems = 0; + m_History.BufferLength = Pedometer_Default_MaxHistoryEntries; + + + // Create an auto-reset event for signaling the busy read to stop + m_HistoryCancelReadEvt = CreateEvent(NULL, FALSE, FALSE, NULL); + if (NULL == m_HistoryCancelReadEvt) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! Failed to create an event %!STATUS!", Status); + goto Exit; + } + + // Create timer object for keeping history + WDF_TIMER_CONFIG_INIT(&TimerConfig, HardwareSimulator::OnHistoryTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SimulatorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_HistoryTimer); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! WdfTimerCreate for history failed %!STATUS!", Status); + goto Exit; + } + + + // Set the simulator state to "initialized" + m_State = SimulatorState_Initialized; + m_SimulatorInstance = SimulatorInstance; + } + +Exit: + if (!NT_SUCCESS(Status) && NULL != m_Lock) + { + WdfObjectDelete(m_Lock); + m_Lock = NULL; + } + + SENSOR_FunctionExit(Status); + + return Status; +} + + +// This routine perform a simulator cleanup +NTSTATUS +HardwareSimulator::Cleanup() +{ + NTSTATUS status = STATUS_SUCCESS; + + if (SimulatorState_Started == m_State) + { + Stop(); + } + + // Delete lock + if (NULL != m_Lock) + { + WdfObjectDelete(m_Lock); + m_Lock = NULL; + } + + // Close handle to Read cancellation event + if (NULL != m_HistoryCancelReadEvt) + { + CloseHandle(m_HistoryCancelReadEvt); + m_HistoryCancelReadEvt = NULL; + } + + + m_History.FirstElemIndex = 0; + m_History.LastElemIndex = 0; + m_History.NumOfElems = 0; + m_History.BufferLength = 0; + + // Delete history buffer + if (nullptr != m_History.pData) + { + free(m_History.pData); + m_History.pData = nullptr; + } + + // Delete history lock + if (NULL != m_HistoryLock) + { + WdfObjectDelete(m_HistoryLock); + m_HistoryLock = NULL; + } + + // Set the simulator state to "not initialized" + m_State = SimulatorState_NotInitialized; + + return status; +} + + +// This routine starts the simulator +NTSTATUS +HardwareSimulator::Start() +{ + NTSTATUS status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (SimulatorState_Initialized == m_State) + { + WdfTimerStart(m_Timer, WDF_REL_TIMEOUT_IN_MS(SIMULATOR_HARDWARE_INTERVAL_MS)); + m_State = SimulatorState_Started; + } + + SENSOR_FunctionExit(status); + + return status; +} + + +// This routine stops the simulator +NTSTATUS +HardwareSimulator::Stop() +{ + NTSTATUS status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (SimulatorState_Started == m_State) + { + WdfTimerStop(m_Timer, TRUE); + m_State = SimulatorState_Initialized; + } + + SENSOR_FunctionExit(status); + + return status; +} + + +// This callback is called when the simulator wait time has expired and the simulator +// is ready to switch to the next sample. The callback updates the sample index and +// schedules the next wake up time. +VOID +HardwareSimulator::OnTimerExpire( + _In_ WDFTIMER Timer) // WDF timer object +{ + HardwareSimulator *pSimulator = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + pSimulator = GetHardwareSimulatorContextFromInstance(WdfTimerGetParentObject(Timer)); + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + } + + if (NT_SUCCESS(Status)) + { + // Increment the sample index, roll over if the index reach the end of the array + WdfWaitLockAcquire(pSimulator->m_Lock, NULL); + pSimulator->m_Index++; + pSimulator->m_Index = pSimulator->m_Index % ARRAYSIZE(SimulatorData); + + if (FALSE != SimulatorData[pSimulator->m_Index].IsFirstAfterReset) + { + pSimulator->m_HasReset = TRUE; + } + + WdfWaitLockRelease(pSimulator->m_Lock); + + WdfTimerStart(pSimulator->m_Timer, WDF_REL_TIMEOUT_IN_MS(SIMULATOR_HARDWARE_INTERVAL_MS)); + } + + SENSOR_FunctionExit(Status); +} + + +// This routine returns the current sample from the driver at the current m_Index +// location +NTSTATUS +HardwareSimulator::GetSample( + _Out_ PedometerSample *Sample) // Pedometer sample +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == Sample) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! Sample parameter is null"); + } + + if (NT_SUCCESS(Status)) + { + WdfWaitLockAcquire(m_Lock, NULL); + *Sample = SimulatorData[m_Index]; + + // The IsFirstAfterReset value should only be true for the first sample after a pedometer reset. + // (Simulator specific) The below makes sure this requirement is respected when multiple calls to GetSample() + // happen in a shorter time than is required by the simulator to switch to the next sample (i.e. if multiple calls + // to GetSample() happen within the same second). + if (FALSE != m_HasReset) + { + Sample->IsFirstAfterReset = TRUE; + m_HasReset = FALSE; + } + else + { + Sample->IsFirstAfterReset = FALSE; + } + + WdfWaitLockRelease(m_Lock); + + GetSystemTimeAsFileTime(&Sample->Timestamp); + } + + SENSOR_FunctionExit(Status); + + return Status; +} + + +// This routine resets the pedometer +NTSTATUS +HardwareSimulator::Reset() +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + WdfWaitLockAcquire(m_Lock, NULL); + m_Index = 0; + WdfWaitLockRelease(m_Lock); + + SENSOR_FunctionExit(Status); + + return Status; +} + + +// This routine is called by history retrieval thread to remove an entry from the history buffer. +// Note this function must be called under lock +_Requires_lock_held_(m_HistoryLock) +NTSTATUS +HardwareSimulator::RemoveDataElemFromHistoryBuffer( + _Out_ PPedometerSample pData // Pedometer data removed from the buffer + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (0 == m_History.NumOfElems) + { + // buffer empty + Status = STATUS_NO_MORE_ENTRIES; + } + else + { + *pData = m_History.pData[m_History.FirstElemIndex]; + m_History.FirstElemIndex++; + m_History.FirstElemIndex %= m_History.BufferLength; + m_History.NumOfElems--; + if (0 == m_History.NumOfElems) + { + // Buffer Empty. 'LastElemIndex' should be same as 'FirstElemIndex' + m_History.LastElemIndex = m_History.FirstElemIndex; + } + } + + return Status; +} + + + +// This routine is called by worker thread to add an entry to the history buffer. +// Note this function must be called under lock +_Requires_lock_held_(m_HistoryLock) +NTSTATUS +HardwareSimulator::AddDataElemToHistoryBuffer( + _In_ PPedometerSample pData // Pedometer data to be added to the buffer + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (0 == m_History.NumOfElems) + { + // buffer empty + m_History.NumOfElems++; + } + else if (m_History.BufferLength > m_History.NumOfElems) + { + // buffer not full yet. Increment the index of the last element in the circular buffer + m_History.LastElemIndex++; + m_History.LastElemIndex %= m_History.BufferLength; + // Increment the num of elements + m_History.NumOfElems++; + } + else if (m_History.BufferLength == m_History.NumOfElems) + { + // buffer full. Over-write the oldest element in the circular buffer + m_History.FirstElemIndex++; + m_History.FirstElemIndex %= m_History.BufferLength; + m_History.LastElemIndex++; + m_History.LastElemIndex %= m_History.BufferLength; + } + + m_History.pData[m_History.LastElemIndex] = *pData; + + return Status; +} + + + +// This callback is called when interval wait time has expired and driver is ready +// to collect new sample. The callback stores pedometer data in history buffer, +// and schedules next wake up time. +VOID +HardwareSimulator::OnHistoryTimerExpire( + _In_ WDFTIMER HistoryTimer // WDF timer object + ) +{ + PHardwareSimulator pSimulator = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + PedometerSample Sample = {}; + + SENSOR_FunctionEnter(); + + pSimulator = GetHardwareSimulatorContextFromInstance(WdfTimerGetParentObject(HistoryTimer)); + + if (nullptr == pSimulator) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); + goto Exit; + } + + // Just use the current sample to store in the history buffer + Status = pSimulator->GetSample(&Sample); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! GetSample failed %!STATUS!", Status); + goto Exit; + } + + WdfWaitLockAcquire(pSimulator->m_HistoryLock, NULL); + + // Add data to the buffer + Status = pSimulator->AddDataElemToHistoryBuffer(&Sample); + if (!NT_SUCCESS(Status)) + { + TraceError("PED %!FUNC! AddDataElemToHistoryBuffer Failed %!STATUS!", Status); + } + WdfWaitLockRelease(pSimulator->m_HistoryLock); + + // Schedule next wake up time + if (FALSE != pSimulator->m_HistoryStarted) + { + WdfTimerStart(pSimulator->m_HistoryTimer, WDF_REL_TIMEOUT_IN_MS(pSimulator->m_HistoryIntervalInMs)); + } + +Exit: + + SENSOR_FunctionExit(Status); +} + +// This routine starts a timer that periodically records the samples to History +NTSTATUS +HardwareSimulator::StartHistory() +{ + NTSTATUS Status = STATUS_SUCCESS; + + WdfWaitLockAcquire(m_HistoryLock, NULL); + + if (FALSE != m_HistoryStarted) + { + Status = STATUS_DEVICE_BUSY; + TraceError("PED %!FUNC! History Collection is already started %!STATUS!", Status); + goto Exit; + } + + // Start keeping history + m_HistoryStarted = TRUE; + + // Start timer + WdfTimerStart(m_HistoryTimer, WDF_REL_TIMEOUT_IN_MS(m_HistoryIntervalInMs)); + +Exit: + + WdfWaitLockRelease(m_HistoryLock); + return Status; +} + +// This routine stops the timer that is responsible for history collection. +NTSTATUS +HardwareSimulator::StopHistory() +{ + WdfWaitLockAcquire(m_HistoryLock, NULL); + + // Stop collecting history + m_HistoryStarted = FALSE; + + // Stop timer + WdfTimerStop(m_HistoryTimer, TRUE); + + WdfWaitLockRelease(m_HistoryLock); + + return STATUS_SUCCESS; +} + +// This routine clears the history collected thus far +NTSTATUS +HardwareSimulator::ClearHistory() +{ + NTSTATUS Status = STATUS_SUCCESS; + + WdfWaitLockAcquire(m_HistoryLock, NULL); + + m_History.FirstElemIndex = 0; + m_History.LastElemIndex = 0; + m_History.NumOfElems = 0; + RtlZeroMemory(m_History.pData, (m_History.BufferLength*sizeof(PedometerSample))); + + // Clearing History should reset the Pedometer + Status = Reset(); + + WdfWaitLockRelease(m_HistoryLock); + + return Status; + +} + +// This routine reads the history collected so far up to a maximum of 'BufferSize' records. +// Once read, those samples will be removed from the History. +// All read samples will be removed from the History buffer +// Any unread samples will continue to persist int the History buffer +NTSTATUS +HardwareSimulator::ReadHistory( + _Inout_ PULONG SamplesCount, + _Out_writes_to_(*SamplesCount, *SamplesCount) PPedometerSample HistorySamplesBuffer + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + ULONG SamplesCopied = 0; + + // Make sure we have sufficient memory to fill in the samples + if (0 == *SamplesCount) + { + Status = STATUS_BUFFER_TOO_SMALL; + goto Exit; + } + + while (*SamplesCount > SamplesCopied) + { + PedometerSample Data = {}; + + // Check whether the Cancel event is signaled before looping through each time to retrieve an entry from the history buffer. + if (WAIT_OBJECT_0 == WaitForSingleObjectEx(m_HistoryCancelReadEvt, 0, FALSE)) + { + TraceError("PED %!FUNC! Read canceled"); + Status = STATUS_CANCELLED; + break; + } + + WdfWaitLockAcquire(m_HistoryLock, NULL); + Status = RemoveDataElemFromHistoryBuffer(&Data); + WdfWaitLockRelease(m_HistoryLock); + + if (!NT_SUCCESS(Status)) + { + break; + } + + HistorySamplesBuffer[SamplesCopied++] = Data; + } + + if (STATUS_NO_MORE_ENTRIES == Status) + { + // Ignore STATUS_NO_MORE_ENTRIES if there were any entries that were copied + if (0 < SamplesCopied) + { + Status = STATUS_SUCCESS; + } + } + else if (*SamplesCount < SamplesCopied) + { + Status = STATUS_BUFFER_OVERFLOW; + } + +Exit: + *SamplesCount = SamplesCopied; + return Status; +} + +// This routine sets an event for the ReadHistory function to exit +// This is for illustration purpose only. For real HW, use an appropriate method to cancel the pending reads. +NTSTATUS +HardwareSimulator::SignalReadCancellation() +{ + SetEvent(m_HistoryCancelReadEvt); + return STATUS_SUCCESS; +} + |
