summaryrefslogtreecommitdiff
path: root/sensors/Pedometer
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /sensors/Pedometer
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'sensors/Pedometer')
-rw-r--r--sensors/Pedometer/Device.h209
-rw-r--r--sensors/Pedometer/Driver.h19
-rw-r--r--sensors/Pedometer/HardwareSimulator.h102
-rw-r--r--sensors/Pedometer/Pedometer.def6
-rw-r--r--sensors/Pedometer/Pedometer.inx95
-rw-r--r--sensors/Pedometer/Pedometer.sln28
-rw-r--r--sensors/Pedometer/Pedometer.vcxproj205
-rw-r--r--sensors/Pedometer/Pedometer.vcxproj.Filters46
-rw-r--r--sensors/Pedometer/ReadMe.md7
-rw-r--r--sensors/Pedometer/SensorsTrace.h93
-rw-r--r--sensors/Pedometer/client.cpp1224
-rw-r--r--sensors/Pedometer/device.cpp738
-rw-r--r--sensors/Pedometer/driver.cpp76
-rw-r--r--sensors/Pedometer/hardwaresimulator.cpp677
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;
+}
+