summaryrefslogtreecommitdiff
path: root/sensors
diff options
context:
space:
mode:
authorWei Mao <[email protected]>2017-03-17 20:14:57 -0700
committerWei Mao <[email protected]>2017-03-17 20:14:57 -0700
commit406cf3e4c6cd251bf69cdd8d7b6433f3477d3980 (patch)
tree15ca9253d190ab5e16cde06526dc17b486f32a22 /sensors
parent1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (diff)
Use lower case
Diffstat (limited to 'sensors')
-rw-r--r--sensors/ADXL345Acc/ADXL345Acc.asl57
-rw-r--r--sensors/ADXL345Acc/ADXL345Acc.def6
-rw-r--r--sensors/ADXL345Acc/ADXL345Acc.inxbin0 -> 5384 bytes
-rw-r--r--sensors/ADXL345Acc/ADXL345Acc.sln28
-rw-r--r--sensors/ADXL345Acc/ADXL345Acc.vcxproj204
-rw-r--r--sensors/ADXL345Acc/ADXL345Acc.vcxproj.Filters40
-rw-r--r--sensors/ADXL345Acc/Device.h190
-rw-r--r--sensors/ADXL345Acc/Driver.h19
-rw-r--r--sensors/ADXL345Acc/Gallery.xml161
-rw-r--r--sensors/ADXL345Acc/SensorsTrace.h110
-rw-r--r--sensors/ADXL345Acc/adxl345.h123
-rw-r--r--sensors/ADXL345Acc/client.cpp1034
-rw-r--r--sensors/ADXL345Acc/device.cpp474
-rw-r--r--sensors/ADXL345Acc/driver.cpp66
-rw-r--r--sensors/Activity/Activity.def6
-rw-r--r--sensors/Activity/Activity.inxbin0 -> 5180 bytes
-rw-r--r--sensors/Activity/Activity.sln28
-rw-r--r--sensors/Activity/Activity.vcxproj204
-rw-r--r--sensors/Activity/Activity.vcxproj.Filters43
-rw-r--r--sensors/Activity/Device.h200
-rw-r--r--sensors/Activity/Driver.h16
-rw-r--r--sensors/Activity/Gallery.xml160
-rw-r--r--sensors/Activity/HardwareSimulator.h49
-rw-r--r--sensors/Activity/SensorsTrace.h102
-rw-r--r--sensors/Activity/client.cpp1021
-rw-r--r--sensors/Activity/device.cpp835
-rw-r--r--sensors/Activity/driver.cpp55
-rw-r--r--sensors/Activity/hardwaresimulator.cpp276
-rw-r--r--sensors/CustomSensors/CustomSensors.def6
-rw-r--r--sensors/CustomSensors/CustomSensors.inxbin0 -> 5464 bytes
-rw-r--r--sensors/CustomSensors/CustomSensors.sln28
-rw-r--r--sensors/CustomSensors/CustomSensors.vcxproj204
-rw-r--r--sensors/CustomSensors/CustomSensors.vcxproj.Filters43
-rw-r--r--sensors/CustomSensors/Device.h138
-rw-r--r--sensors/CustomSensors/Driver.h19
-rw-r--r--sensors/CustomSensors/Gallery.xml168
-rw-r--r--sensors/CustomSensors/HardwareSimulator.h57
-rw-r--r--sensors/CustomSensors/SensorsTrace.h153
-rw-r--r--sensors/CustomSensors/client.cpp611
-rw-r--r--sensors/CustomSensors/device.cpp601
-rw-r--r--sensors/CustomSensors/driver.cpp80
-rw-r--r--sensors/CustomSensors/hardwaresimulator.cpp249
-rw-r--r--sensors/Pedometer/Device.h211
-rw-r--r--sensors/Pedometer/Driver.h19
-rw-r--r--sensors/Pedometer/Gallery.xml160
-rw-r--r--sensors/Pedometer/HardwareSimulator.h102
-rw-r--r--sensors/Pedometer/Pedometer.def6
-rw-r--r--sensors/Pedometer/Pedometer.inxbin0 -> 5234 bytes
-rw-r--r--sensors/Pedometer/Pedometer.sln28
-rw-r--r--sensors/Pedometer/Pedometer.vcxproj204
-rw-r--r--sensors/Pedometer/Pedometer.vcxproj.Filters43
-rw-r--r--sensors/Pedometer/SensorsTrace.h102
-rw-r--r--sensors/Pedometer/client.cpp1242
-rw-r--r--sensors/Pedometer/device.cpp743
-rw-r--r--sensors/Pedometer/driver.cpp76
-rw-r--r--sensors/Pedometer/hardwaresimulator.cpp677
-rw-r--r--sensors/SimpleDeviceOrientationSensor/Device.h137
-rw-r--r--sensors/SimpleDeviceOrientationSensor/Driver.h19
-rw-r--r--sensors/SimpleDeviceOrientationSensor/Gallery.xml160
-rw-r--r--sensors/SimpleDeviceOrientationSensor/HardwareSimulator.h58
-rw-r--r--sensors/SimpleDeviceOrientationSensor/SensorsTrace.h100
-rw-r--r--sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.def6
-rw-r--r--sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.inxbin0 -> 6446 bytes
-rw-r--r--sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.sln28
-rw-r--r--sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj204
-rw-r--r--sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj.Filters43
-rw-r--r--sensors/SimpleDeviceOrientationSensor/client.cpp595
-rw-r--r--sensors/SimpleDeviceOrientationSensor/device.cpp572
-rw-r--r--sensors/SimpleDeviceOrientationSensor/driver.cpp75
-rw-r--r--sensors/SimpleDeviceOrientationSensor/hardwaresimulator.cpp248
70 files changed, 13722 insertions, 0 deletions
diff --git a/sensors/ADXL345Acc/ADXL345Acc.asl b/sensors/ADXL345Acc/ADXL345Acc.asl
new file mode 100644
index 00000000..34acd00e
--- /dev/null
+++ b/sensors/ADXL345Acc/ADXL345Acc.asl
@@ -0,0 +1,57 @@
+// Steps to update the SSDT:
+// 0a. Copy ASL.exe to your development board
+// 0b. Open a command prompt as administrator and navigate to the directory where you have copied ASL.exe
+// 1. Decompile the SSDT ("asl.exe /tab=ssdt")
+// 2. Open ssdt.asl in a text editor
+// 3. Insert a scope entry (e.g. Scope(_SB_) { ADXL345 device node goes here })
+// 4. Compile ssdt.asl ("asl.exe ssdt.asl")
+// 5. Load updated SSDT ("asl /loadtable ssdt.aml")
+// 6. Restart your development board
+
+// ADXL345 accelerometer device node
+Device(SPBA)
+{
+ Name(_HID, "ADXL345Acc")
+ Name(_UID, 1)
+
+ Method(_CRS, 0x0, NotSerialized)
+ {
+ Name(RBUF, ResourceTemplate()
+ {
+ I2CSerialBus(0x53, ControllerInitiated, 400000, AddressingMode7Bit, "\\_SB.I2C3", 0, ResourceConsumer)
+ GpioInt(Edge, ActiveHigh, Exclusive, PullDown, 0, "\\_SB.GPO2") {0x17}
+ })
+ Return(RBUF)
+ } // Method (_CRS ...)
+
+ Method(_DSM, 0x4, NotSerialized)
+ {
+ If(LEqual(Arg0, Buffer(0x10)
+ {
+ 0x1e, 0x54, 0x81, 0x76, 0x27, 0x88, 0x39, 0x42, 0x8d, 0x9d, 0x36, 0xbe, 0x7f, 0xe1, 0x25, 0x42
+ }))
+ {
+ If(LEqual(Arg2, Zero))
+ {
+ Return(Buffer(One)
+ {
+ 0x03
+ })
+ }
+ If(LEqual(Arg2, One))
+ {
+ Return(Buffer(0x4)
+ {
+ 0x00, 0x01, 0x02, 0x03
+ })
+ }
+ }
+ Else
+ {
+ Return(Buffer(One)
+ {
+ 0x00
+ })
+ }
+ } // Method(_DSM ...)
+} // Device(SPBA)
diff --git a/sensors/ADXL345Acc/ADXL345Acc.def b/sensors/ADXL345Acc/ADXL345Acc.def
new file mode 100644
index 00000000..3e2e8f53
--- /dev/null
+++ b/sensors/ADXL345Acc/ADXL345Acc.def
@@ -0,0 +1,6 @@
+; ADXL345Acc.def : Declares the module parameters.
+
+LIBRARY ADXL345Acc
+
+EXPORTS
+
diff --git a/sensors/ADXL345Acc/ADXL345Acc.inx b/sensors/ADXL345Acc/ADXL345Acc.inx
new file mode 100644
index 00000000..8d7649da
--- /dev/null
+++ b/sensors/ADXL345Acc/ADXL345Acc.inx
Binary files differ
diff --git a/sensors/ADXL345Acc/ADXL345Acc.sln b/sensors/ADXL345Acc/ADXL345Acc.sln
new file mode 100644
index 00000000..f3bbe543
--- /dev/null
+++ b/sensors/ADXL345Acc/ADXL345Acc.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}") = "ADXL345Acc", "ADXL345Acc.vcxproj", "{3A526221-1444-46C8-974F-E143021E03DE}"
+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
+ {3A526221-1444-46C8-974F-E143021E03DE}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3A526221-1444-46C8-974F-E143021E03DE}.Debug|Win32.Build.0 = Debug|Win32
+ {3A526221-1444-46C8-974F-E143021E03DE}.Release|Win32.ActiveCfg = Release|Win32
+ {3A526221-1444-46C8-974F-E143021E03DE}.Release|Win32.Build.0 = Release|Win32
+ {3A526221-1444-46C8-974F-E143021E03DE}.Debug|x64.ActiveCfg = Debug|x64
+ {3A526221-1444-46C8-974F-E143021E03DE}.Debug|x64.Build.0 = Debug|x64
+ {3A526221-1444-46C8-974F-E143021E03DE}.Release|x64.ActiveCfg = Release|x64
+ {3A526221-1444-46C8-974F-E143021E03DE}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/sensors/ADXL345Acc/ADXL345Acc.vcxproj b/sensors/ADXL345Acc/ADXL345Acc.vcxproj
new file mode 100644
index 00000000..3e04c33b
--- /dev/null
+++ b/sensors/ADXL345Acc/ADXL345Acc.vcxproj
@@ -0,0 +1,204 @@
+<?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>{3A526221-1444-46C8-974F-E143021E03DE}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{DE16C6D3-2353-458A-96C0-0E2E2FFD8776}</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">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppModuleName>ADXL345Acc</WppModuleName>
+ <WppScanConfigurationData>sensorstrace.h</WppScanConfigurationData>
+ </ClCompile>
+ <Inf Include="ADXL345Acc.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\ADXL345Acc.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>ADXL345Acc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>ADXL345Acc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>ADXL345Acc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>ADXL345Acc</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;$(DDK_INC_PATH)</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;$(DDK_INC_PATH)</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;$(DDK_INC_PATH)</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>ADXL345Acc.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;$(DDK_INC_PATH)</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;$(DDK_INC_PATH)</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;$(DDK_INC_PATH)</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>ADXL345Acc.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;$(DDK_INC_PATH)</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;$(DDK_INC_PATH)</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;$(DDK_INC_PATH)</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>ADXL345Acc.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;$(DDK_INC_PATH)</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;$(DDK_INC_PATH)</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;$(DDK_INC_PATH)</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>ADXL345Acc.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </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/ADXL345Acc/ADXL345Acc.vcxproj.Filters b/sensors/ADXL345Acc/ADXL345Acc.vcxproj.Filters
new file mode 100644
index 00000000..9868db4c
--- /dev/null
+++ b/sensors/ADXL345Acc/ADXL345Acc.vcxproj.Filters
@@ -0,0 +1,40 @@
+<?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>{8B8F5375-2938-477A-A326-BCE6C04EE921}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{A8C574E7-E5DB-4D77-9103-890C1262723A}</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>{2FDE4AFE-6848-41B7-ACF4-3F754E9570F5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{3C84808A-857E-4997-B228-0E9EB21A7A98}</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>
+ <None Include="ADXL345Acc.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="ADXL345Acc.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/sensors/ADXL345Acc/Device.h b/sensors/ADXL345Acc/Device.h
new file mode 100644
index 00000000..e1648227
--- /dev/null
+++ b/sensors/ADXL345Acc/Device.h
@@ -0,0 +1,190 @@
+//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 <reshub.h>
+#include <strsafe.h>
+
+#include <SensorsDef.h>
+#include <SensorsCx.h>
+#include <sensorsutils.h>
+#include <SensorsDriversUtils.h>
+
+#include "Adxl345.h"
+#include "SensorsTrace.h"
+
+
+
+#define SENSORV2_POOL_TAG_ACCELEROMETER '2ccA'
+
+
+// Sensor Common Properties
+typedef enum
+{
+ SENSOR_PROPERTY_STATE = 0,
+ SENSOR_PROPERTY_MIN_DATA_INTERVAL,
+ SENSOR_PROPERTY_MAX_DATA_FIELD_SIZE,
+ SENSOR_PROPERTY_TYPE,
+ SENSOR_PROPERTIES_COUNT
+} SENSOR_PROPERTIES_INDEX;
+
+// Sensor Enumeration Properties
+typedef enum
+{
+ SENSOR_ENUMERATION_PROPERTY_TYPE = 0,
+ SENSOR_ENUMERATION_PROPERTY_MANUFACTURER,
+ SENSOR_ENUMERATION_PROPERTY_MODEL,
+ SENSOR_ENUMERATION_PROPERTY_CONNECTION_TYPE,
+ SENSOR_ENUMERATION_PROPERTY_PERSISTENT_UNIQUE_ID,
+ SENSOR_ENUMERATION_PROPERTY_CATEGORY,
+ SENSOR_ENUMERATION_PROPERTY_ISPRIMARY,
+ SENSOR_ENUMERATION_PROPERTIES_COUNT
+} SENSOR_ENUMERATION_PROPERTIES_INDEX;
+
+// Data-field Properties
+typedef enum
+{
+ SENSOR_DATA_ACCELERATION_X_G = 0,
+ SENSOR_DATA_ACCELERATION_Y_G,
+ SENSOR_DATA_ACCELERATION_Z_G,
+ SENSOR_DATA_TIMESTAMP,
+ SENSOR_DATA_COUNT
+} SENSOR_DATA_INDEX;
+
+typedef enum
+{
+ SENSOR_DATA_FIELD_PROPERTY_RESOLUTION = 0,
+ SENSOR_DATA_FIELD_PROPERTY_RANGE_MIN,
+ SENSOR_DATA_FIELD_PROPERTY_RANGE_MAX,
+ SENSOR_DATA_FIELD_PROPERTIES_COUNT
+} SENSOR_DATA_FIELD_PROPERTIES_INDEX;
+
+typedef struct _REGISTER_SETTING
+{
+ BYTE Register;
+ BYTE Value;
+} REGISTER_SETTING, *PREGISTER_SETTING;
+
+// Return the rate that is just less than the desired report interval
+inline DATA_RATE _GetDataRateFromReportInterval(_In_ ULONG ReportInterval)
+{
+ DATA_RATE dataRate = ACCELEROMETER_SUPPORTED_DATA_RATES[0];
+
+ for (ULONG i = 0; i < ACCELEROMETER_SUPPORTED_DATA_RATES_COUNT; i++)
+ {
+ dataRate = ACCELEROMETER_SUPPORTED_DATA_RATES[i];
+ if (dataRate.DataRateInterval <= ReportInterval)
+ {
+ break;
+ }
+ }
+
+ return dataRate;
+}
+
+// Array of settings that describe the initial device configuration.
+const REGISTER_SETTING g_ConfigurationSettings[] =
+{
+ // Standby mode
+ { ADXL345_POWER_CTL, ADXL345_POWER_CTL_STANDBY },
+ // +-16g, 13-bit resolution
+ { ADXL345_DATA_FORMAT,
+ ADXL345_DATA_FORMAT_FULL_RES | ADXL345_DATA_FORMAT_JUSTIFY_RIGHT | ADXL345_DATA_FORMAT_RANGE_16G },
+ // No FIFO
+ { ADXL345_FIFO_CTL, ADXL345_FIFO_CTL_MODE_BYPASS },
+ // Data rate set to default
+ { ADXL345_BW_RATE, _GetDataRateFromReportInterval(DEFAULT_ACCELEROMETER_REPORT_INTERVAL).RateCode },
+ // Activity threshold set to default change sensitivity
+ { ADXL345_THRESH_ACT,
+ static_cast<BYTE>(DEFAULT_ACCELEROMETER_CHANGE_SENSITIVITY / ACCELEROMETER_CHANGE_SENSITIVITY_RESOLUTION) },
+ // Activity detection enabled, AC coupled
+ { ADXL345_ACT_INACT_CTL,
+ ADXL345_ACT_INACT_CTL_ACT_ACDC | ADXL345_ACT_INACT_CTL_ACT_X | ADXL345_ACT_INACT_CTL_ACT_Y | ADXL345_ACT_INACT_CTL_ACT_Z },
+ // Activity interrupt mapped to pin 1
+ { ADXL345_INT_MAP, ADXL345_INT_ACTIVITY ^ ADXL345_INT_MASK},
+};
+
+
+
+typedef class _ADXL345AccDevice
+{
+private:
+ // WDF
+ WDFDEVICE m_Device;
+ WDFIOTARGET m_I2CIoTarget;
+ WDFWAITLOCK m_I2CWaitLock;
+ WDFINTERRUPT m_Interrupt;
+
+ // Sensor Operation
+ bool m_PoweredOn;
+ bool m_Started;
+ ULONG m_Interval;
+
+ bool m_FirstSample;
+ VEC3D m_CachedThresholds;
+ VEC3D m_LastSample;
+
+ SENSOROBJECT m_SensorInstance;
+
+ // Sensor Specific Properties
+ PSENSOR_PROPERTY_LIST m_pSupportedDataFields;
+ PSENSOR_COLLECTION_LIST m_pEnumerationProperties;
+ PSENSOR_COLLECTION_LIST m_pSensorProperties;
+ PSENSOR_COLLECTION_LIST m_pSensorData;
+ PSENSOR_COLLECTION_LIST m_pDataFieldProperties;
+ PSENSOR_COLLECTION_LIST m_pThresholds;
+
+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;
+
+ // 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;
+
+ // Interrupt callbacks
+ static EVT_WDF_INTERRUPT_ISR OnInterruptIsr;
+ static EVT_WDF_INTERRUPT_WORKITEM OnInterruptWorkItem;
+
+private:
+ NTSTATUS GetData();
+
+ // Helper function for OnPrepareHardware to initialize sensor to default properties
+ NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorInstance);
+ VOID DeInit();
+
+ // Helper function for OnPrepareHardware to get resources from ACPI and configure the I/O target
+ NTSTATUS ConfigureIoTarget(_In_ WDFCMRESLIST ResourceList,
+ _In_ WDFCMRESLIST ResourceListTranslated);
+
+ // Helper function for OnD0Entry which sets up device to default configuration
+ NTSTATUS PowerOn();
+ NTSTATUS PowerOff();
+
+} ADXL345AccDevice, *PADXL345AccDevice;
+
+// Set up accessor function to retrieve device context
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ADXL345AccDevice, GetADXL345AccContextFromSensorInstance); \ No newline at end of file
diff --git a/sensors/ADXL345Acc/Driver.h b/sensors/ADXL345Acc/Driver.h
new file mode 100644
index 00000000..6c069c44
--- /dev/null
+++ b/sensors/ADXL345Acc/Driver.h
@@ -0,0 +1,19 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved
+//
+//Abstract:
+//
+// This module contains the type definitions for the ADXL345 accelerometer
+// 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/ADXL345Acc/Gallery.xml b/sensors/ADXL345Acc/Gallery.xml
new file mode 100644
index 00000000..2d3eabf5
--- /dev/null
+++ b/sensors/ADXL345Acc/Gallery.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="../../buildx/script2/preview.xslt"?>
+<gallery_sample xmlns="http://microsoft.com/wdcml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://microsoft.com/wdcml ../../buildx/schema/xsd/wdcml.xsd">
+ <metadata id="gallery_samples.107a_gallery" type="gallery_sample" msdnID="7cba6311-f0db-4c3d-8f1f-25de8648b353">
+ <title>ADXL345Accelerometer</title>
+ <!-- Add a devlang for each programming language in all versions of the sample. -->
+ <devlang value="cpp" />
+ <!-- Do not change tech value -->
+ <tech value="gallery_samples" />
+ <index />
+ <sample_langs>
+ <!-- Describes the languages to which the sample code itself has been localized. -->
+ <sample_lang xml:lang="en-us" />
+ </sample_langs>
+ </metadata>
+ <content>
+ <desc>
+ <p><abstract>The ADXL345Accelerometer sample shows how to write a UMDF v2 driver to control an ADXL345 accelerometer chip.</abstract></p>
+ </desc>
+ <outline />
+ <license_info>
+ <default_license />
+ </license_info>
+ <programming_models>
+ <programming_model value="win32" />
+ </programming_models>
+ <application_frameworks>
+ </application_frameworks>
+ <!-- For Driver Samples Only -->
+ <driver_models>
+ <!-- possible values: kmdf, umdf, wdm, ndis, wddm -->
+ <driver_model value="UMDF" />
+ </driver_models>
+ <driver_techs>
+ <driver_tech value="Windows Driver" />
+ </driver_techs>
+ <related_techs>
+ </related_techs>
+ <os_requirements>
+ <min_os>
+ <client name="winblue"/>
+ <server name="wbluesrv"/>
+ </min_os>
+ </os_requirements>
+ <required_sdks>
+ <min_sdk>
+ <tla rid="windows_driver_kit_8" />
+ </min_sdk>
+ </required_sdks>
+ <supported_ides>
+ <supported_ide>
+ <tla rid="tla_visualstu2013" />
+ </supported_ide>
+ </supported_ides>
+ <build_info>
+ <authored_instructions>
+ <section>
+ <!-- Include any special instructions for compiling your sample -->
+ <sectioncontents>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </build_info>
+ <run_info>
+ <authored_instructions>
+ <section>
+ <sectioncontents>
+ <p>To install the sample driver, follow these steps:</p>
+ <proch>
+ <item>Ensure that the driver builds without errors.</item>
+ <item>Ensure the appropriate hardware resources have been assigned in the ACPI table using ASL. A device node with HWID ACPI\ADXL345Acc should be created.</item>
+ <item>Copy the DLL and INF files to a separate folder.</item>
+ <item>Enter the command "<inline_code devlang="cmd">devcon.exe update ADXL345Acc.inf ACPI\ADXL345Acc</inline_code>" to install the driver on an existing device node. You can find the devcon.exe program in the tools\devcon folder where you installed the WDK.</item>
+ </proch>
+ </sectioncontents>
+ </section>
+ <section>
+ <title>File manifest</title>
+ <sectioncontents>
+ <p>The following source files are in the src\Sensors\ADXL345Acc folder and are used to build the ADXL345Acc.dll and ADXL345Acc.inf files.</p>
+ <table>
+ <tr>
+ <th>File</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>
+ <p>device.h, device.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's WDF PnP event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>client.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's callback functions from the class extension to the ADXL345 accelerometer.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>driver.h, driver.cpp</p>
+ </td>
+ <td>
+ <p>WDF driver entry event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>ADXL345.h</p>
+ </td>
+ <td>
+ <p>Device specific definitions.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>makefile.inc</p>
+ </td>
+ <td>
+ <p>Defines custom build actions. Includes the conversion of the .INX file into a .INF file.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>SensorsTrace.h</p>
+ </td>
+ <td>
+ <p>Implementation the sensor traces files.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>ADXL345Acc.ctl</p>
+ </td>
+ <td>
+ <p>Declaration of driver's tracing GUID</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>ADXL345Acc.inx</p>
+ </td>
+ <td>
+ <p>Describes the installation of the driver. The build process converts this into a .INF.</p>
+ </td>
+ </tr>
+ </table>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </run_info>
+ </content>
+ <!-- List the component compcentral path -->
+ <feature_teams>
+ <feature_team_info comp_central_path="CORE-OS Core\SiGMa-Silicon, Graphics and Media\SiPlat - Silicon Platform\Sensors" dev_owner="osamasal" writer_owner="ericdoku" />
+ </feature_teams>
+ <workflow_control_host />
+</gallery_sample>
diff --git a/sensors/ADXL345Acc/SensorsTrace.h b/sensors/ADXL345Acc/SensorsTrace.h
new file mode 100644
index 00000000..9e35c9e4
--- /dev/null
+++ b/sensors/ADXL345Acc/SensorsTrace.h
@@ -0,0 +1,110 @@
+//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 - 49b7f554-b812-46ae-8838-c65ee504d4e2
+
+#include <evntrace.h>
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ ADXL345AccDriverTraceGuid, (49b7f554,b812,46ae,8838,c65ee504d4e2), \
+ 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(lvl,flags) \
+ WPP_LEVEL_LOGGER(flags)
+
+#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \
+ (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+
+// Driver specific #defines
+#define DRIVER_TRACING_ID L"Microsoft\\UMDF2.0\\ADXL345Accelerometer V1.0"
+
+// 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()*/; \
+ }
+
+
+
+// WPP Recorder -------------------------------------------------------------------------------------------
+//
+// The following two macros are required to enable WPP Recorder functionality for clients of the Sensor Class Extension
+//
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_FILTER(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS)
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_ARGS(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/sensors/ADXL345Acc/adxl345.h b/sensors/ADXL345Acc/adxl345.h
new file mode 100644
index 00000000..42f44052
--- /dev/null
+++ b/sensors/ADXL345Acc/adxl345.h
@@ -0,0 +1,123 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved
+//
+//Abstract:
+//
+// This module contains the constant definitions for the accelerometer's
+// register interface and default property values.
+
+#pragma once
+
+#include "WTypesbase.h"
+
+
+
+// Register interface
+#define ADXL345_DEVID 0x00
+#define ADXL345_THRESH_TAP 0x1D
+#define ADXL345_OFFSET_X 0x1E
+#define ADXL345_OFFSET_Y 0x1F
+#define ADXL345_OFFSET_Z 0x20
+#define ADXL345_DURATION_TAP 0x21
+#define ADXL345_LATENT_TAP 0x22
+#define ADXL345_WINDOW_TAP 0x23
+#define ADXL345_THRESH_ACT 0x24
+#define ADXL345_THRESH_INACT 0x25
+#define ADXL345_TIME_INACT 0x26
+#define ADXL345_ACT_INACT_CTL 0x27
+#define ADXL345_THRESH_FF 0x28
+#define ADXL345_TIME_FF 0x29
+#define ADXL345_TAP_AXES 0x2A
+#define ADXL345_ACT_TAP_STATUS 0x2B
+#define ADXL345_BW_RATE 0x2C
+#define ADXL345_POWER_CTL 0x2D
+#define ADXL345_INT_ENABLE 0x2E
+#define ADXL345_INT_MAP 0x2F
+#define ADXL345_INT_SOURCE 0x30
+#define ADXL345_DATA_FORMAT 0x31
+#define ADXL345_DATA_X0 0x32
+#define ADXL345_DATA_X1 0x33
+#define ADXL345_DATA_Y0 0x34
+#define ADXL345_DATA_Y1 0x35
+#define ADXL345_DATA_Z0 0x36
+#define ADXL345_DATA_Z1 0x37
+#define ADXL345_FIFO_CTL 0x38
+#define ADXL345_FIFO_STATUS 0x39
+
+// ACT_INACT_CTL register bits
+#define ADXL345_ACT_INACT_CTL_ACT_ACDC 0x80
+#define ADXL345_ACT_INACT_CTL_ACT_X 0x40
+#define ADXL345_ACT_INACT_CTL_ACT_Y 0x20
+#define ADXL345_ACT_INACT_CTL_ACT_Z 0x10
+#define ADXL345_ACT_INACT_CTL_INACT_ACDC 0x08
+#define ADXL345_ACT_INACT_CTL_INACT_X 0x04
+#define ADXL345_ACT_INACT_CTL_INACT_Y 0x02
+#define ADXL345_ACT_INACT_CTL_INACT_Z 0x01
+
+// POWER_CTL register bits
+#define ADXL345_POWER_CTL_STANDBY 0x00
+#define ADXL345_POWER_CTL_MEASURE 0x08
+
+// INT_ENABLE | MAP | SOURCE register bits
+#define ADXL345_INT_MASK 0xFF
+#define ADXL345_INT_DATA_READY 0x80
+#define ADXL345_INT_SINGLE_TAP 0x40
+#define ADXL345_INT_DOUBLE_TAP 0x20
+#define ADXL345_INT_ACTIVITY 0x10
+#define ADXL345_INT_INACTIVITY 0x08
+#define ADXL345_INT_FREEFALL 0x04
+#define ADXL345_INT_WATERMARK 0x02
+#define ADXL345_INT_OVERRUN 0x01
+
+// DATA_FORMAT register bits
+#define ADXL345_DATA_FORMAT_FULL_RES 0x08
+#define ADXL345_DATA_FORMAT_JUSTIFY_RIGHT 0x00
+#define ADXL345_DATA_FORMAT_JUSTIFY_LEFT 0x04
+#define ADXL345_DATA_FORMAT_RANGE_MASK 0x03
+#define ADXL345_DATA_FORMAT_RANGE_2G 0x00
+#define ADXL345_DATA_FORMAT_RANGE_4G 0x01
+#define ADXL345_DATA_FORMAT_RANGE_8G 0x02
+#define ADXL345_DATA_FORMAT_RANGE_16G 0x03
+
+// DATA register bits - the data report includes adjacent data registers, for a total of 6 bytes
+#define ADXL345_DATA_REPORT_SIZE_BYTES 6
+
+// FIFO_CTL register bits
+#define ADXL345_FIFO_CTL_MODE_MASK 0xC0
+#define ADXL345_FIFO_CTL_MODE_BYPASS 0x00
+#define ADXL345_FIFO_CTL_MODE_FIFO 0x40
+#define ADXL345_FIFO_CTL_MODE_STREAM 0x80
+#define ADXL345_FIFO_CTL_MODE_TRIGGER 0xC0
+
+// Bus address
+const unsigned short SENSOR_ACCELEROMETER_BUS_ADDRESS[] = L"1D";
+
+// Default property values
+typedef struct _DATA_RATE
+{
+ ULONG DataRateInterval;
+ BYTE RateCode;
+} DATA_RATE, *PDATA_RATE;
+
+const unsigned short SENSOR_ACCELEROMETER_NAME[] = L"Accelerometer";
+const unsigned short SENSOR_ACCELEROMETER_DESCRIPTION[] = L"Accelerometer Sensor";
+const unsigned short SENSOR_ACCELEROMETER_ID[] = L"ADXL345";
+const unsigned short SENSOR_ACCELEROMETER_MANUFACTURER[] = L"Analog Devices";
+const unsigned short SENSOR_ACCELEROMETER_MODEL[] = L"ADXL345";
+const unsigned short SENSOR_ACCELEROMETER_SERIAL_NUMBER[] = L"0123456789=0123456789";
+
+const DOUBLE ACCELEROMETER_MIN_ACCELERATION_G = -16.0;
+const DOUBLE ACCELEROMETER_MAX_ACCELERATION_G = 16.0;
+const DOUBLE ACCELEROMETER_RESOLUTION_ACCELERATION_G = 0.004;
+
+const ULONG ACCELEROMETER_MIN_REPORT_INTERVAL = 10;
+const ULONG DEFAULT_ACCELEROMETER_REPORT_INTERVAL = 100;
+const ULONG CURRENT_REPORT_INTERVAL_NOT_SET = 0;
+const DATA_RATE ACCELEROMETER_SUPPORTED_DATA_RATES[] = { { 160, 0x06 }, { 80, 0x07 }, { 40, 0x08 }, { 20, 0x09 }, { 10, 0x0A } };
+const ULONG ACCELEROMETER_SUPPORTED_DATA_RATES_COUNT = ARRAYSIZE(ACCELEROMETER_SUPPORTED_DATA_RATES);
+
+const DOUBLE ACCELEROMETER_CHANGE_SENSITIVITY_RESOLUTION = 0.0625;
+const DOUBLE ACCELEROMETER_MIN_CHANGE_SENSITIVITY = 0.0625;
+const DOUBLE ACCELEROMETER_MAX_CHANGE_SENSITIVITY = 16.0;
+const DOUBLE ACCELEROMETER_DEFAULT_AXIS_THRESHOLD = ACCELEROMETER_MIN_CHANGE_SENSITIVITY / ACCELEROMETER_CHANGE_SENSITIVITY_RESOLUTION;
+const DOUBLE DEFAULT_ACCELEROMETER_CHANGE_SENSITIVITY = 0.0625;
+const DOUBLE CHANGE_SENSITIVITY_NOT_SET = -1.0; \ No newline at end of file
diff --git a/sensors/ADXL345Acc/client.cpp b/sensors/ADXL345Acc/client.cpp
new file mode 100644
index 00000000..747fd654
--- /dev/null
+++ b/sensors/ADXL345Acc/client.cpp
@@ -0,0 +1,1034 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of driver callback functions
+// from clx to ADXL345 accelerometer.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "Device.h"
+#include "Adxl345.h"
+
+#include <timeapi.h>
+
+#include "Client.tmh"
+
+
+// Analog Adxl345 Unique ID
+// {EF2C014C-DEBA-43F4-890D-978095684DD6}
+DEFINE_GUID(GUID_Adxl345Device_UniqueID,
+ 0xef2c014c, 0xdeba, 0x43f4, 0x89, 0xd, 0x97, 0x80, 0x95, 0x68, 0x4d, 0xd6);
+
+
+// Helper function for initializing ADXL345AccDevice. Returns status.
+inline NTSTATUS InitSensorCollection(
+ _In_ ULONG CollectionListCount,
+ _Outptr_ PSENSOR_COLLECTION_LIST *CollectionList,
+ _In_ SENSOROBJECT SensorInstance) // SENSOROBJECT for sensor instance
+{
+ WDF_OBJECT_ATTRIBUTES MemoryAttributes;
+ WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes);
+ MemoryAttributes.ParentObject = SensorInstance;
+
+ WDFMEMORY MemoryHandle = NULL;
+ ULONG MemorySize = SENSOR_COLLECTION_LIST_SIZE(CollectionListCount);
+ NTSTATUS Status = WdfMemoryCreate(&MemoryAttributes,
+ PagedPool,
+ SENSORV2_POOL_TAG_ACCELEROMETER,
+ MemorySize,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(CollectionList));
+ if (!NT_SUCCESS(Status) || nullptr == *CollectionList)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ TraceError("ACC %!FUNC! WdfMemoryCreate failed %!STATUS!", Status);
+ return Status;
+ }
+
+ SENSOR_COLLECTION_LIST_INIT(*CollectionList, MemorySize);
+ (*CollectionList)->Count = CollectionListCount;
+ return Status;
+}
+
+// Helper function for initializing ADXL345AccDevice. Returns status.
+inline NTSTATUS InitSensorProperty(
+ _In_ ULONG PropertyListCount,
+ _Outptr_ PSENSOR_PROPERTY_LIST *PropertyList,
+ _In_ SENSOROBJECT SensorInstance) // SENSOROBJECT for sensor instance
+{
+ WDF_OBJECT_ATTRIBUTES MemoryAttributes;
+ WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes);
+ MemoryAttributes.ParentObject = SensorInstance;
+
+ WDFMEMORY MemoryHandle = NULL;
+ ULONG MemorySize = SENSOR_PROPERTY_LIST_SIZE(PropertyListCount);
+ NTSTATUS Status = WdfMemoryCreate(&MemoryAttributes,
+ PagedPool,
+ SENSORV2_POOL_TAG_ACCELEROMETER,
+ MemorySize,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(PropertyList));
+ if (!NT_SUCCESS(Status) || nullptr == *PropertyList)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ TraceError("ACC %!FUNC! WdfMemoryCreate failed %!STATUS!", Status);
+ return Status;
+ }
+
+ SENSOR_PROPERTY_LIST_INIT(*PropertyList, MemorySize);
+ (*PropertyList)->Count = PropertyListCount;
+ return Status;
+}
+
+// This routine initializes the sensor to its default properties
+NTSTATUS ADXL345AccDevice::Initialize(
+ _In_ WDFDEVICE Device, // WDFDEVICE object
+ _In_ SENSOROBJECT SensorInstance) // SENSOROBJECT for each sensor instance
+{
+ SENSOR_FunctionEnter();
+
+ // Store device and instance
+ m_Device = Device;
+ m_SensorInstance = SensorInstance;
+ m_Started = false;
+
+ // Create Lock
+ NTSTATUS Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &(m_I2CWaitLock));
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! WdfWaitLockCreate failed %!STATUS!", Status);
+ }
+
+ // Sensor Enumeration Properties
+ if (NT_SUCCESS(Status))
+ {
+ Status = InitSensorCollection(SENSOR_ENUMERATION_PROPERTIES_COUNT, &m_pEnumerationProperties, SensorInstance);
+ if (NT_SUCCESS(Status))
+ {
+ m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_TYPE].Key = DEVPKEY_Sensor_Type;
+ InitPropVariantFromCLSID(GUID_SensorType_Accelerometer3D,
+ &(m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_TYPE].Value));
+
+ m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer;
+ InitPropVariantFromString(SENSOR_ACCELEROMETER_MANUFACTURER,
+ &(m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_MANUFACTURER].Value));
+
+ m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_MODEL].Key = DEVPKEY_Sensor_Model;
+ InitPropVariantFromString(SENSOR_ACCELEROMETER_MODEL,
+ &(m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_MODEL].Value));
+
+ m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType;
+ // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration
+ InitPropVariantFromUInt32(0, // 0: INTEGRATED, 1: ATTACHED, 2: EXTERNAL
+ &(m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_CONNECTION_TYPE].Value));
+
+ m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_PERSISTENT_UNIQUE_ID].Key = DEVPKEY_Sensor_PersistentUniqueId;
+ InitPropVariantFromCLSID(GUID_Adxl345Device_UniqueID,
+ &(m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_PERSISTENT_UNIQUE_ID].Value));
+
+ m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_CATEGORY].Key = DEVPKEY_Sensor_Category;
+ InitPropVariantFromCLSID(GUID_SensorCategory_Motion,
+ &(m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_CATEGORY].Value));
+
+ m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary;
+ InitPropVariantFromBoolean(TRUE,
+ &(m_pEnumerationProperties->List[SENSOR_ENUMERATION_PROPERTY_ISPRIMARY].Value)); // This value should be set to TRUE in order for simple device orientation
+ // to pick up ACC sample readings from this sensor. If this value is set to FALSE
+ // simple device orientation may ignore this sensor.
+ }
+ }
+
+ // Supported Data-Fields
+ if (NT_SUCCESS(Status))
+ {
+ Status = InitSensorProperty(SENSOR_DATA_COUNT, &m_pSupportedDataFields, SensorInstance);
+ if (NT_SUCCESS(Status))
+ {
+ m_pSupportedDataFields->List[SENSOR_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp;
+ m_pSupportedDataFields->List[SENSOR_DATA_ACCELERATION_X_G] = PKEY_SensorData_AccelerationX_Gs;
+ m_pSupportedDataFields->List[SENSOR_DATA_ACCELERATION_Y_G] = PKEY_SensorData_AccelerationY_Gs;
+ m_pSupportedDataFields->List[SENSOR_DATA_ACCELERATION_Z_G] = PKEY_SensorData_AccelerationZ_Gs;
+ }
+ }
+
+ // Sensor Data
+ if (NT_SUCCESS(Status))
+ {
+ Status = InitSensorCollection(SENSOR_DATA_COUNT, &m_pSensorData, SensorInstance);
+ if (NT_SUCCESS(Status))
+ {
+ FILETIME time;
+ m_pSensorData->List[SENSOR_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp;
+ GetSystemTimePreciseAsFileTime(&time);
+ InitPropVariantFromFileTime(&time, &(m_pSensorData->List[SENSOR_DATA_TIMESTAMP].Value));
+
+ m_pSensorData->List[SENSOR_DATA_ACCELERATION_X_G].Key = PKEY_SensorData_AccelerationX_Gs;
+ InitPropVariantFromFloat(0.0f, &(m_pSensorData->List[SENSOR_DATA_ACCELERATION_X_G].Value));
+
+ m_pSensorData->List[SENSOR_DATA_ACCELERATION_Y_G].Key = PKEY_SensorData_AccelerationY_Gs;
+ InitPropVariantFromFloat(0.0f, &(m_pSensorData->List[SENSOR_DATA_ACCELERATION_Y_G].Value));
+
+ m_pSensorData->List[SENSOR_DATA_ACCELERATION_Z_G].Key = PKEY_SensorData_AccelerationZ_Gs;
+ InitPropVariantFromFloat(0.0f, &(m_pSensorData->List[SENSOR_DATA_ACCELERATION_Z_G].Value));
+ }
+ }
+
+ // Sensor Properties
+ if (NT_SUCCESS(Status))
+ {
+ Status = InitSensorCollection(SENSOR_PROPERTIES_COUNT, &m_pSensorProperties, SensorInstance);
+ if (NT_SUCCESS(Status))
+ {
+ m_Interval = DEFAULT_ACCELEROMETER_REPORT_INTERVAL;
+
+ m_pSensorProperties->List[SENSOR_PROPERTY_STATE].Key = PKEY_Sensor_State;
+ InitPropVariantFromUInt32(SensorState_Initializing, &(m_pSensorProperties->List[SENSOR_PROPERTY_STATE].Value));
+
+ m_pSensorProperties->List[SENSOR_PROPERTY_MIN_DATA_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms;
+ InitPropVariantFromUInt32(ACCELEROMETER_MIN_REPORT_INTERVAL, &(m_pSensorProperties->List[SENSOR_PROPERTY_MIN_DATA_INTERVAL].Value));
+
+ m_pSensorProperties->List[SENSOR_PROPERTY_MAX_DATA_FIELD_SIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes;
+ InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pSensorData), &(m_pSensorProperties->List[SENSOR_PROPERTY_MAX_DATA_FIELD_SIZE].Value));
+
+ m_pSensorProperties->List[SENSOR_PROPERTY_TYPE].Key = PKEY_Sensor_Type;
+ InitPropVariantFromCLSID(GUID_SensorType_Accelerometer3D, &(m_pSensorProperties->List[SENSOR_PROPERTY_TYPE].Value));
+ }
+ }
+
+ // Data field properties
+ if (NT_SUCCESS(Status))
+ {
+ Status = InitSensorCollection(SENSOR_DATA_FIELD_PROPERTIES_COUNT, &m_pDataFieldProperties, SensorInstance);
+ if (NT_SUCCESS(Status))
+ {
+ m_pDataFieldProperties->List[SENSOR_DATA_FIELD_PROPERTY_RESOLUTION].Key = PKEY_SensorDataField_Resolution;
+ InitPropVariantFromFloat(static_cast<float>(ACCELEROMETER_CHANGE_SENSITIVITY_RESOLUTION), &(m_pDataFieldProperties->List[SENSOR_DATA_FIELD_PROPERTY_RESOLUTION].Value));
+
+ m_pDataFieldProperties->List[SENSOR_DATA_FIELD_PROPERTY_RANGE_MIN].Key = PKEY_SensorDataField_RangeMinimum;
+ InitPropVariantFromFloat(static_cast<float>(ACCELEROMETER_MIN_CHANGE_SENSITIVITY), &(m_pDataFieldProperties->List[SENSOR_DATA_FIELD_PROPERTY_RANGE_MIN].Value));
+
+ m_pDataFieldProperties->List[SENSOR_DATA_FIELD_PROPERTY_RANGE_MAX].Key = PKEY_SensorDataField_RangeMaximum;
+ InitPropVariantFromFloat(static_cast<float>(ACCELEROMETER_MAX_CHANGE_SENSITIVITY), &(m_pDataFieldProperties->List[SENSOR_DATA_FIELD_PROPERTY_RANGE_MAX].Value));
+ }
+ }
+
+ // Set default threshold
+ if (NT_SUCCESS(Status))
+ {
+ // note: COUNT-1 as timestamp does not have thresholds
+ Status = InitSensorCollection(SENSOR_DATA_COUNT-1, &m_pThresholds, SensorInstance);
+ if NT_SUCCESS(Status)
+ {
+ m_CachedThresholds.X = static_cast<float>(ACCELEROMETER_DEFAULT_AXIS_THRESHOLD);
+ m_CachedThresholds.Y = static_cast<float>(ACCELEROMETER_DEFAULT_AXIS_THRESHOLD);
+ m_CachedThresholds.Z = static_cast<float>(ACCELEROMETER_DEFAULT_AXIS_THRESHOLD);
+
+ m_pThresholds->List[SENSOR_DATA_ACCELERATION_X_G].Key = PKEY_SensorData_AccelerationX_Gs;
+ InitPropVariantFromFloat(static_cast<float>(ACCELEROMETER_DEFAULT_AXIS_THRESHOLD), &(m_pThresholds->List[SENSOR_DATA_ACCELERATION_X_G].Value));
+
+ m_pThresholds->List[SENSOR_DATA_ACCELERATION_Y_G].Key = PKEY_SensorData_AccelerationY_Gs;
+ InitPropVariantFromFloat(static_cast<float>(ACCELEROMETER_DEFAULT_AXIS_THRESHOLD), &(m_pThresholds->List[SENSOR_DATA_ACCELERATION_Y_G].Value));
+
+ m_pThresholds->List[SENSOR_DATA_ACCELERATION_Z_G].Key = PKEY_SensorData_AccelerationZ_Gs;
+ InitPropVariantFromFloat(static_cast<float>(ACCELEROMETER_DEFAULT_AXIS_THRESHOLD), &(m_pThresholds->List[SENSOR_DATA_ACCELERATION_Z_G].Value));
+ }
+ }
+
+ // Reset the FirstSample flag
+ if (NT_SUCCESS(Status))
+ {
+ m_FirstSample = true;
+ }
+ // Trace to this function in case of failure
+ else
+ {
+ TraceError("ACC %!FUNC! failed %!STATUS!", Status);
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+VOID ADXL345AccDevice::DeInit()
+{
+ // Delete lock
+ if (NULL != m_I2CWaitLock)
+ {
+ WdfObjectDelete(m_I2CWaitLock);
+ m_I2CWaitLock = NULL;
+ }
+
+ // Delete sensor instance
+ if (NULL != m_SensorInstance)
+ {
+ WdfObjectDelete(m_SensorInstance);
+ }
+}
+
+// This routine reads a single sample, compares threshold and pushes sample
+// to sensor class extension. This routine is protected by the caller.
+NTSTATUS ADXL345AccDevice::GetData()
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Read the device data
+ BYTE DataBuffer[ADXL345_DATA_REPORT_SIZE_BYTES];
+ WdfWaitLockAcquire(m_I2CWaitLock, NULL);
+ Status = I2CSensorReadRegister(m_I2CIoTarget, ADXL345_DATA_X0, &DataBuffer[0], sizeof(DataBuffer));
+ WdfWaitLockRelease(m_I2CWaitLock);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! I2CSensorReadRegister from 0x%02x failed! %!STATUS!", ADXL345_DATA_X0, Status);
+ }
+ else
+ {
+ bool DataReady = false;
+
+ // Perform data conversion
+ SHORT xRaw = static_cast<SHORT>((DataBuffer[1] << 8) | DataBuffer[0]);
+ SHORT yRaw = static_cast<SHORT>((DataBuffer[3] << 8) | DataBuffer[2]);
+ SHORT zRaw = static_cast<SHORT>((DataBuffer[5] << 8) | DataBuffer[4]);
+
+ const float ScaleFactor = 1 / 256.0F;
+ VEC3D Sample = {};
+ Sample.X = static_cast<float>(xRaw * ScaleFactor);
+ Sample.Y = static_cast<float>(yRaw * ScaleFactor);
+ Sample.Z = static_cast<float>(zRaw * ScaleFactor);
+
+ // Set data ready if this is the first sample or we have exceeded the thresholds
+ if (m_FirstSample)
+ {
+ m_FirstSample = false;
+ DataReady = true;
+ }
+ else if ((fabsf(Sample.X - m_LastSample.X) >= m_CachedThresholds.X) ||
+ (fabsf(Sample.Y - m_LastSample.Y) >= m_CachedThresholds.Y) ||
+ (fabsf(Sample.Z - m_LastSample.Z) >= m_CachedThresholds.Z))
+ {
+ DataReady = true;
+ }
+
+ if (DataReady)
+ {
+ // Update values for SW thresholding and send data to class extension
+ m_LastSample.X = Sample.X;
+ m_LastSample.Y = Sample.Y;
+ m_LastSample.Z = Sample.Z;
+
+ // Save the data in the context
+ InitPropVariantFromFloat(Sample.X, &(m_pSensorData->List[SENSOR_DATA_ACCELERATION_X_G].Value));
+ InitPropVariantFromFloat(Sample.Y, &(m_pSensorData->List[SENSOR_DATA_ACCELERATION_Y_G].Value));
+ InitPropVariantFromFloat(Sample.Z, &(m_pSensorData->List[SENSOR_DATA_ACCELERATION_Z_G].Value));
+
+ FILETIME Timestamp = {};
+ GetSystemTimePreciseAsFileTime(&Timestamp);
+ InitPropVariantFromFileTime(&Timestamp, &(m_pSensorData->List[SENSOR_DATA_TIMESTAMP].Value));
+
+ SensorsCxSensorDataReady(m_SensorInstance, m_pSensorData);
+ }
+ else
+ {
+ TraceInformation("ACC %!FUNC! Data did NOT meet the threshold");
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Services a hardware interrupt.
+BOOLEAN ADXL345AccDevice::OnInterruptIsr(
+ _In_ WDFINTERRUPT Interrupt, // Handle to a framework interrupt object
+ _In_ ULONG /*MessageID*/) // If the device is using message-signaled interrupts (MSIs),
+ // this parameter is the message number that identifies the
+ // device's hardware interrupt message. Otherwise, this value is 0.
+{
+ BOOLEAN InterruptRecognized = FALSE;
+ PADXL345AccDevice pAccDevice = nullptr;
+
+ SENSOR_FunctionEnter();
+
+ // Get the sensor instance
+ ULONG SensorInstanceCount = 1;
+ SENSOROBJECT SensorInstance = NULL;
+ NTSTATUS Status = SensorsCxDeviceGetSensorList(WdfInterruptGetDevice(Interrupt), &SensorInstance, &SensorInstanceCount);
+ if (!NT_SUCCESS(Status) || 0 == SensorInstanceCount || NULL == SensorInstance)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ }
+
+ // Get the device context
+ else // if (NT_SUCCESS(Status))
+ {
+ pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! GetADXL345AccContextFromSensorInstance failed %!STATUS!", Status);
+ }
+ }
+
+ // Read the interrupt source
+ if (NT_SUCCESS(Status))
+ {
+ BYTE IntSrcBuffer = 0;
+ WdfWaitLockAcquire(pAccDevice->m_I2CWaitLock, NULL);
+ Status = I2CSensorReadRegister(pAccDevice->m_I2CIoTarget, ADXL345_INT_SOURCE, &IntSrcBuffer, sizeof(IntSrcBuffer));
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! I2CSensorReadRegister from 0x%02x failed! %!STATUS!", ADXL345_INT_SOURCE, Status);
+ }
+ else if ((IntSrcBuffer & ADXL345_INT_ACTIVITY) == 0)
+ {
+ TraceError("%!FUNC! Interrupt source not recognized");
+ }
+ else
+ {
+ InterruptRecognized = TRUE;
+ BOOLEAN WorkItemQueued = WdfInterruptQueueWorkItemForIsr(Interrupt);
+ TraceVerbose("%!FUNC! Work item %s queued for interrupt", WorkItemQueued ? "" : " already");
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+ return InterruptRecognized;
+}
+
+// Processes interrupt information that the driver's EvtInterruptIsr callback function has stored.
+VOID ADXL345AccDevice::OnInterruptWorkItem(
+ _In_ WDFINTERRUPT Interrupt, // Handle to a framework object
+ _In_ WDFOBJECT /*AssociatedObject*/) // A handle to the framework device object that
+ // the driver passed to WdfInterruptCreate.
+{
+ PADXL345AccDevice pAccDevice = nullptr;
+
+ SENSOR_FunctionEnter();
+
+ // Get the sensor instance
+ ULONG SensorInstanceCount = 1;
+ SENSOROBJECT SensorInstance = NULL;
+ NTSTATUS Status = SensorsCxDeviceGetSensorList(WdfInterruptGetDevice(Interrupt), &SensorInstance, &SensorInstanceCount);
+ if (!NT_SUCCESS(Status) || 0 == SensorInstanceCount || NULL == SensorInstance)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ }
+
+ // Get the device context
+ else //if (NT_SUCCESS(Status))
+ {
+ pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! GetADXL345AccContextFromSensorInstance failed %!STATUS!", Status);
+ }
+ }
+
+ // Read the device data
+ if (NT_SUCCESS(Status))
+ {
+ WdfInterruptAcquireLock(Interrupt);
+ Status = pAccDevice->GetData();
+ WdfInterruptReleaseLock(Interrupt);
+ if (!NT_SUCCESS(Status) && STATUS_DATA_NOT_ACCEPTED != Status)
+ {
+ TraceError("ACC %!FUNC! GetData failed %!STATUS!", Status);
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+}
+
+// Called by Sensor CLX to begin continously sampling the sensor.
+NTSTATUS ADXL345AccDevice::OnStart(
+ _In_ SENSOROBJECT SensorInstance) // Sensor device object
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Get the device context
+ PADXL345AccDevice pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Sensor(0x%p) parameter is invalid %!STATUS!", SensorInstance, Status);
+ }
+ else if (!pAccDevice->m_PoweredOn)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Sensor is not powered on! %!STATUS!", Status);
+ }
+ else
+ {
+ WdfWaitLockAcquire(pAccDevice->m_I2CWaitLock, NULL);
+
+ // Set accelerometer to measurement mode
+ REGISTER_SETTING RegisterSetting = { ADXL345_POWER_CTL, ADXL345_POWER_CTL_MEASURE };
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ if (!NT_SUCCESS(Status))
+ {
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+ TraceError("ACC %!FUNC! I2CSensorWriteRegister to 0x%02x failed! %!STATUS!", RegisterSetting.Register, Status);
+ }
+
+ // Enable interrupts
+ else // if (NT_SUCCESS(Status))
+ {
+ RegisterSetting = { ADXL345_INT_ENABLE, ADXL345_INT_ACTIVITY };
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! I2CSensorWriteRegister to 0x%02x failed! %!STATUS!", RegisterSetting.Register, Status);
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ pAccDevice->m_FirstSample = true;
+ pAccDevice->m_Started = true;
+
+ InitPropVariantFromUInt32(SensorState_Active, &(pAccDevice->m_pSensorProperties->List[SENSOR_PROPERTY_STATE].Value));
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Called by Sensor CLX to stop continously sampling the sensor.
+NTSTATUS ADXL345AccDevice::OnStop(
+ _In_ SENSOROBJECT SensorInstance) // Sensor device object
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Get the device context
+ PADXL345AccDevice pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Sensor(0x%p) parameter is invalid %!STATUS!", SensorInstance, Status);
+ }
+ else
+ {
+ pAccDevice->m_Started = false;
+
+ // Disable interrupts
+ REGISTER_SETTING RegisterSetting = { ADXL345_INT_ENABLE, 0 };
+ WdfWaitLockAcquire(pAccDevice->m_I2CWaitLock, NULL);
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! I2CSensorWriteRegister to 0x%02x failed! %!STATUS!", RegisterSetting.Register, Status);
+ }
+ // Clear any stale interrupts
+ else
+ {
+ RegisterSetting = { ADXL345_INT_SOURCE, 0 };
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! I2CSensorReadRegister from 0x%02x failed! %!STATUS!", RegisterSetting.Register, Status);
+ }
+ }
+
+ // Set accelerometer to standby
+ RegisterSetting = { ADXL345_POWER_CTL, ADXL345_POWER_CTL_STANDBY };
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! I2CSensorWriteRegister to 0x%02x failed! %!STATUS!", RegisterSetting.Register, Status);
+ }
+ else
+ {
+ InitPropVariantFromUInt32(SensorState_Idle, &(pAccDevice->m_pSensorProperties->List[SENSOR_PROPERTY_STATE].Value));
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// 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 ADXL345AccDevice::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
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! pSize: Invalid parameter! %!STATUS!", Status);
+ }
+ else
+ {
+ *pSize = 0;
+
+ // Get the device context
+ PADXL345AccDevice pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Invalid parameters! %!STATUS!", Status);
+ }
+ else if (nullptr == pFields)
+ {
+ // Just return size
+ *pSize = pAccDevice->m_pSupportedDataFields->AllocatedSizeInBytes;
+ }
+ else
+ {
+ if (pFields->AllocatedSizeInBytes < pAccDevice->m_pSupportedDataFields->AllocatedSizeInBytes)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACC %!FUNC! Buffer is too small. Failed %!STATUS!", Status);
+ }
+ else
+ {
+ // Fill out data
+ Status = PropertiesListCopy(pFields, pAccDevice->m_pSupportedDataFields);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! PropertiesListCopy failed %!STATUS!", Status);
+ }
+ else
+ {
+ *pSize = pAccDevice->m_pSupportedDataFields->AllocatedSizeInBytes;
+ }
+ }
+ }
+ }
+
+ 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 ADXL345AccDevice::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
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! pSize: Invalid parameter! %!STATUS!", Status);
+ }
+ else
+ {
+ *pSize = 0;
+
+ // Get the device context
+ PADXL345AccDevice pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Invalid parameters! %!STATUS!", Status);
+ }
+ else if (nullptr == pProperties)
+ {
+ // Just return size
+ *pSize = CollectionsListGetMarshalledSize(pAccDevice->m_pSensorProperties);
+ }
+ else
+ {
+ if (pProperties->AllocatedSizeInBytes < CollectionsListGetMarshalledSize(pAccDevice->m_pSensorProperties))
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACC %!FUNC! Buffer is too small. Failed %!STATUS!", Status);
+ }
+ else
+ {
+ // Fill out all data
+ Status = CollectionsListCopyAndMarshall(pProperties, pAccDevice->m_pSensorProperties);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status);
+ }
+ else
+ {
+ *pSize = CollectionsListGetMarshalledSize(pAccDevice->m_pSensorProperties);
+ }
+ }
+ }
+ }
+
+ 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 ADXL345AccDevice::OnGetDataFieldProperties(
+ _In_ SENSOROBJECT SensorInstance, // Sensor device object
+ _In_ const PROPERTYKEY *pDataField, // 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
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! pSize: Invalid parameter! %!STATUS!", Status);
+ }
+ else
+ {
+ *pSize = 0;
+
+ // Get the device context
+ PADXL345AccDevice pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice || nullptr == pDataField)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Invalid parameters! %!STATUS!", Status);
+ }
+ else if (!IsEqualPropertyKey(*pDataField, pAccDevice->m_pSupportedDataFields->List[SENSOR_DATA_ACCELERATION_X_G]) &&
+ !IsEqualPropertyKey(*pDataField, pAccDevice->m_pSupportedDataFields->List[SENSOR_DATA_ACCELERATION_Y_G]) &&
+ !IsEqualPropertyKey(*pDataField, pAccDevice->m_pSupportedDataFields->List[SENSOR_DATA_ACCELERATION_Z_G]))
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ TraceError("ACC %!FUNC! ADXL345 does NOT have properties for this data field. Failed %!STATUS!", Status);
+ }
+ else if (nullptr == pProperties)
+ {
+ // Just return size
+ *pSize = CollectionsListGetMarshalledSize(pAccDevice->m_pDataFieldProperties);
+ }
+ else
+ {
+ if (pProperties->AllocatedSizeInBytes < CollectionsListGetMarshalledSize(pAccDevice->m_pDataFieldProperties))
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACC %!FUNC! Buffer is too small. Failed %!STATUS!", Status);
+ }
+ else
+ {
+ // Fill out all data
+ Status = CollectionsListCopyAndMarshall(pProperties, pAccDevice->m_pDataFieldProperties);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status);
+ }
+ else
+ {
+ *pSize = CollectionsListGetMarshalledSize(pAccDevice->m_pDataFieldProperties);
+ }
+ }
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Called by Sensor CLX to get sampling rate of the sensor.
+NTSTATUS ADXL345AccDevice::OnGetDataInterval(
+ _In_ SENSOROBJECT SensorInstance, // Sensor device object
+ _Out_ PULONG pDataRateMs) // Sampling rate in milliseconds
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PADXL345AccDevice pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Invalid parameters! %!STATUS!", Status);
+ }
+ else if (nullptr == pDataRateMs)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Invalid parameters! %!STATUS!", Status);
+ }
+ else
+ {
+ *pDataRateMs = pAccDevice->m_Interval;
+ TraceInformation("%!FUNC! giving data rate %lu", *pDataRateMs);
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Called by Sensor CLX to set sampling rate of the sensor.
+NTSTATUS ADXL345AccDevice::OnSetDataInterval(
+ _In_ SENSOROBJECT SensorInstance, // Sensor device object
+ _In_ ULONG DataRateMs) // Sampling rate in milliseconds
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Get the device context
+ PADXL345AccDevice pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice || DataRateMs < ACCELEROMETER_MIN_REPORT_INTERVAL)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Invalid parameters! %!STATUS!", Status);
+ }
+ else
+ {
+ pAccDevice->m_Interval = DataRateMs;
+ if (pAccDevice->m_Started)
+ {
+ pAccDevice->m_Started = false;
+
+ WdfWaitLockAcquire(pAccDevice->m_I2CWaitLock, NULL);
+
+ // Disable Interrupts
+ REGISTER_SETTING RegisterSetting = { ADXL345_INT_ENABLE, 0 };
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ if (!NT_SUCCESS(Status))
+ {
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+ TraceError("ACC %!FUNC! Failed to disable interrupts. %!STATUS!", Status);
+ }
+
+ // Update data rate in HW
+ else // (if NT_SUCCESS(Status))
+ {
+ RegisterSetting = { ADXL345_BW_RATE, _GetDataRateFromReportInterval(DataRateMs).RateCode };
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ if (!NT_SUCCESS(Status))
+ {
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+ TraceError("ACC %!FUNC! I2CSensorWriteRegister to 0x%02x failed! %!STATUS!", RegisterSetting.Register, Status);
+ }
+ }
+
+ // Re-enable Interrupts
+ if (NT_SUCCESS(Status))
+ {
+ pAccDevice->m_Started = true;
+ pAccDevice->m_FirstSample = true;
+
+ RegisterSetting = { ADXL345_INT_ENABLE, ADXL345_INT_ACTIVITY };
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! Failed to re-enable interrupts. %!STATUS!", Status);
+ }
+ }
+ }
+ }
+
+ 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 ADXL345AccDevice::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
+{
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! pSize: Invalid parameter! %!STATUS!", Status);
+ }
+ else
+ {
+ *pSize = 0;
+
+ PADXL345AccDevice pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Invalid parameters! %!STATUS!", Status);
+ }
+ else if (nullptr == pThresholds)
+ {
+ // Just return size
+ *pSize = CollectionsListGetMarshalledSize(pAccDevice->m_pThresholds);
+ }
+ else
+ {
+ if (pThresholds->AllocatedSizeInBytes < CollectionsListGetMarshalledSize(pAccDevice->m_pThresholds))
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACC %!FUNC! Buffer is too small. Failed %!STATUS!", Status);
+ }
+ else
+ {
+ // Fill out all data
+ Status = CollectionsListCopyAndMarshall(pThresholds, pAccDevice->m_pThresholds);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status);
+ }
+ else
+ {
+ *pSize = CollectionsListGetMarshalledSize(pAccDevice->m_pThresholds);
+ }
+ }
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Called by Sensor CLX to set data thresholds.
+NTSTATUS ADXL345AccDevice::OnSetDataThresholds(
+ _In_ SENSOROBJECT SensorInstance, // Sensor Device Object
+ _In_ PSENSOR_COLLECTION_LIST pThresholds) // Pointer to a list of sensor thresholds
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PADXL345AccDevice pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Sensor(0x%p) parameter is invalid %!STATUS!", SensorInstance, Status);
+ }
+
+ else // if (NT_SUCCESS(Status))
+ {
+ for (ULONG i = 0; i < pThresholds->Count; i++)
+ {
+ Status = PropKeyFindKeySetPropVariant(pAccDevice->m_pThresholds, &(pThresholds->List[i].Key), true, &(pThresholds->List[i].Value));
+ if (!NT_SUCCESS(Status))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! Adxl345 does NOT have threshold for this data field. Failed %!STATUS!", Status);
+ break;
+ }
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = PropKeyFindKeyGetFloat(pAccDevice->m_pThresholds, &PKEY_SensorData_AccelerationX_Gs, &(pAccDevice->m_CachedThresholds.X));
+ if (!NT_SUCCESS(Status))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! PropKeyFindKeyGetFloat for X failed! %!STATUS!", Status);
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = PropKeyFindKeyGetFloat(pAccDevice->m_pThresholds, &PKEY_SensorData_AccelerationY_Gs, &(pAccDevice->m_CachedThresholds.Y));
+ if (!NT_SUCCESS(Status))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! PropKeyFindKeyGetFloat for Y failed! %!STATUS!", Status);
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = PropKeyFindKeyGetFloat(pAccDevice->m_pThresholds, &PKEY_SensorData_AccelerationZ_Gs, &(pAccDevice->m_CachedThresholds.Z));
+ if (!NT_SUCCESS(Status))
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! PropKeyFindKeyGetFloat for Z failed! %!STATUS!", Status);
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ // The accelerometer only supports a single value, so pick the smallest, i.e. most sensitive.
+ FLOAT MinThreshold = min(pAccDevice->m_CachedThresholds.X, min(pAccDevice->m_CachedThresholds.Y, pAccDevice->m_CachedThresholds.Z));
+ MinThreshold = max(MinThreshold, static_cast<FLOAT>(ACCELEROMETER_MIN_CHANGE_SENSITIVITY));
+
+ // Disable Interrupts
+ REGISTER_SETTING RegisterSetting = { ADXL345_INT_ENABLE, 0 };
+ WdfWaitLockAcquire(pAccDevice->m_I2CWaitLock, NULL);
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ if (!NT_SUCCESS(Status))
+ {
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+ TraceError("ACC %!FUNC! Failed to disable interrupts. %!STATUS!", Status);
+ }
+
+ // The threshold can only be set in increments, so round down to a more sensitive setting for hardware
+ else //if (NT_SUCCESS(Status))
+ {
+ BYTE NewThreshold = static_cast<BYTE>(MinThreshold / ACCELEROMETER_CHANGE_SENSITIVITY_RESOLUTION);
+ RegisterSetting = { ADXL345_THRESH_ACT, NewThreshold };
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ if (!NT_SUCCESS(Status))
+ {
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+ TraceError("ACC %!FUNC! I2CSensorWriteRegister to 0x%02x failed! %!STATUS!", RegisterSetting.Register, Status);
+ }
+ }
+
+ // Re-enable Interrupts
+ if (NT_SUCCESS(Status))
+ {
+ RegisterSetting = { ADXL345_INT_ENABLE, ADXL345_INT_ACTIVITY };
+ Status = I2CSensorWriteRegister(pAccDevice->m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ WdfWaitLockRelease(pAccDevice->m_I2CWaitLock);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! Failed to re-enable interrupts. %!STATUS!", Status);
+ }
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Called by Sensor CLX to handle IOCTLs that clx does not support
+NTSTATUS ADXL345AccDevice::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;
+}
diff --git a/sensors/ADXL345Acc/device.cpp b/sensors/ADXL345Acc/device.cpp
new file mode 100644
index 00000000..389f28cd
--- /dev/null
+++ b/sensors/ADXL345Acc/device.cpp
@@ -0,0 +1,474 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of WDF callback functions
+// for the ADXL345 accelerometer sensor driver.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "Device.h"
+
+#include "Device.tmh"
+
+
+// This routine is the AddDevice entry point for the custom sensor 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 ADXL345AccDevice::OnDeviceAdd(
+ _In_ WDFDRIVER /* Driver */, // Supplies a handle to the driver object created in DriverEntry
+ _Inout_ PWDFDEVICE_INIT pAccDeviceInit) // Supplies a pointer to a framework-allocated WDFDEVICE_INIT structure
+{
+ WDFDEVICE Device = nullptr;
+
+ SENSOR_FunctionEnter();
+
+ WdfDeviceInitSetPowerPolicyOwnership(pAccDeviceInit, true);
+
+ WDF_OBJECT_ATTRIBUTES FdoAttributes;
+ WDF_OBJECT_ATTRIBUTES_INIT(&FdoAttributes);
+
+ // Initialize FDO (functional device object) attributes and set up file object with sensor extension
+ NTSTATUS Status = SensorsCxDeviceInitConfig(pAccDeviceInit, &FdoAttributes, 0);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! SensorsCxDeviceInitConfig failed %!STATUS!", Status);
+ }
+
+ else // if (NT_SUCCESS(Status))
+ {
+ // Register the PnP callbacks with the framework.
+ WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
+ pnpPowerCallbacks.EvtDevicePrepareHardware = ADXL345AccDevice::OnPrepareHardware;
+ pnpPowerCallbacks.EvtDeviceReleaseHardware = ADXL345AccDevice::OnReleaseHardware;
+ pnpPowerCallbacks.EvtDeviceD0Entry = ADXL345AccDevice::OnD0Entry;
+ pnpPowerCallbacks.EvtDeviceD0Exit = ADXL345AccDevice::OnD0Exit;
+
+ WdfDeviceInitSetPnpPowerEventCallbacks(pAccDeviceInit, &pnpPowerCallbacks);
+
+ // Call the framework to create the device
+ Status = WdfDeviceCreate(&pAccDeviceInit, &FdoAttributes, &Device);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! WdfDeviceCreate failed %!STATUS!", Status);
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ // Register CLX callback function pointers
+ SENSOR_CONTROLLER_CONFIG SensorConfig;
+ SENSOR_CONTROLLER_CONFIG_INIT(&SensorConfig);
+ SensorConfig.DriverIsPowerPolicyOwner = WdfUseDefault;
+
+ SensorConfig.EvtSensorStart = ADXL345AccDevice::OnStart;
+ SensorConfig.EvtSensorStop = ADXL345AccDevice::OnStop;
+ SensorConfig.EvtSensorGetSupportedDataFields = ADXL345AccDevice::OnGetSupportedDataFields;
+ SensorConfig.EvtSensorGetDataInterval = ADXL345AccDevice::OnGetDataInterval;
+ SensorConfig.EvtSensorSetDataInterval = ADXL345AccDevice::OnSetDataInterval;
+ SensorConfig.EvtSensorGetDataFieldProperties = ADXL345AccDevice::OnGetDataFieldProperties;
+ SensorConfig.EvtSensorGetDataThresholds = ADXL345AccDevice::OnGetDataThresholds;
+ SensorConfig.EvtSensorSetDataThresholds = ADXL345AccDevice::OnSetDataThresholds;
+ SensorConfig.EvtSensorGetProperties = ADXL345AccDevice::OnGetProperties;
+ SensorConfig.EvtSensorDeviceIoControl = ADXL345AccDevice::OnIoControl;
+
+ // Initialize the sensor device with the Sensor CLX
+ // This lets the CLX call the above callbacks when
+ // necessary and allows applications to retrieve and
+ // set device data.
+ Status = SensorsCxDeviceInitialize(Device, &SensorConfig);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! SensorsCxDeviceInitialize failed %!STATUS!", Status);
+ }
+ }
+
+ // Ensure device is disable-able
+ // By default, devices enumerated by ACPI are not disable-able
+ // Our accelerometer is enumerated by the ACPI so we must
+ // explicitly make it disable-able.
+ if (NT_SUCCESS(Status))
+ {
+ WDF_DEVICE_STATE DeviceState;
+ WDF_DEVICE_STATE_INIT(&DeviceState);
+ DeviceState.NotDisableable = WdfFalse;
+ WdfDeviceSetDeviceState(Device, &DeviceState);
+ }
+
+ 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 ADXL345AccDevice::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.
+{
+ PADXL345AccDevice pAccDevice = nullptr;
+
+ SENSOR_FunctionEnter();
+
+ // Create WDFOBJECT for the sensor
+ WDF_OBJECT_ATTRIBUTES sensorAttributes;
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&sensorAttributes, ADXL345AccDevice);
+
+ // Register sensor instance with clx
+ SENSOROBJECT SensorInstance = NULL;
+ NTSTATUS Status = SensorsCxSensorCreate(Device, &sensorAttributes, &SensorInstance);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! SensorsCxSensorCreate failed %!STATUS!", Status);
+ }
+
+ else // if (NT_SUCCESS(Status))
+ {
+ pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACC %!FUNC! SensorsCxSensorCreate failed %!STATUS!", Status);
+ }
+ }
+
+ // Fill out sensor context
+ if (NT_SUCCESS(Status))
+ {
+ Status = pAccDevice->Initialize(Device, SensorInstance);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! Initialize device object failed %!STATUS!", Status);
+ }
+ }
+
+ // Initialize sensor instance with clx
+ if (NT_SUCCESS(Status))
+ {
+ SENSOR_CONFIG SensorConfig;
+ SENSOR_CONFIG_INIT(&SensorConfig);
+ SensorConfig.pEnumerationList = pAccDevice->m_pEnumerationProperties;
+ Status = SensorsCxSensorInitialize(SensorInstance, &SensorConfig);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! SensorsCxSensorInitialize failed %!STATUS!", Status);
+ }
+ }
+
+ // ACPI and IoTarget configuration
+ if (NT_SUCCESS(Status))
+ {
+ Status = pAccDevice->ConfigureIoTarget(ResourcesRaw, ResourcesTranslated);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! Failed to configure IoTarget %!STATUS!", Status);
+ }
+ }
+
+ 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.
+NTSTATUS ADXL345AccDevice::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.
+{
+ PADXL345AccDevice pAccDevice = nullptr;
+
+ SENSOR_FunctionEnter();
+
+ // Get the sensor instance
+ ULONG SensorInstanceCount = 1;
+ SENSOROBJECT SensorInstance = NULL;
+ NTSTATUS Status = SensorsCxDeviceGetSensorList(Device, &SensorInstance, &SensorInstanceCount);
+ if (!NT_SUCCESS(Status) || 0 == SensorInstanceCount || NULL == SensorInstance)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ }
+
+ else // if (NT_SUCCESS(Status))
+ {
+ pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! GetADXL345AccContextFromSensorInstance failed %!STATUS!", Status);
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ pAccDevice->DeInit();
+ }
+
+ 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 ADXL345AccDevice::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
+{
+ PADXL345AccDevice pAccDevice = nullptr;
+
+ SENSOR_FunctionEnter();
+
+ // Get the sensor instance
+ ULONG SensorInstanceCount = 1;
+ SENSOROBJECT SensorInstance = NULL;
+ NTSTATUS Status = SensorsCxDeviceGetSensorList(Device, &SensorInstance, &SensorInstanceCount);
+ if (!NT_SUCCESS(Status) || 0 == SensorInstanceCount || NULL == SensorInstance)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ }
+
+ // Get the device context
+ else // if (NT_SUCCESS(Status))
+ {
+ pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! GetADXL345AccContextFromSensorInstance failed %!STATUS!", Status);
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = pAccDevice->PowerOn();
+ }
+
+ 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. EvtDeviceD0Exit event callback must
+// perform any operations that are necessary before the specified device is
+// moved out of the D0 state. If the driver needs to save hardware state
+// before the device is powered down, then that should be done here.
+NTSTATUS ADXL345AccDevice::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
+{
+ PADXL345AccDevice pAccDevice = nullptr;
+
+ SENSOR_FunctionEnter();
+
+ // Get the sensor instance
+ ULONG SensorInstanceCount = 1;
+ SENSOROBJECT SensorInstance = NULL;
+ NTSTATUS Status = SensorsCxDeviceGetSensorList(Device, &SensorInstance, &SensorInstanceCount);
+ if (!NT_SUCCESS(Status) || 0 == SensorInstanceCount || NULL == SensorInstance)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ }
+
+ // Get the device context
+ else // if (NT_SUCCESS(Status))
+ {
+ pAccDevice = GetADXL345AccContextFromSensorInstance(SensorInstance);
+ if (nullptr == pAccDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("ACC %!FUNC! GetADXL345AccContextFromSensorInstance failed %!STATUS!", Status);
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = pAccDevice->PowerOff();
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Get the HW resource from the ACPI, then configure and store the IoTarget
+NTSTATUS ADXL345AccDevice::ConfigureIoTarget(
+ _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.
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG I2CConnectionResourceCount = 0;
+ LARGE_INTEGER I2CConnId = {};
+
+ DECLARE_UNICODE_STRING_SIZE(deviceName, RESOURCE_HUB_PATH_SIZE);
+
+ SENSOR_FunctionEnter();
+
+ // Get hardware resource from ACPI and set up IO target
+ ULONG ResourceCount = WdfCmResourceListGetCount(ResourcesTranslated);
+ for (ULONG i = 0; i < ResourceCount; i++)
+ {
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw = WdfCmResourceListGetDescriptor(ResourcesRaw, i);
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i);
+ switch (Descriptor->Type)
+ {
+ // Check we have I2C bus assigned in ACPI
+ case CmResourceTypeConnection:
+ TraceInformation("ACC %!FUNC! I2C resource found.");
+ if (Descriptor->u.Connection.Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL &&
+ Descriptor->u.Connection.Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C)
+ {
+ I2CConnId.LowPart = Descriptor->u.Connection.IdLowPart;
+ I2CConnId.HighPart = Descriptor->u.Connection.IdHighPart;
+ I2CConnectionResourceCount++;
+ }
+ break;
+
+ // Check we have an interrupt assigned in ACPI and create interrupt
+ case CmResourceTypeInterrupt:
+ TraceInformation("ACC %!FUNC! GPIO interrupt resource found.");
+ WDF_INTERRUPT_CONFIG InterruptConfig;
+ WDF_INTERRUPT_CONFIG_INIT(&InterruptConfig, OnInterruptIsr, NULL);
+ InterruptConfig.InterruptRaw = DescriptorRaw;
+ InterruptConfig.InterruptTranslated = Descriptor;
+ // Configure an interrupt work item which runs at IRQL = PASSIVE_LEVEL
+ // Note: to configure to run at IRQL = DISPATCH_LEVEL, set up an InterruptDpc instead of an InterruptWorkItem
+ InterruptConfig.EvtInterruptWorkItem = OnInterruptWorkItem;
+ InterruptConfig.PassiveHandling = true;
+ Status = WdfInterruptCreate(m_Device, &InterruptConfig, WDF_NO_OBJECT_ATTRIBUTES, &m_Interrupt);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! WdfInterruptCreate failed %!STATUS!", Status);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (NT_SUCCESS(Status) && I2CConnectionResourceCount != 1)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ TraceError("ACC %!FUNC! Did not find I2C resource! %!STATUS!", Status);
+ }
+
+ // Set up I2C I/O target. Issued with I2C R/W transfers
+ if (NT_SUCCESS(Status))
+ {
+ m_I2CIoTarget = NULL;
+ Status = WdfIoTargetCreate(m_Device, WDF_NO_OBJECT_ATTRIBUTES, &m_I2CIoTarget);
+
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! WdfIoTargetCreate failed! %!STATUS!", Status);
+ }
+ }
+
+ // Setup Target string (\\\\.\\RESOURCE_HUB\\<ConnID from ResHub>
+ if (NT_SUCCESS(Status))
+ {
+ Status = StringCbPrintfW(deviceName.Buffer, RESOURCE_HUB_PATH_SIZE, L"%s\\%0*I64x", RESOURCE_HUB_DEVICE_NAME, static_cast<unsigned int>(sizeof(LARGE_INTEGER) * 2), I2CConnId.QuadPart);
+ deviceName.Length = _countof(deviceName_buffer);
+
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! RESOURCE_HUB_CREATE_PATH_FROM_ID failed!");
+ }
+ }
+
+ // Connect to I2C target
+ if (NT_SUCCESS(Status))
+ {
+ WDF_IO_TARGET_OPEN_PARAMS OpenParams;
+ WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(&OpenParams, &deviceName, FILE_ALL_ACCESS);
+
+ Status = WdfIoTargetOpen(m_I2CIoTarget, &OpenParams);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! WdfIoTargetOpen failed! %!STATUS!", Status);
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Write the default device configuration to the device
+NTSTATUS ADXL345AccDevice::PowerOn()
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ WdfWaitLockAcquire(m_I2CWaitLock, NULL);
+
+ for (DWORD i = 0; i < ARRAYSIZE(g_ConfigurationSettings); i++)
+ {
+ REGISTER_SETTING setting = g_ConfigurationSettings[i];
+ Status = I2CSensorWriteRegister(m_I2CIoTarget, setting.Register, &setting.Value, sizeof(setting.Value));
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! I2CSensorReadRegister from 0x%02x failed! %!STATUS!", setting.Register, Status);
+ WdfWaitLockRelease(m_I2CWaitLock);
+ return Status;
+ }
+ }
+
+ WdfWaitLockRelease(m_I2CWaitLock);
+
+ InitPropVariantFromUInt32(SensorState_Idle, &(m_pSensorProperties->List[SENSOR_PROPERTY_STATE].Value));
+ m_PoweredOn = true;
+
+ return Status;
+}
+
+NTSTATUS ADXL345AccDevice::PowerOff()
+{
+ REGISTER_SETTING RegisterSetting = { ADXL345_POWER_CTL, ADXL345_POWER_CTL_STANDBY };
+
+ WdfWaitLockAcquire(m_I2CWaitLock, NULL);
+ NTSTATUS Status = I2CSensorWriteRegister(m_I2CIoTarget, RegisterSetting.Register, &RegisterSetting.Value, sizeof(RegisterSetting.Value));
+ WdfWaitLockRelease(m_I2CWaitLock);
+
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("ACC %!FUNC! Failed to put device into standby %!STATUS!", Status);
+ }
+ else
+ {
+ m_PoweredOn = false;
+ }
+
+ return Status;
+}
diff --git a/sensors/ADXL345Acc/driver.cpp b/sensors/ADXL345Acc/driver.cpp
new file mode 100644
index 00000000..0703d858
--- /dev/null
+++ b/sensors/ADXL345Acc/driver.cpp
@@ -0,0 +1,66 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of entry and exit point
+// of sample ADXL345 accelerometer 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.
+ // DriverEntry must initialize members of DriverObject before it
+ // returns to the caller. DriverObject is allocated by the system
+ // before the driver is loaded, and it is released by the system
+ // after the system unloads the function driver from memory.
+ _In_ PUNICODE_STRING RegistryPath) // Pointer to the driver specific registry key. The function
+ // driver can use the path to store driver related data between
+ // reboots. The path does not store hardware instance specific data.
+{
+ // Initialize WPP Tracing
+ WPP_INIT_TRACING(DriverObject, NULL);
+
+ SENSOR_FunctionEnter();
+
+ WDF_DRIVER_CONFIG DriverConfig;
+ DriverConfig.DriverPoolTag = SENSORV2_POOL_TAG_ACCELEROMETER;
+
+ // Register a cleanup callback so that we can call WPP_CLEANUP when
+ // the framework driver object is deleted during driver unload.
+ WDF_DRIVER_CONFIG_INIT(&DriverConfig, ADXL345AccDevice::OnDeviceAdd);
+ DriverConfig.EvtDriverUnload = OnDriverUnload;
+
+ NTSTATUS Status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &DriverConfig, WDF_NO_HANDLE);
+
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("WdfDriverCreate failed %!STATUS!", Status);
+ }
+
+ 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;
+}
+
diff --git a/sensors/Activity/Activity.def b/sensors/Activity/Activity.def
new file mode 100644
index 00000000..1fe10e90
--- /dev/null
+++ b/sensors/Activity/Activity.def
@@ -0,0 +1,6 @@
+; Activity.def : Declares the module parameters.
+
+LIBRARY Activity
+
+EXPORTS
+
diff --git a/sensors/Activity/Activity.inx b/sensors/Activity/Activity.inx
new file mode 100644
index 00000000..7f2558c1
--- /dev/null
+++ b/sensors/Activity/Activity.inx
Binary files differ
diff --git a/sensors/Activity/Activity.sln b/sensors/Activity/Activity.sln
new file mode 100644
index 00000000..918419d9
--- /dev/null
+++ b/sensors/Activity/Activity.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}") = "Activity", "Activity.vcxproj", "{9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}"
+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
+ {9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}.Debug|Win32.Build.0 = Debug|Win32
+ {9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}.Release|Win32.ActiveCfg = Release|Win32
+ {9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}.Release|Win32.Build.0 = Release|Win32
+ {9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}.Debug|x64.ActiveCfg = Debug|x64
+ {9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}.Debug|x64.Build.0 = Debug|x64
+ {9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}.Release|x64.ActiveCfg = Release|x64
+ {9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/sensors/Activity/Activity.vcxproj b/sensors/Activity/Activity.vcxproj
new file mode 100644
index 00000000..724803cd
--- /dev/null
+++ b/sensors/Activity/Activity.vcxproj
@@ -0,0 +1,204 @@
+<?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>{9C41A0A9-BEE7-4410-A604-2B97BDDE6A87}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{C9C93A11-59AB-4977-BE1F-E0AB103302E2}</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>Activity</WppModuleName>
+ <WppScanConfigurationData>sensorstrace.h</WppScanConfigurationData>
+ </ClCompile>
+ <Inf Include="Activity.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\Activity.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>Activity</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>Activity</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>Activity</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>Activity</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>Activity.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>Activity.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>Activity.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>Activity.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </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/Activity/Activity.vcxproj.Filters b/sensors/Activity/Activity.vcxproj.Filters
new file mode 100644
index 00000000..f32344d8
--- /dev/null
+++ b/sensors/Activity/Activity.vcxproj.Filters
@@ -0,0 +1,43 @@
+<?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>{E51044F1-2844-4B85-9CB3-50C5574B73E6}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{18DACA49-0487-4FC6-94D7-DE977A2AD8D5}</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>{60868430-E51C-40B0-86F8-D5C119418603}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{B845F613-F2F8-4EDB-8CAE-574E38ABD746}</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="Activity.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="Activity.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/sensors/Activity/Device.h b/sensors/Activity/Device.h
new file mode 100644
index 00000000..64b2a5e4
--- /dev/null
+++ b/sensors/Activity/Device.h
@@ -0,0 +1,200 @@
+// 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_ACTIVITY 'itcA'
+static const ULONG Act_Max_State_Count = 7; // Currently there are 7 states
+static const ULONG Act_Default_MinDataInterval_Ms = 3000; // 3 seconds in milli seconds.
+static const ULONG Act_Default_SubscribedStates = ActivityState_Max - 1; // all activities
+static const BOOLEAN Act_Default_Streaming = FALSE; // no streaming
+static const USHORT Act_Default_ConfidenceThreshold_Percentage = 50; // 50% default confidence threshold
+static const ULONG Act_Default_HistoryInterval_Ms = 60000; // 1 minute in milli seconds
+static const ULONG Act_Default_MaxHistoryEntries = 60; // max of 60 history entries
+static const ULONG Act_Default_Power_uW = 2000; // micro watts
+static const ULONG Act_TimeoutForHistoryThread_Ms = 1000; // milli seconds
+static const USHORT Act_ConfidenceForHistoryEntries_Percentage = 70; // percentage
+static const ULONG Act_First_Most_Probable_State = 0;
+
+// 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_SUPPORTEDACTIVITIES,
+ SENSOR_PROPERTY_MAX_HISTORYSIZE,
+ SENSOR_PROPERTY_HISTORY_INTERVAL,
+ SENSOR_PROPERTY_MAX_HISTROYRECORDSIZE,
+ 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,
+ SENSOR_ISPRIMARY,
+
+ // These enumeration properties overlap with a subset of the common properties,
+ // and facilitate discovery without opening a sensor
+ SENSOR_MIN_INTERVAL,
+ SENSOR_POWER,
+ SENSOR_SUPPORTEDACTIVITIES,
+ SENSOR_MAX_HISTORYSIZE,
+ 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
+{
+ ACTIVITY_DATA_TIMESTAMP = 0,
+ ACTIVITY_DATA_CURRENT_STATE,
+ ACTIVITY_DATA_CURRENT_CONFIDENCE,
+ ACTIVITY_DATA_COUNT
+} ACTIVITY_DATA_INDEX;
+
+// Data Thresholds
+typedef enum
+{
+ ACTIVITY_THRESHOLD_SUBSCRIBED_STATES = 0,
+ ACTIVITY_THRESHOLD_STREAMING,
+ ACTIVITY_THRESHOLD_CONFIDENCE,
+ ACTIVITY_THRESHOLD_COUNT
+} ACTIVITY_THRESHOLD_INDEX;
+
+typedef struct _ActivitySample
+{
+ FILETIME Timestamp;
+ ULONG Activity;
+ UINT16 Confidence;
+} ActivitySample, *PActivitySample;
+
+// History buffer
+typedef struct _HistoryCircularBuffer
+{
+ PActivitySample 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
+} HistoryCircularBuffer, *PHistoryCircularBuffer;
+
+typedef class _ActivityDevice
+{
+private:
+ // Simulator
+ WDFOBJECT m_SimulatorInstance;
+
+ // WDF
+ WDFDEVICE m_FxDevice;
+ SENSOROBJECT m_SensorInstance;
+ WDFWAITLOCK m_Lock;
+ WDFTIMER m_Timer;
+ WDFWAITLOCK m_HistoryLock;
+ WDFTIMER m_HistoryTimer;
+
+ // Sensor operation
+ BOOLEAN m_PoweredOn;
+ BOOLEAN m_Started;
+ ULONG m_Interval;
+ BOOLEAN m_FirstSample;
+
+ // History operation
+ HistoryCircularBuffer m_History;
+ BOOLEAN m_HistoryStarted;
+ ULONG m_HistoryIntervalInMs;
+ ULONG m_HistorySizeInRecords;
+ ULONG m_HistoryMarshalledRecordSize;
+ ULONG m_HistoryPowerInuW;
+ HANDLE m_hThread;
+ HANDLE m_ExitEvent;
+ BOOLEAN m_HistoryRetrievalStarted;
+ 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_pLastSample;
+ PSENSOR_COLLECTION_LIST m_pFilteredSample;
+
+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;
+ static EVT_WDF_TIMER OnHistoryTimerExpire;
+
+ // 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;
+
+ // History retrieval
+ static ULONG WINAPI HistoryRetrievalThread(_In_ LPVOID lpParam);
+
+private:
+ NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj);
+ NTSTATUS InitializeSupportedDataFields();
+ NTSTATUS InitializeSensorProperties();
+ NTSTATUS InitializeEnumerationProperties();
+ NTSTATUS InitializeDataFieldProperties();
+ NTSTATUS GetData();
+ _Requires_lock_held_(m_HistoryLock)
+ NTSTATUS AddDataElementToHistoryBuffer(_In_ PActivitySample pData);
+ _Requires_lock_held_(m_HistoryLock)
+ NTSTATUS RemoveDataElementFromHistoryBuffer(_Out_ PActivitySample pData);
+ _Requires_lock_held_(m_HistoryLock)
+ NTSTATUS ClearHistoryBuffer();
+} ActivityDevice, *PActivityDevice;
+
+//
+// Set up accessor function to retrieve device context
+//
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ActivityDevice, GetActivityContextFromSensorInstance); \ No newline at end of file
diff --git a/sensors/Activity/Driver.h b/sensors/Activity/Driver.h
new file mode 100644
index 00000000..6c1611c5
--- /dev/null
+++ b/sensors/Activity/Driver.h
@@ -0,0 +1,16 @@
+// Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+// Abstract:
+// This module contains the implementation of entry and exit point of activity sample driver.
+//
+// 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/Activity/Gallery.xml b/sensors/Activity/Gallery.xml
new file mode 100644
index 00000000..bb6e792a
--- /dev/null
+++ b/sensors/Activity/Gallery.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="../../buildx/script2/preview.xslt"?>
+<gallery_sample xmlns="http://microsoft.com/wdcml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://microsoft.com/wdcml ../../buildx/schema/xsd/wdcml.xsd">
+ <metadata id="gallery_samples.107a_gallery" type="gallery_sample" msdnID="7cba6311-f0db-4c3d-8f1f-25de8648b353">
+ <title>Activity</title>
+ <!-- Add a devlang for each programming language in all versions of the sample. -->
+ <devlang value="cpp" />
+ <!-- Do not change tech value -->
+ <tech value="gallery_samples" />
+ <index />
+ <sample_langs>
+ <!-- Describes the languages to which the sample code itself has been localized. -->
+ <sample_lang xml:lang="en-us" />
+ </sample_langs>
+ </metadata>
+ <content>
+ <desc>
+ <p><abstract>The activity sensor sample shows how to write a UMDF v2 driver to control a virtual activity sensor.</abstract></p>
+ </desc>
+ <outline />
+ <license_info>
+ <default_license />
+ </license_info>
+ <programming_models>
+ <programming_model value="win32" />
+ </programming_models>
+ <application_frameworks>
+ </application_frameworks>
+ <!-- For Driver Samples Only -->
+ <driver_models>
+ <!-- possible values: kmdf, umdf, wdm, ndis, wddm -->
+ <driver_model value="UMDF" />
+ </driver_models>
+ <driver_techs>
+ <driver_tech value="Windows Driver" />
+ </driver_techs>
+ <related_techs>
+ </related_techs>
+ <os_requirements>
+ <min_os>
+ <client name="winblue"/>
+ <server name="wbluesrv"/>
+ </min_os>
+ </os_requirements>
+ <required_sdks>
+ <min_sdk>
+ <tla rid="windows_driver_kit_8" />
+ </min_sdk>
+ </required_sdks>
+ <supported_ides>
+ <supported_ide>
+ <tla rid="tla_visualstu2012" />
+ </supported_ide>
+ </supported_ides>
+ <build_info>
+ <authored_instructions>
+ <section>
+ <!-- Include any special instructions for compiling your sample -->
+ <sectioncontents>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </build_info>
+ <run_info>
+ <authored_instructions>
+ <section>
+ <sectioncontents>
+ <p>To install the sample driver, follow these steps:</p>
+ <proch>
+ <item>Ensure that the driver builds without errors.</item>
+ <item>Copy the DLL and INF files to a separate folder.</item>
+ <item>Enter the command "<inline_code devlang="cmd">devcon.exe update Activity.inf ACPI\&lt;HWID&gt;</inline_code>" to install the driver on an existing device node. You can find the devcon.exe program in the tools\devcon folder where you installed the WDK.</item>
+ </proch>
+ </sectioncontents>
+ </section>
+ <section>
+ <title>File manifest</title>
+ <sectioncontents>
+ <p>The following source files are in the src\Sensors\Activity folder and are used to build the Activity.dll and Activity.inf files.</p>
+ <table>
+ <tr>
+ <th>File</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>
+ <p>device.h, device.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's WDF PnP event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>client.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's callback functions from the class extension to activity sensors.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>driver.h, driver.cpp</p>
+ </td>
+ <td>
+ <p>WDF driver entry event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>hardwaresimulator.h, hardwaresimulator.cpp</p>
+ </td>
+ <td>
+ <p>Hardware simulator implementation</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>makefile.inc</p>
+ </td>
+ <td>
+ <p>Defines custom build actions. Includes the conversion of the .INX file into a .INF file.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>SensorsTrace.h</p>
+ </td>
+ <td>
+ <p>Implementation the sensor traces files.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>Activity.ctl</p>
+ </td>
+ <td>
+ <p>Declaration of driver's tracing GUID</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>Activity.inx</p>
+ </td>
+ <td>
+ <p>Describes the installation of the driver. The build process converts this into a .INF.</p>
+ </td>
+ </tr>
+ </table>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </run_info>
+ </content>
+ <!-- List the component compcentral path -->
+ <feature_teams>
+ <feature_team_info comp_central_path="CORE-OS Core\SiGMa-Silicon, Graphics and Media\SiPlat - Silicon Platform\Sensors" dev_owner="osamasal" writer_owner="ericdoku" />
+ </feature_teams>
+ <workflow_control_host />
+</gallery_sample>
diff --git a/sensors/Activity/HardwareSimulator.h b/sensors/Activity/HardwareSimulator.h
new file mode 100644
index 00000000..c61325f1
--- /dev/null
+++ b/sensors/Activity/HardwareSimulator.h
@@ -0,0 +1,49 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved
+//
+//Abstract:
+// This module contains the type definitions for the activity sample driver hardware simulator.
+//
+//Environment:
+// Windows User-Mode Driver Framework (UMDF)
+
+#pragma once
+
+#include "Device.h"
+
+typedef enum SIMULATOR_STATE
+{
+ SimulatorState_NotInitialized = 0,
+ SimulatorState_Initialized,
+ SimulatorState_Started
+} SIMULATOR_STATE;
+
+typedef class HardwareSimulator
+{
+private:
+ WDFTIMER m_Timer;
+ ULONG m_Index;
+ WDFWAITLOCK m_Lock;
+ SIMULATOR_STATE m_State;
+
+public:
+ HardwareSimulator();
+ ~HardwareSimulator();
+
+ // WDF callbacks
+ static EVT_WDF_TIMER OnTimerExpire;
+
+ static NTSTATUS Initialize(_In_ WDFDEVICE device, _Out_ WDFOBJECT *pSimulatorInstance);
+ VOID Deinitialize();
+ VOID Start();
+ VOID Stop();
+ NTSTATUS GetSample(_Inout_ PSENSOR_COLLECTION_LIST pSample);
+ NTSTATUS GetSample(_Out_ PActivitySample pSample);
+
+private:
+ NTSTATUS InitializeInternal(_In_ WDFOBJECT simulatorInstance);
+
+} HardwareSimulator, *PHardwareSimulator;
+
+
+// Set up accessor function to retrieve device context
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(HardwareSimulator, GetHardwareSimulatorContextFromInstance);
diff --git a/sensors/Activity/SensorsTrace.h b/sensors/Activity/SensorsTrace.h
new file mode 100644
index 00000000..f6239fd7
--- /dev/null
+++ b/sensors/Activity/SensorsTrace.h
@@ -0,0 +1,102 @@
+//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 - B6E7F50C-8F25-445E-8B39-D05802A53EB9
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ ActivityTraceGuid, (B6E7F50C,8F25,445E,8B39,D05802A53EB9), \
+ 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()*/; \
+ }
+
+
+
+// WPP Recorder -------------------------------------------------------------------------------------------
+//
+// The following two macros are required to enable WPP Recorder functionality for clients of the Sensor Class Extension
+//
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_FILTER(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS)
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_ARGS(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/sensors/Activity/client.cpp b/sensors/Activity/client.cpp
new file mode 100644
index 00000000..ca4c5bc2
--- /dev/null
+++ b/sensors/Activity/client.cpp
@@ -0,0 +1,1021 @@
+// Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+// Abstract:
+// This module contains the implementation of driver callback function from clx to activity detection driver.
+//
+// Environment:
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "Device.h"
+#include "HardwareSimulator.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 ActivityDevice::GetData()
+{
+ BOOLEAN dataReady = FALSE;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (NULL != m_SimulatorInstance)
+ {
+ // Use simulator to get m_pFiltered Sample
+ PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance);
+ if (nullptr != pSimulator)
+ {
+ status = pSimulator->GetSample(m_pFilteredSample);
+ }
+ else
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ status = CollectionsListSortSubscribedActivitiesByConfidence(m_pThresholds, m_pFilteredSample);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! CollectionsListSortSubscribedActivitiesByConfidence failed! %!STATUS!", status);
+ }
+ else
+ {
+ // new sample?
+ if (FALSE != m_FirstSample)
+ {
+ dataReady = TRUE;
+ }
+ else
+ {
+ dataReady = EvaluateActivityThresholds(m_pFilteredSample, m_pLastSample, m_pThresholds);
+ }
+ }
+ }
+
+ if (FALSE != dataReady)
+ {
+ // update last sample
+ FILETIME TimeStamp = {};
+ memcpy_s(m_pLastSample, m_pFilteredSample->AllocatedSizeInBytes, m_pFilteredSample, m_pFilteredSample->AllocatedSizeInBytes);
+ GetSystemTimePreciseAsFileTime(&TimeStamp);
+ InitPropVariantFromFileTime(&TimeStamp, &(m_pLastSample->List[ACTIVITY_DATA_TIMESTAMP].Value));
+
+ // push to clx
+ SensorsCxSensorDataReady(m_SensorInstance, m_pLastSample);
+ m_FirstSample = FALSE;
+ }
+ else
+ {
+ status = STATUS_DATA_NOT_ACCEPTED;
+ TraceInformation("ACT %!FUNC! Data did NOT meet the threshold");
+ }
+
+ SENSOR_FunctionExit(status);
+ 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 ActivityDevice::OnTimerExpire(_In_ WDFTIMER timer)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(WdfTimerGetParentObject(timer));
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! GetActivityContextFromSensorInstance failed %!STATUS!", status);
+ }
+ else
+ {
+ // Get data and push to clx
+ WdfWaitLockAcquire(pDevice->m_Lock, NULL);
+ status = pDevice->GetData();
+ if (!NT_SUCCESS(status) && STATUS_DATA_NOT_ACCEPTED != status)
+ {
+ TraceError("ACT %!FUNC! GetAccData Failed %!STATUS!", status);
+ }
+ WdfWaitLockRelease(pDevice->m_Lock);
+
+ // Schedule next wake up time
+ if (Act_Default_MinDataInterval_Ms <= pDevice->m_Interval &&
+ FALSE != pDevice->m_PoweredOn &&
+ FALSE != pDevice->m_Started)
+ {
+ WdfTimerStart(pDevice->m_Timer, WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval));
+ }
+ }
+
+ SENSOR_FunctionExit(status);
+}
+
+// Called by Sensor CLX to begin continously sampling the sensor.
+NTSTATUS ActivityDevice::OnStart(_In_ SENSOROBJECT sensorInstance)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status);
+ }
+ else
+ {
+ if (FALSE == pDevice->m_PoweredOn)
+ {
+ status = STATUS_DEVICE_NOT_READY;
+ TraceError("ACT %!FUNC! Sensor is not powered on! %!STATUS!", status);
+ }
+ else
+ {
+ // Start simulation
+ if (NULL != pDevice->m_SimulatorInstance)
+ {
+ PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance);
+ if (nullptr != pSimulator)
+ {
+ pSimulator->Start();
+ }
+ }
+
+ // Start sensing
+ pDevice->m_FirstSample = TRUE;
+ pDevice->m_Started = TRUE;
+ InitPropVariantFromUInt32(SensorState_Active, &(pDevice->m_pProperties->List[SENSOR_PROPERTY_STATE].Value));
+ WdfTimerStart(pDevice->m_Timer, WDF_REL_TIMEOUT_IN_MS(Act_Default_MinDataInterval_Ms));
+ }
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// Called by Sensor CLX to stop continously sampling the sensor.
+NTSTATUS ActivityDevice::OnStop(_In_ SENSOROBJECT sensorInstance)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status);
+ }
+ else
+ {
+ // Stop sensing
+ pDevice->m_Started = FALSE;
+ WdfTimerStop(pDevice->m_Timer, TRUE);
+ InitPropVariantFromUInt32(SensorState_Idle, &(pDevice->m_pProperties->List[SENSOR_PROPERTY_STATE].Value));
+
+ // Stop simulation
+ if (NULL != pDevice->m_SimulatorInstance)
+ {
+ PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance);
+ if (nullptr != pSimulator)
+ {
+ pSimulator->Stop();
+ }
+ }
+ }
+
+ 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 ActivityDevice::RemoveDataElementFromHistoryBuffer(_Out_ PActivitySample pData)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (nullptr == pData)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! NULL ptr passed in %!STATUS!", status);
+ }
+ else
+ {
+ if (0 == m_History.NumOfElems)
+ {
+ // buffer empty
+ status = STATUS_NO_MORE_ENTRIES;
+ }
+ else
+ {
+ // Remove the oldest element from the circular buffer
+ *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 ActivityDevice::AddDataElementToHistoryBuffer(_In_ PActivitySample pData)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (nullptr == pData)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! GetActivityContextFromSensorInstance failed %!STATUS!", status);
+ }
+ else
+ {
+ 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
+ m_History.LastElemIndex++;
+ m_History.LastElemIndex %= m_History.BufferLength;
+ m_History.NumOfElems++;
+ }
+ else if (m_History.BufferLength == m_History.NumOfElems)
+ {
+ // buffer full. Over-write the oldest element
+ m_History.FirstElemIndex++;
+ m_History.FirstElemIndex %= m_History.BufferLength;
+ m_History.LastElemIndex++;
+ m_History.LastElemIndex %= m_History.BufferLength;
+ }
+ memcpy_s(&(m_History.pData[m_History.LastElemIndex]),
+ sizeof(m_History.pData[m_History.LastElemIndex]),
+ pData,
+ sizeof(*pData));
+ }
+
+ return status;
+}
+
+// This routine is for clearing the history buffer. Note this function must be called under lock.
+_Requires_lock_held_(m_HistoryLock)
+NTSTATUS ActivityDevice::ClearHistoryBuffer()
+{
+ m_History.FirstElemIndex = 0;
+ m_History.LastElemIndex = 0;
+ m_History.NumOfElems = 0;
+ RtlZeroMemory(m_History.pData, (m_History.BufferLength*sizeof(ActivitySample)));
+ return STATUS_SUCCESS;
+}
+
+// This callback is called when interval wait time has expired and driver is ready
+// to collect new sample. The callback stores activity data in history buffer,
+// and schedules next wake up time.
+VOID ActivityDevice::OnHistoryTimerExpire(_In_ WDFTIMER historyTimer)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(WdfTimerGetParentObject(historyTimer));
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! GetActivityContextFromSensorInstance failed %!STATUS!", status);
+ }
+ else
+ {
+ ActivitySample data = {};
+ if (NULL != pDevice->m_SimulatorInstance)
+ {
+ PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance);
+ if (nullptr != pSimulator)
+ {
+ status = pSimulator->GetSample(&data);
+ }
+ else
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ GetSystemTimePreciseAsFileTime(&(data.Timestamp));
+
+ if (NT_SUCCESS(status))
+ {
+ // Add data to the buffer
+ WdfWaitLockAcquire(pDevice->m_HistoryLock, NULL);
+ status = pDevice->AddDataElementToHistoryBuffer(&data);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! AddDataElementToHistoryBuffer Failed %!STATUS!", status);
+ }
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+ }
+
+ // Schedule next wake up time
+ if (FALSE != pDevice->m_HistoryStarted)
+ {
+ WdfTimerStart(pDevice->m_HistoryTimer, WDF_REL_TIMEOUT_IN_MS(pDevice->m_HistoryIntervalInMs));
+ }
+ }
+
+ SENSOR_FunctionExit(status);
+}
+
+// Called by Sensor CLX to begin keeping history
+NTSTATUS ActivityDevice::OnStartHistory(_In_ SENSOROBJECT sensorInstance)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status);
+ }
+ else if (0 == pDevice->m_HistorySizeInRecords)
+ {
+ status = STATUS_NOT_SUPPORTED;
+ TraceError("ACT %!FUNC! Sensor does not support History");
+ }
+ else if (FALSE == pDevice->m_PoweredOn)
+ {
+ status = STATUS_DEVICE_NOT_READY;
+ TraceError("ACT %!FUNC! Sensor is not powered on! %!STATUS!", status);
+ }
+ else
+ {
+ // Start keeping history
+ pDevice->m_HistoryStarted = TRUE;
+ WdfTimerStart(pDevice->m_HistoryTimer, WDF_REL_TIMEOUT_IN_MS(pDevice->m_HistoryIntervalInMs));
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// Called by Sensor CLX to stop keeping history.
+NTSTATUS ActivityDevice::OnStopHistory(_In_ SENSOROBJECT sensorInstance)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status);
+ }
+ else
+ {
+ // Stop keeping history
+ pDevice->m_HistoryStarted = FALSE;
+ WdfTimerStop(pDevice->m_HistoryTimer, TRUE);
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// Called by Sensor CLX to clear all history stored in the sensor.
+NTSTATUS ActivityDevice::OnClearHistory(_In_ SENSOROBJECT sensorInstance)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status);
+ }
+ else
+ {
+ WdfWaitLockAcquire(pDevice->m_HistoryLock, NULL);
+ status = pDevice->ClearHistoryBuffer();
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! ClearHistoryBuffer Failed %!STATUS!", status);
+ }
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// Called by Sensor CLX to start retrieving history.
+NTSTATUS ActivityDevice::OnStartHistoryRetrieval(
+ _In_ SENSOROBJECT sensorInstance,
+ _Inout_updates_bytes_(historySizeInBytes) PSENSOR_COLLECTION_LIST pHistoryBuffer,
+ _In_ ULONG historySizeInBytes
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status);
+ }
+ else
+ {
+ // 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_HistoryLock, NULL);
+ BOOLEAN IsStarted = pDevice->m_HistoryRetrievalStarted;
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+
+ if (FALSE != IsStarted)
+ {
+ status = STATUS_DEVICE_BUSY;
+ TraceError("ACT %!FUNC! StartHistoryRetrieval called again before the previous call"
+ "finishes retrieving history %!STATUS!", status);
+ }
+ else
+ {
+ // 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;
+ }
+
+ // check that the buffer is not null
+ if (NULL == pHistoryBuffer)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! History buffer cannot be NULL. %!STATUS!", status);
+ }
+ else
+ {
+ // check that the buffer can hold at least one entry
+ if (historySizeInBytes < pDevice->m_HistoryMarshalledRecordSize)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ TraceError("ACT %!FUNC! History buffer is too small to even fill one complete entry. %!STATUS!", status);
+ }
+ else
+ {
+ pDevice->m_ClientHistoryBuffer = pHistoryBuffer;
+ pDevice->m_ClientHistoryBufferSize = historySizeInBytes;
+
+ // Reset exit event
+ ResetEvent(pDevice->m_ExitEvent);
+
+ WdfWaitLockAcquire(pDevice->m_HistoryLock, NULL);
+
+ // 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<PVOID>(sensorInstance), // pointer to variable to be passed
+ 0, // run immediately
+ NULL); // Thread ID
+ if (NULL == pDevice->m_hThread)
+ {
+ status = STATUS_UNSUCCESSFUL;
+ TraceError("ACT %!FUNC! CreateThread Failed %!STATUS!", status);
+ }
+ else
+ {
+ pDevice->m_HistoryRetrievalStarted = TRUE;
+ }
+
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+ }
+ }
+ }
+ }
+
+ SENSOR_FunctionExit(status);
+
+ if (nullptr != pDevice && !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 ActivityDevice::OnCancelHistoryRetrieval(_In_ SENSOROBJECT sensorInstance, _Out_ PULONG pBytesWritten)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ *pBytesWritten = 0;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status);
+ }
+ else
+ {
+ // Check if history retrieval operation is in progress
+ WdfWaitLockAcquire(pDevice->m_HistoryLock, NULL);
+ BOOLEAN IsStarted = pDevice->m_HistoryRetrievalStarted;
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+
+ if (FALSE == IsStarted)
+ {
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ TraceError("ACT %!FUNC! History retrieval is not in progress %!STATUS!", status);
+ }
+ else
+ {
+ // Signal the history retrieval thread to exit
+ SetEvent(pDevice->m_ExitEvent);
+
+ // Wait for the history retrieval thread to finish writing the entry since no partial entries are allowed.
+ DWORD result = WaitForSingleObjectEx(pDevice->m_hThread, Act_TimeoutForHistoryThread_Ms, FALSE);
+ if (WAIT_OBJECT_0 != result)
+ {
+ // continue to mark history retrieval stop
+ status = NTSTATUS_FROM_WIN32(result);
+ TraceError("ACT %!FUNC! WaitForSingleObjectEx failed! %!STATUS!", status);
+ }
+
+ WdfWaitLockAcquire(pDevice->m_HistoryLock, NULL);
+ *pBytesWritten = CollectionsListGetMarshalledSizeWithoutSerialization(pDevice->m_ClientHistoryBuffer);
+ pDevice->m_HistoryRetrievalStarted = FALSE;
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+ }
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// Created on calling StartHistoryRetrieval function.
+ULONG WINAPI ActivityDevice::HistoryRetrievalThread(_In_ LPVOID lpParam)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOLEAN exitSignal = FALSE;
+ UINT existingCount = 0;
+ UINT fillableCount = 0;
+
+ SENSOROBJECT sensorInstance = reinterpret_cast<SENSOROBJECT>(lpParam);
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice ||
+ NULL == pDevice->m_ClientHistoryBuffer ||
+ pDevice->m_HistoryMarshalledRecordSize > pDevice->m_ClientHistoryBufferSize)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status);
+ }
+ else
+ {
+ // Capture the number of entries in the driver's history buffer at this moment
+ WdfWaitLockAcquire(pDevice->m_HistoryLock, NULL);
+ existingCount = pDevice->m_History.NumOfElems;
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+
+ // How many entries can the client supplied buffer hold
+ fillableCount = (pDevice->m_ClientHistoryBufferSize - SENSOR_COLLECTION_LIST_HEADER_SIZE) / (pDevice->m_HistoryMarshalledRecordSize - SENSOR_COLLECTION_LIST_HEADER_SIZE);
+
+ // Find the minimum of the number of entries in the driver's history buffer and
+ // the number of entries that can be held by the client supplied buffer
+ UINT count = min(existingCount, fillableCount);
+
+ // All entries into the client's buffer must be complete i.e. no partial entries are allowed.
+ // Check whether the exit event is signaled before looping through each time to retrieve an entry from the driver's history buffer.
+ // Each history record will only contain first entry of the most probable state.
+ for (UINT index = 0; index < count; index++)
+ {
+ ActivitySample data = {};
+ UINT elementIndex = ACTIVITY_DATA_COUNT * index;
+ if (WAIT_OBJECT_0 == WaitForSingleObject(pDevice->m_ExitEvent, 0))
+ {
+ exitSignal = TRUE;
+ break;
+ }
+
+ WdfWaitLockAcquire(pDevice->m_HistoryLock, NULL);
+ if (!NT_SUCCESS(pDevice->RemoveDataElementFromHistoryBuffer(&data)))
+ {
+ // Only return error if there is no more entry which is not an error. Therefore no need to set status.
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+ break;
+ }
+
+ elementIndex = (index * ACTIVITY_DATA_COUNT) + ACTIVITY_DATA_TIMESTAMP;
+ pDevice->m_ClientHistoryBuffer->List[elementIndex].Key = PKEY_SensorData_Timestamp;
+ InitPropVariantFromFileTime(&(data.Timestamp), &(pDevice->m_ClientHistoryBuffer->List[elementIndex].Value));
+
+ elementIndex = (index * ACTIVITY_DATA_COUNT) + ACTIVITY_DATA_CURRENT_STATE;
+ pDevice->m_ClientHistoryBuffer->List[elementIndex].Key = PKEY_SensorData_CurrentActivityState;
+ InitPropVariantFromUInt32(data.Activity, &(pDevice->m_ClientHistoryBuffer->List[elementIndex].Value));
+
+ elementIndex = (index * ACTIVITY_DATA_COUNT) + ACTIVITY_DATA_CURRENT_CONFIDENCE;
+ pDevice->m_ClientHistoryBuffer->List[elementIndex].Key = PKEY_SensorData_CurrentActivityStateConfidence_Percentage;
+ InitPropVariantFromUInt16(data.Confidence, &(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 = (index + 1) * ACTIVITY_DATA_COUNT;
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+ }
+ }
+
+ if (FALSE == exitSignal)
+ {
+ if (fillableCount < existingCount)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (0 == existingCount)
+ {
+ status = STATUS_NO_MORE_ENTRIES;
+ }
+ // call completed callback only if retrieval was not canceled
+ SensorsCxSensorHistoryRetrievalCompleted(pDevice->m_SensorInstance, CollectionsListGetMarshalledSizeWithoutSerialization(pDevice->m_ClientHistoryBuffer), status);
+ }
+
+ WdfWaitLockAcquire(pDevice->m_HistoryLock, NULL);
+ pDevice->m_HistoryRetrievalStarted = FALSE;
+ WdfWaitLockRelease(pDevice->m_HistoryLock);
+
+ return ERROR_SUCCESS;
+}
+
+// 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 ActivityDevice::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
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice || nullptr == pSize)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Invalid parameters! %!STATUS!", status);
+ }
+ else
+ {
+ if (nullptr == pFields)
+ {
+ // Just return size
+ *pSize = pDevice->m_pSupportedDataFields->AllocatedSizeInBytes;
+ }
+ else
+ {
+ if (pFields->AllocatedSizeInBytes < pDevice->m_pSupportedDataFields->AllocatedSizeInBytes)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! Buffer is too small. Failed %!STATUS!", status);
+ }
+ else
+ {
+ // Fill out data
+ status = PropertiesListCopy(pFields, pDevice->m_pSupportedDataFields);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! PropertiesListCopy failed %!STATUS!", status);
+ }
+ else
+ {
+ *pSize = pDevice->m_pSupportedDataFields->AllocatedSizeInBytes;
+ }
+ }
+ }
+ }
+
+ 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 ActivityDevice::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
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice || nullptr == pSize)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Invalid parameters! %!STATUS!", status);
+ }
+ else
+ {
+ if (nullptr == pProperties)
+ {
+ // Just return size
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pProperties);
+ }
+ else
+ {
+ if (pProperties->AllocatedSizeInBytes <
+ CollectionsListGetMarshalledSize(pDevice->m_pProperties))
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! Buffer is too small. Failed %!STATUS!", status);
+ }
+ else
+ {
+ // Fill out all data
+ status = CollectionsListCopyAndMarshall(pProperties, pDevice->m_pProperties);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", status);
+ }
+ else
+ {
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pProperties);
+ }
+ }
+ }
+ }
+
+ 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 ActivityDevice::OnGetDataFieldProperties(
+ _In_ SENSOROBJECT sensorInstance, // sensor device object
+ _In_ const PROPERTYKEY *pDataField, // 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
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice || nullptr == pSize || nullptr == pDataField)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Invalid parameters! %!STATUS!", status);
+ }
+ else
+ {
+ if (*pDataField == PKEY_SensorData_CurrentActivityStateConfidence_Percentage)
+ {
+ if (nullptr == pProperties)
+ {
+ // Just return size
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties);
+ }
+ else
+ {
+ if (pProperties->AllocatedSizeInBytes < CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties))
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! Buffer is too small. Failed %!STATUS!", status);
+ }
+ else
+ {
+ // Fill out all data
+ status = CollectionsListCopyAndMarshall(pProperties, pDevice->m_pDataFieldProperties);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", status);
+ }
+ else
+ {
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties);
+ }
+ }
+ }
+ }
+ else
+ {
+ status = STATUS_NOT_SUPPORTED;
+ TraceError("ACT %!FUNC! AccFake does NOT have properties for this data field. Failed %!STATUS!", status);
+ }
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ *pSize = 0;
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// Called by Sensor CLX to get sampling rate of the sensor.
+NTSTATUS ActivityDevice::OnGetDataInterval(_In_ SENSOROBJECT sensorInstance, _Out_ PULONG pDataRateMs)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ *pDataRateMs = 0;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice || nullptr == pDataRateMs)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status);
+ }
+ else
+ {
+ *pDataRateMs = pDevice->m_Interval;
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// Called by Sensor CLX to set sampling rate of the sensor.
+NTSTATUS ActivityDevice::OnSetDataInterval(_In_ SENSOROBJECT sensorInstance, _In_ ULONG dataRateMs)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice || Act_Default_MinDataInterval_Ms > dataRateMs)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Invalid parameters! %!STATUS!", status);
+ }
+ else
+ {
+ 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(Act_Default_MinDataInterval_Ms));
+ }
+ }
+
+ 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 ActivityDevice::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
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice || nullptr == pSize)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Invalid parameters! %!STATUS!", status);
+ }
+ else
+ {
+ if (nullptr == pThresholds)
+ {
+ // Just return size
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pThresholds);
+ }
+ else
+ {
+ if (pThresholds->AllocatedSizeInBytes < CollectionsListGetMarshalledSize(pDevice->m_pThresholds))
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! Buffer is too small. Failed %!STATUS!", status);
+ }
+ else
+ {
+ // Fill out all data
+ status = CollectionsListCopyAndMarshall(pThresholds, pDevice->m_pThresholds);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", status);
+ }
+ else
+ {
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pThresholds);
+ }
+ }
+ }
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ *pSize = 0;
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// Called by Sensor CLX to set data thresholds.
+NTSTATUS ActivityDevice::OnSetDataThresholds(
+ _In_ SENSOROBJECT sensorInstance, // sensor device object
+ _In_ PSENSOR_COLLECTION_LIST pThresholds) // pointer to a list of sensor thresholds
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", sensorInstance, status);
+ }
+ else
+ {
+ WdfWaitLockAcquire(pDevice->m_Lock, NULL);
+
+ for (ULONG 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("ACT %!FUNC! ActivityFake does NOT have threshold for this data field. Failed %!STATUS!", status);
+ break;
+ }
+ }
+
+ WdfWaitLockRelease(pDevice->m_Lock);
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// Called by Sensor CLX to handle IOCTLs that clx does not support.
+NTSTATUS ActivityDevice::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
+{
+ SENSOR_FunctionEnter();
+
+ WdfRequestComplete(request, STATUS_NOT_SUPPORTED);
+
+ SENSOR_FunctionExit(STATUS_NOT_SUPPORTED);
+ return STATUS_NOT_SUPPORTED;
+}
diff --git a/sensors/Activity/device.cpp b/sensors/Activity/device.cpp
new file mode 100644
index 00000000..1b0339db
--- /dev/null
+++ b/sensors/Activity/device.cpp
@@ -0,0 +1,835 @@
+// 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)
+
+#include "Device.h"
+#include "HardwareSimulator.h"
+#include "Device.tmh"
+
+// Activity Unique ID {8b3dd227-cc0e-465f-a36e-811c94a1b240}
+DEFINE_GUID(GUID_ActivityDevice_UniqueID, 0x8b3dd227, 0xcc0e, 0x465f, 0xa3, 0x6e, 0x81, 0x1c, 0x94, 0xa1, 0xb2, 0x40);
+
+static const float ActivityFakeDevice_Confidence_Resolution = 1.0f;
+static const float ActivityFakeDevice_Confidence_Minimum = 0.0f;
+static const float ActivityFakeDevice_Confidence_Maximum = 100.0f;
+
+// This routine initializes the sensor's enumeration properties
+NTSTATUS ActivityDevice::InitializeEnumerationProperties()
+{
+ WDF_OBJECT_ATTRIBUTES memoryAttributes = {};
+ WDFMEMORY memoryHandle = NULL;
+ const ULONG size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ENUMERATION_PROPERTIES_COUNT);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
+ memoryAttributes.ParentObject = m_SensorInstance;
+ status = WdfMemoryCreate(&memoryAttributes,
+ PagedPool,
+ SENSOR_POOL_TAG_ACTIVITY,
+ size,
+ &memoryHandle,
+ reinterpret_cast<PVOID*>(&m_pEnumerationProperties));
+ if (!NT_SUCCESS(status) || nullptr == m_pEnumerationProperties)
+ {
+ TraceError("ACT %!FUNC! WdfMemoryCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ 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_ActivityDetection,
+ &(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"Fake ACTIVITY V2",
+ &(m_pEnumerationProperties->List[SENSOR_MODEL].Value));
+
+ m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId;
+ InitPropVariantFromCLSID(GUID_ActivityDevice_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_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary;
+ InitPropVariantFromBoolean(FALSE,
+ &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value));
+
+ m_pEnumerationProperties->List[SENSOR_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms;
+ InitPropVariantFromUInt32(Act_Default_MinDataInterval_Ms,
+ &(m_pEnumerationProperties->List[SENSOR_MIN_INTERVAL].Value));
+
+ m_pEnumerationProperties->List[SENSOR_POWER].Key = PKEY_Sensor_Power_Milliwatts;
+ InitPropVariantFromFloat((m_HistoryPowerInuW / 1000.0f),
+ &(m_pEnumerationProperties->List[SENSOR_POWER].Value));
+
+ m_pEnumerationProperties->List[SENSOR_SUPPORTEDACTIVITIES].Key = PKEY_SensorData_SupportedActivityStates;
+ InitPropVariantFromUInt32(Act_Default_SubscribedStates,
+ &(m_pEnumerationProperties->List[SENSOR_SUPPORTEDACTIVITIES].Value));
+
+ m_pEnumerationProperties->List[SENSOR_MAX_HISTORYSIZE].Key = PKEY_SensorHistory_MaxSize_Bytes;
+ InitPropVariantFromUInt32(SENSOR_COLLECTION_LIST_HEADER_SIZE + ((m_HistoryMarshalledRecordSize - SENSOR_COLLECTION_LIST_HEADER_SIZE) * m_HistorySizeInRecords),
+ &(m_pEnumerationProperties->List[SENSOR_MAX_HISTORYSIZE].Value)); // History only logs one most probable state
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// This routine initializes the sensor's properties
+NTSTATUS ActivityDevice::InitializeSensorProperties()
+{
+ WDF_OBJECT_ATTRIBUTES memoryAttributes = {};
+ WDFMEMORY memoryHandle = NULL;
+ const ULONG size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTIES_COUNT);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
+ memoryAttributes.ParentObject = m_SensorInstance;
+ status = WdfMemoryCreate(&memoryAttributes,
+ PagedPool,
+ SENSOR_POOL_TAG_ACTIVITY,
+ size,
+ &memoryHandle,
+ reinterpret_cast<PVOID*>(&m_pProperties));
+ if (!NT_SUCCESS(status) || nullptr == m_pProperties)
+ {
+ TraceError("ACT %!FUNC! WdfMemoryCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ 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(Act_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_pLastSample),
+ &(m_pProperties->List[SENSOR_PROPERTY_MAX_DATAFIELDSIZE].Value));
+
+ m_pProperties->List[SENSOR_PROPERTY_SENSOR_TYPE].Key = PKEY_Sensor_Type;
+ InitPropVariantFromCLSID(GUID_SensorType_ActivityDetection,
+ &(m_pProperties->List[SENSOR_PROPERTY_SENSOR_TYPE].Value));
+
+ m_pProperties->List[SENSOR_PROPERTY_SENSOR_POWER].Key = PKEY_Sensor_Power_Milliwatts;
+ InitPropVariantFromFloat((m_HistoryPowerInuW / 1000.0f),
+ &(m_pProperties->List[SENSOR_PROPERTY_SENSOR_POWER].Value));
+
+ m_pProperties->List[SENSOR_PROPERTY_SUPPORTEDACTIVITIES].Key = PKEY_SensorData_SupportedActivityStates;
+ InitPropVariantFromUInt32(Act_Default_SubscribedStates,
+ &(m_pProperties->List[SENSOR_PROPERTY_SUPPORTEDACTIVITIES].Value));
+
+ m_pProperties->List[SENSOR_PROPERTY_MAX_HISTORYSIZE].Key = PKEY_SensorHistory_MaxSize_Bytes;
+ InitPropVariantFromUInt32(SENSOR_COLLECTION_LIST_HEADER_SIZE + ((m_HistoryMarshalledRecordSize - SENSOR_COLLECTION_LIST_HEADER_SIZE) * m_HistorySizeInRecords),
+ &(m_pProperties->List[SENSOR_PROPERTY_MAX_HISTORYSIZE].Value)); // History only logs one most probable state
+
+ m_pProperties->List[SENSOR_PROPERTY_HISTORY_INTERVAL].Key = PKEY_SensorHistory_Interval_Ms;
+ InitPropVariantFromUInt32(m_HistoryIntervalInMs,
+ &(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));
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// This routine initializes the data field properties
+NTSTATUS ActivityDevice::InitializeDataFieldProperties()
+{
+ WDF_OBJECT_ATTRIBUTES memoryAttributes = {};
+ WDFMEMORY memoryHandle = NULL;
+ const ULONG size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
+ memoryAttributes.ParentObject = m_SensorInstance;
+ status = WdfMemoryCreate(&memoryAttributes,
+ PagedPool,
+ SENSOR_POOL_TAG_ACTIVITY,
+ size,
+ &memoryHandle,
+ reinterpret_cast<PVOID*>(&m_pDataFieldProperties));
+ if (!NT_SUCCESS(status) || nullptr == m_pDataFieldProperties)
+ {
+ TraceError("ACT %!FUNC! WdfMemoryCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, size);
+ m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT;
+
+ m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution;
+ InitPropVariantFromFloat(ActivityFakeDevice_Confidence_Resolution,
+ &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value));
+
+ m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum;
+ InitPropVariantFromFloat(ActivityFakeDevice_Confidence_Minimum,
+ &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value));
+
+ m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum;
+ InitPropVariantFromFloat(ActivityFakeDevice_Confidence_Maximum,
+ &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value));
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// This routine initializes the supported data fields
+NTSTATUS ActivityDevice::InitializeSupportedDataFields()
+{
+ WDF_OBJECT_ATTRIBUTES memoryAttributes = {};
+ WDFMEMORY memoryHandle = NULL;
+ const ULONG size = SENSOR_PROPERTY_LIST_SIZE(ACTIVITY_DATA_COUNT);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
+ memoryAttributes.ParentObject = m_SensorInstance;
+ status = WdfMemoryCreate(&memoryAttributes,
+ PagedPool,
+ SENSOR_POOL_TAG_ACTIVITY,
+ size,
+ &memoryHandle,
+ reinterpret_cast<PVOID*>(&m_pSupportedDataFields));
+ if (!NT_SUCCESS(status) || nullptr == m_pSupportedDataFields)
+ {
+ TraceError("ACT %!FUNC! WdfMemoryCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, size);
+ m_pSupportedDataFields->Count = ACTIVITY_DATA_COUNT;
+
+ m_pSupportedDataFields->List[ACTIVITY_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp;
+ m_pSupportedDataFields->List[ACTIVITY_DATA_CURRENT_STATE] = PKEY_SensorData_CurrentActivityState;
+ m_pSupportedDataFields->List[ACTIVITY_DATA_CURRENT_CONFIDENCE] = PKEY_SensorData_CurrentActivityStateConfidence_Percentage;
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// This routine initializes the sensor to its default properties
+NTSTATUS ActivityDevice::Initialize(
+ _In_ WDFDEVICE device, // WDFDEVICE object
+ _In_ SENSOROBJECT sensorInstance) // SENSOROBJECT for each sensor instance
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Initial configuration
+ m_FxDevice = device;
+ m_SensorInstance = sensorInstance;
+ m_Interval = Act_Default_MinDataInterval_Ms;
+ m_FirstSample = TRUE;
+ m_Started = FALSE;
+ m_HistorySizeInRecords = Act_Default_MaxHistoryEntries;
+ m_HistoryPowerInuW = Act_Default_Power_uW;
+ m_HistoryIntervalInMs = Act_Default_HistoryInterval_Ms;
+ m_HistoryStarted = FALSE;
+ m_HistoryRetrievalStarted = FALSE;
+ m_History.FirstElemIndex = 0;
+ m_History.LastElemIndex = 0;
+ m_History.NumOfElems = 0;
+ m_History.BufferLength = m_HistorySizeInRecords;
+ m_hThread = NULL;
+
+ // Initialize the activity simulator
+ status = HardwareSimulator::Initialize(device, &m_SimulatorInstance);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! HardwareSimulator::Initialize failed %!STATUS!", status);
+ status = STATUS_SUCCESS; // Failed to set up simulator should not fail the driver
+ }
+
+ // Create Lock
+ status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! WdfWaitLockCreate failed %!STATUS!", status);
+ }
+
+ // Create history lock
+ if (NT_SUCCESS(status))
+ {
+ status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_HistoryLock);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! WdfWaitLockCreate failed %!STATUS!", status);
+ }
+ }
+
+ // Create timer object for polling sensor samples
+ if (NT_SUCCESS(status))
+ {
+ WDF_OBJECT_ATTRIBUTES timerAttributes = {};
+ WDF_TIMER_CONFIG timerConfig = {};
+
+ WDF_TIMER_CONFIG_INIT(&timerConfig, ActivityDevice::OnTimerExpire);
+ WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
+ timerAttributes.ParentObject = sensorInstance;
+ timerAttributes.ExecutionLevel = WdfExecutionLevelPassive;
+
+ status = WdfTimerCreate(&timerConfig, &timerAttributes, &m_Timer);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! WdfTimerCreate failed %!STATUS!", status);
+ }
+ }
+
+ // Create timer object for keeping history
+ if (NT_SUCCESS(status))
+ {
+ WDF_OBJECT_ATTRIBUTES timerAttributes = {};
+ WDF_TIMER_CONFIG timerConfig = {};
+
+ WDF_TIMER_CONFIG_INIT(&timerConfig, ActivityDevice::OnHistoryTimerExpire);
+ WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes);
+ timerAttributes.ParentObject = sensorInstance;
+ timerAttributes.ExecutionLevel = WdfExecutionLevelPassive;
+
+ status = WdfTimerCreate(&timerConfig, &timerAttributes, &m_HistoryTimer);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! WdfTimerCreate for history failed %!STATUS!", status);
+ }
+ }
+
+ // Last available data
+ if (NT_SUCCESS(status))
+ {
+ // Allocate a buffer for max state count. 7 States and 1 timestamp, each
+ // state has activity and confidence. The actual size will be adjusted when
+ // data is ready to be pushed to clx.
+ const ULONG size = SENSOR_COLLECTION_LIST_SIZE(Act_Max_State_Count * 2 + 1);
+ WDF_OBJECT_ATTRIBUTES memoryAttributes = {};
+ WDFMEMORY memoryHandle = NULL;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
+ memoryAttributes.ParentObject = sensorInstance;
+ status = WdfMemoryCreate(&memoryAttributes,
+ PagedPool,
+ SENSOR_POOL_TAG_ACTIVITY,
+ size,
+ &memoryHandle,
+ reinterpret_cast<PVOID*>(&m_pLastSample));
+ if (!NT_SUCCESS(status) || nullptr == m_pLastSample)
+ {
+ TraceError("ACT %!FUNC! WdfMemoryCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ FILETIME time = {};
+ SENSOR_COLLECTION_LIST_INIT(m_pLastSample, size);
+ m_pLastSample->Count = Act_Max_State_Count * 2 + 1;
+ m_pLastSample->List[ACTIVITY_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp;
+ InitPropVariantFromFileTime(&time, &(m_pLastSample->List[ACTIVITY_DATA_TIMESTAMP].Value));
+ for (ULONG Count = 1; Count < Act_Max_State_Count * 2 + 1; Count += 2)
+ {
+ m_pLastSample->List[Count].Key = PKEY_SensorData_CurrentActivityState;
+ InitPropVariantFromUInt32(ActivityState_Stationary, &(m_pLastSample->List[Count].Value));
+ m_pLastSample->List[Count + 1].Key = PKEY_SensorData_CurrentActivityStateConfidence_Percentage;
+ InitPropVariantFromUInt16(100, &(m_pLastSample->List[Count + 1].Value));
+ }
+ }
+ }
+
+ // Filtered data
+ if (NT_SUCCESS(status) && nullptr != m_pLastSample && 0 != m_pLastSample->AllocatedSizeInBytes)
+ {
+ WDF_OBJECT_ATTRIBUTES memoryAttributes = {};
+ WDFMEMORY memoryHandle = NULL;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
+ memoryAttributes.ParentObject = sensorInstance;
+ status = WdfMemoryCreate(&memoryAttributes,
+ PagedPool,
+ SENSOR_POOL_TAG_ACTIVITY,
+ m_pLastSample->AllocatedSizeInBytes,
+ &memoryHandle,
+ reinterpret_cast<PVOID*>(&m_pFilteredSample));
+ if (!NT_SUCCESS(status) || nullptr == m_pFilteredSample)
+ {
+ TraceError("ACT %!FUNC! WdfMemoryCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ // It's safe to memcpy because there is no embedded pointer
+ memcpy_s(m_pFilteredSample, m_pLastSample->AllocatedSizeInBytes, m_pLastSample, m_pLastSample->AllocatedSizeInBytes);
+ }
+ }
+
+ // Get the Marshalled size for a single history record
+ if (NT_SUCCESS(status))
+ {
+ // Set the count to 3, as the History Record contains information about only
+ // the most probable activity (unlike the Activity Data that can represent multiple activities)
+ // { Timestamp, ActivityState, Confidence}
+ m_pFilteredSample->Count = 3;
+ // 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_pFilteredSample);
+ }
+
+ // Sensor Properties. This must be called after setting up m_pLastSample and m_HistoryMarshalledRecordSize
+ if (NT_SUCCESS(status))
+ {
+ status = InitializeSensorProperties();
+ }
+
+ // Sensor Enumeration Properties.
+ if (NT_SUCCESS(status))
+ {
+ status = InitializeEnumerationProperties();
+ }
+
+ // Supported Data-Fields
+ if (NT_SUCCESS(status))
+ {
+ status = InitializeSupportedDataFields();
+ }
+
+ // Data field properties
+ if (NT_SUCCESS(status))
+ {
+ status = InitializeDataFieldProperties();
+ }
+
+ // Set default threshold
+ if (NT_SUCCESS(status))
+ {
+ const ULONG size = SENSOR_COLLECTION_LIST_SIZE(ACTIVITY_THRESHOLD_COUNT);
+ WDF_OBJECT_ATTRIBUTES memoryAttributes = {};
+ WDFMEMORY memoryHandle = NULL;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
+ memoryAttributes.ParentObject = sensorInstance;
+ status = WdfMemoryCreate(&memoryAttributes,
+ PagedPool,
+ SENSOR_POOL_TAG_ACTIVITY,
+ size,
+ &memoryHandle,
+ reinterpret_cast<PVOID*>(&m_pThresholds));
+ if (!NT_SUCCESS(status) || nullptr == m_pThresholds)
+ {
+ TraceError("ACT %!FUNC! WdfMemoryCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ SENSOR_COLLECTION_LIST_INIT(m_pThresholds, size);
+ m_pThresholds->Count = ACTIVITY_THRESHOLD_COUNT;
+
+ m_pThresholds->List[ACTIVITY_THRESHOLD_SUBSCRIBED_STATES].Key = PKEY_SensorData_SubscribedActivityStates;
+ InitPropVariantFromUInt32(Act_Default_SubscribedStates,
+ &(m_pThresholds->List[ACTIVITY_THRESHOLD_SUBSCRIBED_STATES].Value));
+
+ m_pThresholds->List[ACTIVITY_THRESHOLD_STREAMING].Key = PKEY_SensorData_ActivityStream;
+ InitPropVariantFromBoolean(Act_Default_Streaming,
+ &(m_pThresholds->List[ACTIVITY_THRESHOLD_STREAMING].Value));
+
+ m_pThresholds->List[ACTIVITY_THRESHOLD_CONFIDENCE].Key = PKEY_SensorData_ConfidenceThreshold_Percentage;
+ InitPropVariantFromUInt16(Act_Default_ConfidenceThreshold_Percentage,
+ &(m_pThresholds->List[ACTIVITY_THRESHOLD_CONFIDENCE].Value));
+ }
+ }
+
+ // Initialize history buffer
+ if (NT_SUCCESS(status))
+ {
+ const ULONG size = sizeof(ActivitySample) * m_HistorySizeInRecords;
+ WDF_OBJECT_ATTRIBUTES memoryAttributes = {};
+ WDFMEMORY memoryHandle = NULL;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&memoryAttributes);
+ memoryAttributes.ParentObject = sensorInstance;
+ status = WdfMemoryCreate(&memoryAttributes,
+ PagedPool,
+ SENSOR_POOL_TAG_ACTIVITY,
+ size,
+ &memoryHandle,
+ reinterpret_cast<PVOID*>(&(m_History.pData)));
+ if (!NT_SUCCESS(status) || nullptr == m_History.pData)
+ {
+ TraceError("ACT %!FUNC! WdfMemoryCreate failed %!STATUS!", status);
+ }
+ }
+
+ // Create event for signaling the history retrieval thread to exit
+ if (NT_SUCCESS(status))
+ {
+ m_ExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (NULL == m_ExitEvent || INVALID_HANDLE_VALUE == m_ExitEvent)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! Failed to create an event %!STATUS!", status);
+ }
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// This routine is the AddDevice entry point for the fake activity 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 ActivityDevice::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
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Initialize FDO attributes and set up file object with sensor extension
+ WDF_OBJECT_ATTRIBUTES fdoAttributes = {};
+ ULONG flag = 0;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&fdoAttributes);
+ status = SensorsCxDeviceInitConfig(pDeviceInit, &fdoAttributes, flag);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! SensorsCxDeviceInitConfig failed %!STATUS!", status);
+ }
+ else
+ {
+ WDF_PNPPOWER_EVENT_CALLBACKS callbacks = {};
+ WDFDEVICE device = NULL;
+
+ // Register the PnP callbacks with the framework.
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&callbacks);
+ callbacks.EvtDevicePrepareHardware = ActivityDevice::OnPrepareHardware;
+ callbacks.EvtDeviceReleaseHardware = ActivityDevice::OnReleaseHardware;
+ callbacks.EvtDeviceD0Entry = ActivityDevice::OnD0Entry;
+ callbacks.EvtDeviceD0Exit = ActivityDevice::OnD0Exit;
+ WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &callbacks);
+
+ // Call the framework to create the device
+ status = WdfDeviceCreate(&pDeviceInit, &fdoAttributes, &device);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! WdfDeviceCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ SENSOR_CONTROLLER_CONFIG sensorConfig = {};
+
+ // Register CLX callback function pointers
+ SENSOR_CONTROLLER_CONFIG_INIT(&sensorConfig);
+ sensorConfig.DriverIsPowerPolicyOwner = WdfUseDefault;
+
+ sensorConfig.EvtSensorStart = ActivityDevice::OnStart;
+ sensorConfig.EvtSensorStop = ActivityDevice::OnStop;
+ sensorConfig.EvtSensorGetSupportedDataFields = ActivityDevice::OnGetSupportedDataFields;
+ sensorConfig.EvtSensorGetDataInterval = ActivityDevice::OnGetDataInterval;
+ sensorConfig.EvtSensorSetDataInterval = ActivityDevice::OnSetDataInterval;
+ sensorConfig.EvtSensorGetDataFieldProperties = ActivityDevice::OnGetDataFieldProperties;
+ sensorConfig.EvtSensorGetDataThresholds = ActivityDevice::OnGetDataThresholds;
+ sensorConfig.EvtSensorSetDataThresholds = ActivityDevice::OnSetDataThresholds;
+ sensorConfig.EvtSensorGetProperties = ActivityDevice::OnGetProperties;
+ sensorConfig.EvtSensorDeviceIoControl = ActivityDevice::OnIoControl;
+ sensorConfig.EvtSensorStartHistory = ActivityDevice::OnStartHistory;
+ sensorConfig.EvtSensorStopHistory = ActivityDevice::OnStopHistory;
+ sensorConfig.EvtSensorClearHistory = ActivityDevice::OnClearHistory;
+ sensorConfig.EvtSensorStartHistoryRetrieval = ActivityDevice::OnStartHistoryRetrieval;
+ sensorConfig.EvtSensorCancelHistoryRetrieval = ActivityDevice::OnCancelHistoryRetrieval;
+
+ // Set up power capabilities and IO queues
+ status = SensorsCxDeviceInitialize(device, &sensorConfig);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! SensorsCxDeviceInitialize failed %!STATUS!", status);
+ }
+ }
+ }
+
+ 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 ActivityDevice::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.
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Create WDFOBJECT for the sensor
+ WDF_OBJECT_ATTRIBUTES sensorAttributes = {};
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&sensorAttributes, ActivityDevice);
+
+ // Register sensor instance with clx
+ SENSOROBJECT sensorInstance = NULL;
+ status = SensorsCxSensorCreate(device, &sensorAttributes, &sensorInstance);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! SensorsCxSensorCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! GetActivityContextFromSensorInstance failed %!STATUS!", status);
+ }
+ else
+ {
+ // Fill out properties
+ status = pDevice->Initialize(device, sensorInstance);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! Initialize device object failed %!STATUS!", status);
+ }
+ else
+ {
+ SENSOR_CONFIG sensorConfig = {};
+ SENSOR_CONFIG_INIT(&sensorConfig);
+ sensorConfig.pEnumerationList = pDevice->m_pEnumerationProperties;
+ status = SensorsCxSensorInitialize(sensorInstance, &sensorConfig);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! SensorsCxSensorInitialize failed %!STATUS!", status);
+ }
+ }
+ }
+ }
+
+ 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.
+NTSTATUS ActivityDevice::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.
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Get sensor instance
+ SENSOROBJECT sensorInstance = NULL;
+ ULONG sensorInstanceCount = 1; // only expect 1 sensor instance
+
+ status = SensorsCxDeviceGetSensorList(device, &sensorInstance, &sensorInstanceCount);
+ if (!NT_SUCCESS(status) || sensorInstanceCount == 0 || sensorInstance == NULL)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", status);
+ }
+ else
+ {
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! GetActivityContextFromSensorInstance failed %!STATUS!", status);
+ }
+ else
+ {
+ // Cleanup activity simulator
+ if (NULL != pDevice->m_SimulatorInstance)
+ {
+ PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance);
+ if (nullptr != pSimulator)
+ {
+ pSimulator->Deinitialize();
+ }
+ // Continue tearing down
+ WdfObjectDelete(pDevice->m_SimulatorInstance);
+ pDevice->m_SimulatorInstance = NULL;
+ }
+
+ // Close handle to history retrieval thread
+ if (NULL != pDevice->m_hThread)
+ {
+ SetEvent(pDevice->m_ExitEvent);
+
+ DWORD result = WaitForSingleObjectEx(pDevice->m_hThread, Act_TimeoutForHistoryThread_Ms, FALSE);
+ if (WAIT_OBJECT_0 != result)
+ {
+ // continue tearing down
+ status = NTSTATUS_FROM_WIN32(result);
+ TraceError("ACT %!FUNC! WaitForSingleObjectEx failed %!STATUS!", status);
+ }
+
+ CloseHandle(pDevice->m_hThread);
+ pDevice->m_hThread = NULL;
+ }
+
+ // Close handle to exit event
+ if (NULL != pDevice->m_ExitEvent)
+ {
+ CloseHandle(pDevice->m_ExitEvent);
+ pDevice->m_ExitEvent = NULL;
+ }
+
+ // Delete history lock
+ if (NULL != pDevice->m_HistoryLock)
+ {
+ WdfObjectDelete(pDevice->m_HistoryLock);
+ pDevice->m_HistoryLock = NULL;
+ }
+
+ // Delete lock
+ if (NULL != pDevice->m_Lock)
+ {
+ WdfObjectDelete(pDevice->m_Lock);
+ pDevice->m_Lock = NULL;
+ }
+
+ // Delete sensor instance.
+ if (NULL != pDevice->m_SensorInstance)
+ {
+ // Memory created by WdfMemoryCreate with m_SensorInstance as parent object will be
+ // destroyed automatically when m_SensorInstance is deleted. pDevice will be no longer
+ // accessible at beyond this point.
+ WdfObjectDelete(pDevice->m_SensorInstance);
+ pDevice = nullptr;
+ }
+ }
+ }
+
+ 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 ActivityDevice::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.
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Get sensor instance
+ SENSOROBJECT sensorInstance = NULL;
+ ULONG sensorInstanceCount = 1;
+
+ status = SensorsCxDeviceGetSensorList(device, &sensorInstance, &sensorInstanceCount);
+ if (!NT_SUCCESS(status) || sensorInstanceCount == 0 || sensorInstance == NULL)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", status);
+ }
+ else
+ {
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! GetActivityContextFromSensorInstance failed %!STATUS!", status);
+ }
+ else
+ {
+ // Power on sensor
+ pDevice->m_PoweredOn = TRUE;
+ InitPropVariantFromUInt32(SensorState_Idle, &(pDevice->m_pProperties->List[SENSOR_PROPERTY_STATE].Value));
+ }
+ }
+
+ 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 ActivityDevice::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.
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Get sensor instance
+ SENSOROBJECT sensorInstance = NULL;
+ ULONG sensorInstanceCount = 1;
+ status = SensorsCxDeviceGetSensorList(device, &sensorInstance, &sensorInstanceCount);
+ if (!NT_SUCCESS(status) || sensorInstanceCount == 0 || sensorInstance == NULL)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", status);
+ }
+ else
+ {
+
+ PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance);
+ if (nullptr == pDevice)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! GetActivityContextFromSensorInstance failed %!STATUS!", status);
+ }
+ else
+ {
+ // Power off sensor
+ pDevice->m_PoweredOn = FALSE;
+ }
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+} \ No newline at end of file
diff --git a/sensors/Activity/driver.cpp b/sensors/Activity/driver.cpp
new file mode 100644
index 00000000..b501f30a
--- /dev/null
+++ b/sensors/Activity/driver.cpp
@@ -0,0 +1,55 @@
+// Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+// Abstract:
+// This module contains the implementation of entry and exit point of activity sample driver.
+//
+// Environment:
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "Device.h"
+#include "Driver.h"
+#include "Driver.tmh"
+
+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_ACTIVITY;
+
+ // Initialize the driver configuration structure.
+ WDF_DRIVER_CONFIG_INIT(&driverConfig, ActivityDevice::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("ACT %!FUNC! WdfDriverCreate failed: %!STATUS!", status);
+ }
+
+ SENSOR_FunctionExit(status);
+ return status;
+}
+
+// This routine is called when the driver unloads.
+VOID OnDriverUnload(_In_ WDFDRIVER driver)
+{
+ 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/Activity/hardwaresimulator.cpp b/sensors/Activity/hardwaresimulator.cpp
new file mode 100644
index 00000000..29d9203b
--- /dev/null
+++ b/sensors/Activity/hardwaresimulator.cpp
@@ -0,0 +1,276 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+// This module contains the implementation of the activity sample driver hardware simulator.
+//
+//Environment:
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "HardwareSimulator.h"
+#include "HardwareSimulator.tmh"
+
+static const ULONG SIMULATOR_HARDWARE_INTERVAL_SEC = 10;
+static const ULONG MAX_ACTIVITY_STATE_PER_SAMPLE = 4;
+
+// Simulated activity data
+const ActivitySample c_SimulatorData[][MAX_ACTIVITY_STATE_PER_SAMPLE] = {
+ // This is a 2D array. Each row is one activity sample. One activity sample consist one or more
+ // state and confidence pair.
+ { { {}, ActivityState_InVehicle, 40 }, { {}, ActivityState_Biking, 30 }, { {}, ActivityState_Walking, 20 }, { } }, // InVehicle 40%, Biking 30%, Walking 20%
+ { { {}, ActivityState_Biking, 45 }, { {}, ActivityState_InVehicle, 40 }, { {}, ActivityState_Fidgeting, 30 }, { {}, ActivityState_Walking, 20 } }, // Biking 45%, InVehicle 40% Fidgeting 30%, Walking 20%
+ { { {}, ActivityState_Idle, 80 }, { {}, ActivityState_InVehicle, 60 }, { {}, ActivityState_Biking, 35 }, { {}, ActivityState_Walking, 20 } }, // Idle 80%, InVehicle 60%, Biking 35%, Walking 20%
+ { { {}, ActivityState_InVehicle, 75 }, { {}, ActivityState_Idle, 55 }, { {}, ActivityState_Walking, 18 }, { } }, // InVehicle 75%, Idle 55%, Walking 18%
+ { { {}, ActivityState_Biking, 90 }, { }, { }, { } }, // Biking 90%
+};
+
+HardwareSimulator::HardwareSimulator() :
+ m_Index(0),
+ m_Lock(NULL),
+ m_State(SimulatorState_NotInitialized),
+ m_Timer(NULL)
+{
+}
+
+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 *pSimulatorInstance) // Instance of the WDF object for the simulator
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ *pSimulatorInstance = NULL;
+
+ // Create WDFOBJECT for the hardware simulator
+ WDF_OBJECT_ATTRIBUTES hardwareSimulatorAttributes = {};
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&hardwareSimulatorAttributes, HardwareSimulator);
+ hardwareSimulatorAttributes.ParentObject = device;
+
+ status = WdfObjectCreate(&hardwareSimulatorAttributes, pSimulatorInstance);
+ if (!NT_SUCCESS(status))
+ {
+ TraceError("ACT %!FUNC! WdfObjectCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(*pSimulatorInstance);
+ if (nullptr == pSimulator)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", status);
+ }
+ else
+ {
+ status = pSimulator->InitializeInternal(*pSimulatorInstance);
+ }
+ }
+
+ SENSOR_FunctionExit(status);
+
+ return status;
+}
+
+
+// Internal routine to perform simulator initialization
+NTSTATUS HardwareSimulator::InitializeInternal(_In_ WDFOBJECT SimulatorInstance)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ 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("ACT %!FUNC! WdfWaitLockCreate for m_Lock failed %!STATUS!", status);
+ }
+ else
+ {
+ WDF_OBJECT_ATTRIBUTES timerAttributes = {};
+ WDF_TIMER_CONFIG timerConfig = {};
+
+ // 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("ACT %!FUNC! WdfTimerCreate failed %!STATUS!", status);
+ }
+ else
+ {
+ // Set the simulator state to "initialized"
+ m_State = SimulatorState_Initialized;
+ }
+ }
+ }
+
+ if (!NT_SUCCESS(status) && NULL != m_Lock)
+ {
+ WdfObjectDelete(m_Lock);
+ m_Lock = NULL;
+ }
+
+ SENSOR_FunctionExit(status);
+
+ return status;
+}
+
+
+// This routine perform a simulator cleanup
+VOID HardwareSimulator::Deinitialize()
+{
+ if (SimulatorState_Started == m_State)
+ {
+ Stop();
+ }
+
+ // Delete lock. m_Timer will be deleted when the wdfobject is deleted
+ if (NULL != m_Lock)
+ {
+ WdfObjectDelete(m_Lock);
+ m_Lock = NULL;
+ }
+
+ // Set the simulator state to "not initialized"
+ m_State = SimulatorState_NotInitialized;
+}
+
+
+// This routine starts the simulator
+VOID HardwareSimulator::Start()
+{
+ SENSOR_FunctionEnter();
+
+ if (SimulatorState_Initialized == m_State)
+ {
+ WdfTimerStart(m_Timer, WDF_REL_TIMEOUT_IN_SEC(SIMULATOR_HARDWARE_INTERVAL_SEC));
+ m_State = SimulatorState_Started;
+ }
+
+ SENSOR_FunctionExit(STATUS_SUCCESS);
+}
+
+
+// This routine stops the simulator
+VOID HardwareSimulator::Stop()
+{
+ SENSOR_FunctionEnter();
+
+ if (SimulatorState_Started == m_State)
+ {
+ WdfTimerStop(m_Timer, TRUE);
+ m_State = SimulatorState_Initialized;
+ }
+
+ SENSOR_FunctionExit(STATUS_SUCCESS);
+}
+
+
+// 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)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(WdfTimerGetParentObject(timer));
+ if (nullptr == pSimulator)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("ACT %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", status);
+ }
+ else
+ {
+ // 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(c_SimulatorData);
+ WdfWaitLockRelease(pSimulator->m_Lock);
+ WdfTimerStart(pSimulator->m_Timer, WDF_REL_TIMEOUT_IN_SEC(SIMULATOR_HARDWARE_INTERVAL_SEC));
+ }
+
+ SENSOR_FunctionExit(status);
+}
+
+
+// This routine returns the current sample collection from the driver at the current m_Index location
+NTSTATUS HardwareSimulator::GetSample(_Inout_ PSENSOR_COLLECTION_LIST pSample)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSample ||
+ SENSOR_COLLECTION_LIST_SIZE(MAX_ACTIVITY_STATE_PER_SAMPLE * 2 + 1) > pSample->AllocatedSizeInBytes)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sample parameter is null");
+ }
+ else
+ {
+ pSample->Count = 1;
+
+ WdfWaitLockAcquire(m_Lock, NULL);
+ if (ARRAYSIZE(c_SimulatorData) > m_Index)
+ {
+ for (ULONG count = 0, index = 1;
+ count < MAX_ACTIVITY_STATE_PER_SAMPLE && NULL != c_SimulatorData[m_Index][count].Activity;
+ count++, index += 2)
+ {
+ pSample->List[index].Key = PKEY_SensorData_CurrentActivityState;
+ InitPropVariantFromUInt32(c_SimulatorData[m_Index][count].Activity, &(pSample->List[index].Value));
+
+ pSample->List[index + 1].Key = PKEY_SensorData_CurrentActivityStateConfidence_Percentage;
+ InitPropVariantFromUInt16(c_SimulatorData[m_Index][count].Confidence, &(pSample->List[index + 1].Value));
+
+ pSample->Count += 2;
+ }
+ }
+ WdfWaitLockRelease(m_Lock);
+ }
+
+ SENSOR_FunctionExit(status);
+
+ return status;
+}
+
+// This routine returns the current most probable sample from the driver at the current m_Index location
+NTSTATUS HardwareSimulator::GetSample(_Out_ PActivitySample pSample)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSample)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ TraceError("ACT %!FUNC! Sample parameter is null");
+ }
+ else
+ {
+ WdfWaitLockAcquire(m_Lock, NULL);
+ *pSample = c_SimulatorData[m_Index][0];
+ WdfWaitLockRelease(m_Lock);
+ }
+
+ SENSOR_FunctionExit(status);
+
+ return status;
+} \ No newline at end of file
diff --git a/sensors/CustomSensors/CustomSensors.def b/sensors/CustomSensors/CustomSensors.def
new file mode 100644
index 00000000..85e0bd6c
--- /dev/null
+++ b/sensors/CustomSensors/CustomSensors.def
@@ -0,0 +1,6 @@
+; CustomSensors.def : Declares the module parameters.
+
+LIBRARY CustomSensors
+
+EXPORTS
+
diff --git a/sensors/CustomSensors/CustomSensors.inx b/sensors/CustomSensors/CustomSensors.inx
new file mode 100644
index 00000000..b26b6848
--- /dev/null
+++ b/sensors/CustomSensors/CustomSensors.inx
Binary files differ
diff --git a/sensors/CustomSensors/CustomSensors.sln b/sensors/CustomSensors/CustomSensors.sln
new file mode 100644
index 00000000..7a56d3a7
--- /dev/null
+++ b/sensors/CustomSensors/CustomSensors.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}") = "CustomSensors", "CustomSensors.vcxproj", "{C7936A1F-21BA-40FD-AE64-CE2515F05934}"
+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
+ {C7936A1F-21BA-40FD-AE64-CE2515F05934}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C7936A1F-21BA-40FD-AE64-CE2515F05934}.Debug|Win32.Build.0 = Debug|Win32
+ {C7936A1F-21BA-40FD-AE64-CE2515F05934}.Release|Win32.ActiveCfg = Release|Win32
+ {C7936A1F-21BA-40FD-AE64-CE2515F05934}.Release|Win32.Build.0 = Release|Win32
+ {C7936A1F-21BA-40FD-AE64-CE2515F05934}.Debug|x64.ActiveCfg = Debug|x64
+ {C7936A1F-21BA-40FD-AE64-CE2515F05934}.Debug|x64.Build.0 = Debug|x64
+ {C7936A1F-21BA-40FD-AE64-CE2515F05934}.Release|x64.ActiveCfg = Release|x64
+ {C7936A1F-21BA-40FD-AE64-CE2515F05934}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/sensors/CustomSensors/CustomSensors.vcxproj b/sensors/CustomSensors/CustomSensors.vcxproj
new file mode 100644
index 00000000..113ddd23
--- /dev/null
+++ b/sensors/CustomSensors/CustomSensors.vcxproj
@@ -0,0 +1,204 @@
+<?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>{C7936A1F-21BA-40FD-AE64-CE2515F05934}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{44B5CD90-E5CF-456E-9A6C-C45CDBE2798D}</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>CustomSensors</WppModuleName>
+ <WppScanConfigurationData>sensorstrace.h</WppScanConfigurationData>
+ </ClCompile>
+ <Inf Include="CustomSensors.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\CustomSensors.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>CustomSensors</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>CustomSensors</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>CustomSensors</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>CustomSensors</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>CustomSensors.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>CustomSensors.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>CustomSensors.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>CustomSensors.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </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/CustomSensors/CustomSensors.vcxproj.Filters b/sensors/CustomSensors/CustomSensors.vcxproj.Filters
new file mode 100644
index 00000000..64faeaa5
--- /dev/null
+++ b/sensors/CustomSensors/CustomSensors.vcxproj.Filters
@@ -0,0 +1,43 @@
+<?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>{1291330B-BA98-4314-80CF-D3134BEDBBA6}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{9C6A940E-519A-42F6-A82D-26F842A0D171}</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>{6E878311-5CC7-4E2F-A368-13D99DB045D2}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{A229BB48-B83A-416A-8CF5-B15D4793A8C0}</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="CustomSensors.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="CustomSensors.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/sensors/CustomSensors/Device.h b/sensors/CustomSensors/Device.h
new file mode 100644
index 00000000..0679b137
--- /dev/null
+++ b/sensors/CustomSensors/Device.h
@@ -0,0 +1,138 @@
+//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>
+
+#include "HardwareSimulator.h"
+
+#define SENSORV2_POOL_TAG_CUSTOM_SENSOR 'mtsC'
+
+#define Cstm_Default_MinDataInterval_Ms (200) // 200 milliseconds interval is sufficient for this CO2 sensor
+
+
+// Sensor Common Properties
+typedef enum
+{
+ SENSOR_PROPERTY_STATE = 0,
+ SENSOR_PROPERTY_MIN_INTERVAL,
+ SENSOR_PROPERTY_MAX_DATAFIELDSIZE,
+ SENSOR_PROPERTY_SENSOR_TYPE,
+ 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,
+ SENSOR_ISPRIMARY,
+ SENSOR_VENDOR_DEFINED_TYPE,
+ 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
+{
+ CSTM_DATA_CO2_LEVEL_PERCENT = 0,
+ CSTM_DATA_TIMESTAMP,
+ CSTM_DATA_COUNT
+} CSTM_DATA_INDEX;
+
+typedef struct _CustomSensorSample
+{
+ FLOAT AtmosphericCO2Level;
+} CustomSensorSample, *PCustomSensorSample;
+
+typedef class _CustomSensorDevice
+{
+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;
+ ULONGLONG m_SampleCount;
+
+ CustomSensorSample m_LastSample;
+
+ // 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_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;
+
+private:
+
+ NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj);
+ NTSTATUS GetData();
+
+} CustomSensorDevice, *PCustomSensorDevice;
+
+// Set up accessor function to retrieve device context
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CustomSensorDevice, GetCustomSensorContextFromSensorInstance);
+
+#define CustomSensorDevice_Resolution (0.1f) // CO2 concentration resolution in parts per million (ppmv).
+#define CustomSensorDevice_Minimum_CO2Level (0.0f) // Minimum CO2 concentration in parts per million (ppmv).
+#define CustomSensorDevice_Maximum_CO2Level (10000.0f) // Maximum CO2 concentration in parts per million (ppmv). \ No newline at end of file
diff --git a/sensors/CustomSensors/Driver.h b/sensors/CustomSensors/Driver.h
new file mode 100644
index 00000000..d1470317
--- /dev/null
+++ b/sensors/CustomSensors/Driver.h
@@ -0,0 +1,19 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved
+//
+//Abstract:
+//
+// This module contains the type definitions for the fake custom sensor'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/CustomSensors/Gallery.xml b/sensors/CustomSensors/Gallery.xml
new file mode 100644
index 00000000..8f84093a
--- /dev/null
+++ b/sensors/CustomSensors/Gallery.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="../../buildx/script2/preview.xslt"?>
+<gallery_sample xmlns="http://microsoft.com/wdcml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://microsoft.com/wdcml ../../buildx/schema/xsd/wdcml.xsd">
+ <metadata id="gallery_samples.107a_gallery" type="gallery_sample" msdnID="7cba6311-f0db-4c3d-8f1f-25de8648b353">
+ <title>CustomSensors</title>
+ <!-- Add a devlang for each programming language in all versions of the sample. -->
+ <devlang value="cpp" />
+ <!-- Do not change tech value -->
+ <tech value="gallery_samples" />
+ <index />
+ <sample_langs>
+ <!-- Describes the languages to which the sample code itself has been localized. -->
+ <sample_lang xml:lang="en-us" />
+ </sample_langs>
+ </metadata>
+ <content>
+ <desc>
+ <p><abstract>The CustomSensors sample shows how to write a UMDF v2 driver to control a virtual CO2 sensor.</abstract></p>
+ </desc>
+ <outline />
+ <license_info>
+ <default_license />
+ </license_info>
+ <programming_models>
+ <programming_model value="win32" />
+ </programming_models>
+ <application_frameworks>
+ </application_frameworks>
+ <!-- For Driver Samples Only -->
+ <driver_models>
+ <!-- possible values: kmdf, umdf, wdm, ndis, wddm -->
+ <driver_model value="UMDF" />
+ </driver_models>
+ <driver_techs>
+ <driver_tech value="Windows Driver" />
+ </driver_techs>
+ <related_techs>
+ </related_techs>
+ <os_requirements>
+ <min_os>
+ <client name="winblue"/>
+ <server name="wbluesrv"/>
+ </min_os>
+ </os_requirements>
+ <required_sdks>
+ <min_sdk>
+ <tla rid="windows_driver_kit_8" />
+ </min_sdk>
+ </required_sdks>
+ <supported_ides>
+ <supported_ide>
+ <tla rid="tla_visualstu2012" />
+ </supported_ide>
+ </supported_ides>
+ <build_info>
+ <authored_instructions>
+ <section>
+ <!-- Include any special instructions for compiling your sample -->
+ <sectioncontents>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </build_info>
+ <run_info>
+ <authored_instructions>
+ <section>
+ <sectioncontents>
+ <p>To install the sample driver, follow these steps:</p>
+ <proch>
+ <item>Ensure that the driver builds without errors.</item>
+ <item>Copy the DLL and INF files to a separate folder.</item>
+ <item>Enter the command "<inline_code devlang="cmd">devcon.exe update CustomSensors.inf ACPI\&lt;HWID&gt;</inline_code>" to install the driver on an existing device node. You can find the devcon.exe program in the tools\devcon folder where you installed the WDK.</item>
+ </proch>
+ </sectioncontents>
+ </section>
+ <section>
+ <title>File manifest</title>
+ <sectioncontents>
+ <p>The following source files are in the src\Sensors\CustomSensors folder and are used to build the CustomSensors.dll and CustomSensors.inf files.</p>
+ <table>
+ <tr>
+ <th>File</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>
+ <p>device.h, device.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's WDF PnP event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>client.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's callback functions from the class extension to custom sensors.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>driver.h, driver.cpp</p>
+ </td>
+ <td>
+ <p>WDF driver entry event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>hardwaresimulator.h, hardwaresimulator.cpp</p>
+ </td>
+ <td>
+ <p>Hardware simulator implementation</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>makefile.inc</p>
+ </td>
+ <td>
+ <p>Defines custom build actions. Includes the conversion of the .INX file into a .INF file.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>SensorsTrace.h</p>
+ </td>
+ <td>
+ <p>Implementation the sensor traces files.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>CustomSensors.ctl</p>
+ </td>
+ <td>
+ <p>Declaration of driver's tracing GUID</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>CustomSensor.inx</p>
+ </td>
+ <td>
+ <p>Describes the installation of the driver. The build process converts this into a .INF.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>Trace.h</p>
+ </td>
+ <td>
+ <p>Sets up WPP tracing.</p>
+ </td>
+ </tr>
+ </table>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </run_info>
+ </content>
+ <!-- List the component compcentral path -->
+ <feature_teams>
+ <feature_team_info comp_central_path="CORE-OS Core\SiGMa-Silicon, Graphics and Media\SiPlat - Silicon Platform\Sensors" dev_owner="osamasal" writer_owner="ericdoku" />
+ </feature_teams>
+ <workflow_control_host />
+</gallery_sample>
diff --git a/sensors/CustomSensors/HardwareSimulator.h b/sensors/CustomSensors/HardwareSimulator.h
new file mode 100644
index 00000000..e170918b
--- /dev/null
+++ b/sensors/CustomSensors/HardwareSimulator.h
@@ -0,0 +1,57 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved
+//
+//Abstract:
+//
+// This module contains the type definitions for the custom sensor sample
+// hardware simulator.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#pragma once
+
+#include <windows.h>
+#include <wdf.h>
+
+#include <SensorsTrace.h>
+#include <SensorsCx.h>
+
+#define SIMULATOR_HARDWARE_INTERVAL_MS (100) // 100ms
+
+typedef enum _SIMULATOR_STATE
+{
+ SimulatorState_NotInitialized = 0,
+ SimulatorState_Initialized,
+ SimulatorState_Started
+} SIMULATOR_STATE;
+
+typedef class _HardwareSimulator
+{
+private:
+ WDFTIMER m_Timer;
+ ULONG m_Index;
+ WDFWAITLOCK m_Lock;
+ SIMULATOR_STATE m_State;
+ WDFOBJECT m_SimulatorInstance;
+
+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();
+ FLOAT GetSample();
+
+private:
+ NTSTATUS InitializeInternal(_In_ WDFOBJECT SimulatorInstance);
+
+} HardwareSimulator, *PHardwareSimulator;
+
+// Set up accessor function to retrieve device context
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(HardwareSimulator, GetHardwareSimulatorContextFromInstance);
diff --git a/sensors/CustomSensors/SensorsTrace.h b/sensors/CustomSensors/SensorsTrace.h
new file mode 100644
index 00000000..2e84827a
--- /dev/null
+++ b/sensors/CustomSensors/SensorsTrace.h
@@ -0,0 +1,153 @@
+//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 - FC04E08F-6981-4597-A879-311ED3882506
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ CustomSensorsTraceGuid, (FC04E08F,6981,4597,A879,311ED3882506), \
+ 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
+
+
+
+//
+// CLX ---------------------------------------------------------------------------------------------------
+//
+
+//MACRO: CLX_FunctionEnter
+//
+//begin_wpp config
+//USEPREFIX (CLX_FunctionEnter, "%!STDPREFIX! CLX %!FUNC! FunctionEnter");
+//FUNC CLX_FunctionEnter{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=EntryExit}(...);
+//end_wpp
+
+//MACRO: CLX_FunctionExit
+//
+//begin_wpp config
+//USEPREFIX (CLX_FunctionExit, "%!STDPREFIX! CLX %!FUNC! FunctionExit: %!STATUS!", __status);
+//FUNC CLX_FunctionExit{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=EntryExit}(CLXEXIT);
+//end_wpp
+#define WPP_LEVEL_FLAGS_CLXEXIT_ENABLED(LEVEL, FLAGS, status) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS)
+#define WPP_LEVEL_FLAGS_CLXEXIT_LOGGER(LEVEL, FLAGS, status) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS)
+
+#define WPP_LEVEL_FLAGS_CLXEXIT_PRE(LEVEL, FLAGS, status) { \
+ NTSTATUS __status = status;
+#define WPP_LEVEL_FLAGS_CLXEXIT_POST(LEVEL, FLAGS, status) /*TraceMessage()*/; \
+ }
+
+
+
+// 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()*/; \
+ }
+
+
+// SENSRSVC ------------------------------------------------------------------------------------------------
+
+//MACRO: SENSRSVC_FunctionEnter
+//
+//begin_wpp config
+//USEPREFIX (SENSRSVC_FunctionEnter, "%!STDPREFIX! SENSRSVC %!FUNC! FunctionEnter");
+//FUNC SENSRSVC_FunctionEnter{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=EntryExit}(...);
+//end_wpp
+
+//MACRO: SENSRSVC_FunctionExit
+//
+//begin_wpp config
+//USEPREFIX (SENSRSVC_FunctionExit, "%!STDPREFIX! SENSRSVC %!FUNC! FunctionExit: %!HRESULT!", __hr);
+//FUNC SENSRSVC_FunctionExit{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=EntryExit}(SENSRSVCEXIT);
+//end_wpp
+#define WPP_LEVEL_FLAGS_SENSRSVCEXIT_ENABLED(LEVEL, FLAGS, hr) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS)
+#define WPP_LEVEL_FLAGS_SENSRSVCEXIT_LOGGER(LEVEL, FLAGS, hr) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS)
+
+#define WPP_LEVEL_FLAGS_SENSRSVCEXIT_PRE(LEVEL, FLAGS, hr) { \
+ HRESULT __hr = hr;
+#define WPP_LEVEL_FLAGS_SENSRSVCEXIT_POST(LEVEL, FLAGS, hr) /*TraceMessage()*/; \
+ }
+
+
+
+// WPP Recorder -------------------------------------------------------------------------------------------
+//
+// The following two macros are required to enable WPP Recorder functionality for clients of the Sensor Class Extension
+//
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_FILTER(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS)
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_ARGS(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/sensors/CustomSensors/client.cpp b/sensors/CustomSensors/client.cpp
new file mode 100644
index 00000000..d3915d3d
--- /dev/null
+++ b/sensors/CustomSensors/client.cpp
@@ -0,0 +1,611 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of driver callback function
+// from clx to custom sensors.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "Device.h"
+#include <timeapi.h>
+
+#include "Client.tmh"
+
+// This routine is called by worker thread to read a single sample and push it back
+// to CLX.
+NTSTATUS CustomSensorDevice::GetData()
+{
+ PHardwareSimulator pSimulator = nullptr;
+ FILETIME TimeStamp = {};
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (FALSE != m_FirstSample)
+ {
+ Status = GetPerformanceTime(&m_StartTime);
+ if (!NT_SUCCESS(Status))
+ {
+ m_StartTime = 0;
+ TraceError("CSTM %!FUNC! GetPerformanceTime %!STATUS!", Status);
+ }
+
+ m_SampleCount = 0;
+ }
+
+ pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance);
+ if (nullptr == pSimulator)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("CSTM %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // push to clx
+ InitPropVariantFromFloat(pSimulator->GetSample(), &(m_pData->List[CSTM_DATA_CO2_LEVEL_PERCENT].Value));
+
+ GetSystemTimePreciseAsFileTime(&TimeStamp);
+ InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[CSTM_DATA_TIMESTAMP].Value));
+
+ SensorsCxSensorDataReady(m_SensorInstance, m_pData);
+ m_FirstSample = FALSE;
+
+Exit:
+ SENSOR_FunctionExit(Status);
+
+ 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,
+// pushes it up to CLX framework, and schedule next wake up time.
+VOID
+CustomSensorDevice::OnTimerExpire(
+ _In_ WDFTIMER Timer // WDF timer object
+ )
+{
+ PCustomSensorDevice pDevice = nullptr;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ pDevice = GetCustomSensorContextFromSensorInstance(WdfTimerGetParentObject(Timer));
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("CSTM %!FUNC! GetCustomSensorContextFromSensorInstance failed %!STATUS!", Status);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ // Get data and push to clx
+ WdfWaitLockAcquire(pDevice->m_Lock, NULL);
+ Status = pDevice->GetData();
+ if (!NT_SUCCESS(Status) && Status != STATUS_DATA_NOT_ACCEPTED)
+ {
+ TraceError("CSTM %!FUNC! GetCstmData 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
+ {
+ pDevice->m_SampleCount++;
+ if (CurrentTimeMs > (pDevice->m_StartTime + (pDevice->m_Interval * (pDevice->m_SampleCount + 1))))
+ {
+ // If we skipped two or more beats, reschedule the timer with a zero due time to catch up on missing samples
+ WaitTimeHundredNanoseconds = 0;
+ }
+ else
+ {
+ WaitTimeHundredNanoseconds = (pDevice->m_StartTime +
+ (pDevice->m_Interval * (pDevice->m_SampleCount + 1))) - CurrentTimeMs;
+ }
+ WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(WaitTimeHundredNanoseconds);
+ }
+ }
+ WdfTimerStart(pDevice->m_Timer, WaitTimeHundredNanoseconds);
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+}
+
+
+
+// Called by Sensor CLX to begin continously sampling the sensor.
+NTSTATUS
+CustomSensorDevice::OnStart(
+ _In_ SENSOROBJECT SensorInstance // sensor device object
+ )
+{
+ PHardwareSimulator pSimulator = nullptr;
+ PCustomSensorDevice pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("PED %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ // 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.
+ // Note1: the WDF timer is only as precise as the system resolution allows it to be.
+ // In the case of the CO2 sensor, the reporting interval is 200 milliseconds. The default
+ // system resolution (15.6 milliseconds) is therefore fine enough to guarantee an accurate sample
+ // reporting interval. Some sensors using a lower reporting interval may want to reduce the system
+ // time resolution by calling into timeBeginPeriod() before starting the polling timer.
+ //
+ // Important consideration: calling into timeBeginPeriod() should be used with care as it has
+ // an adverse on the system performance and power consumption.
+ //
+ // Note2: 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, 0);
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+
+
+// Called by Sensor CLX to stop continously sampling the sensor.
+NTSTATUS
+CustomSensorDevice::OnStop(
+ _In_ SENSOROBJECT SensorInstance // sensor device object
+ )
+{
+ PHardwareSimulator pSimulator = nullptr;
+ PCustomSensorDevice pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ // 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("CSTM %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pSimulator->Stop();
+ }
+
+Exit:
+ SENSOR_FunctionExit(Status);
+
+ return Status;
+}
+
+
+
+
+// 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
+CustomSensorDevice::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
+ )
+{
+ PCustomSensorDevice pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! pSize: Invalid parameter! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ *pSize = 0;
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! pDevice: Invalid parameter! %!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("CSTM %!FUNC! Buffer is too small. Failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Fill out data
+ Status = PropertiesListCopy (pFields, pDevice->m_pSupportedDataFields);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("CSTM %!FUNC! PropertiesListCopy failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ *pSize = pDevice->m_pSupportedDataFields->AllocatedSizeInBytes;
+ }
+
+Exit:
+ 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
+CustomSensorDevice::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
+ )
+{
+ PCustomSensorDevice pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! pSize: Invalid parameter! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ *pSize = 0;
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! pDevice: Invalid parameter! %!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("CSTM %!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("CSTM %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pProperties);
+ }
+
+Exit:
+ 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
+CustomSensorDevice::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
+)
+{
+ PCustomSensorDevice pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! pSize: Invalid parameter! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ *pSize = 0;
+
+ if (nullptr == pDevice || nullptr == DataField)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! Invalid parameters! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ if ((*DataField == pDevice->m_pSupportedDataFields->List[CSTM_DATA_CO2_LEVEL_PERCENT]))
+ {
+ if (nullptr == pProperties)
+ {
+ // Just return size
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties);
+ }
+ else
+ {
+ if (pProperties->AllocatedSizeInBytes <
+ CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties))
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("CSTM %!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("CSTM %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties);
+ }
+ }
+ else
+ {
+ Status = STATUS_NOT_SUPPORTED;
+ TraceError("CSTM %!FUNC! CustomSensor does NOT have properties for this data field. Failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+Exit:
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+
+
+// Called by Sensor CLX to get sampling rate of the sensor.
+NTSTATUS
+CustomSensorDevice::OnGetDataInterval(
+ _In_ SENSOROBJECT SensorInstance, // sensor device object
+ _Out_ PULONG DataRateMs // sampling rate in milliseconds
+ )
+{
+ PCustomSensorDevice pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ goto Exit;
+ }
+
+ if (nullptr == DataRateMs)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! DataRateMs(0x%p) parameter is invalid. Failed %!STATUS!", 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
+CustomSensorDevice::OnSetDataInterval(
+ _In_ SENSOROBJECT SensorInstance, // sensor device object
+ _In_ ULONG DataRateMs // sampling rate in milliseconds
+ )
+{
+ PCustomSensorDevice pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice || Cstm_Default_MinDataInterval_Ms > DataRateMs)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ goto Exit;
+ }
+
+ if (Cstm_Default_MinDataInterval_Ms > DataRateMs)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! DataRateMs(%d) parameter is smaller than the minimum data interval. Failed %!STATUS!", DataRateMs, 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(Cstm_Default_MinDataInterval_Ms));
+ }
+
+Exit:
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+
+
+// UNSUPPORTED at this point of time
+NTSTATUS
+CustomSensorDevice::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
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ SENSOR_COLLECTION_LIST emptyList = {};
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! Invalid parameters! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Even though thresholds are not yet supported for custom sensors,
+ // the minimum reported size must be that of an empty list for the
+ // class extension to work properly
+ emptyList.AllocatedSizeInBytes = sizeof(emptyList);
+
+ *pSize = CollectionsListGetMarshalledSize(&emptyList);
+
+ SENSOR_FunctionExit(Status);
+
+Exit:
+ return Status;
+}
+
+
+
+// UNSUPPORTED at this point of time
+NTSTATUS
+CustomSensorDevice::OnSetDataThresholds(
+ _In_ SENSOROBJECT /*SensorInstance*/, // sensor device object
+ _In_ PSENSOR_COLLECTION_LIST /*pThresholds*/ // pointer to a list of sensor thresholds
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ // Usupported at this point in time
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+
+
+// Called by Sensor CLX to handle IOCTLs that clx does not support
+NTSTATUS
+CustomSensorDevice::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;
+}
diff --git a/sensors/CustomSensors/device.cpp b/sensors/CustomSensors/device.cpp
new file mode 100644
index 00000000..c08a0eb6
--- /dev/null
+++ b/sensors/CustomSensors/device.cpp
@@ -0,0 +1,601 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of WDF callback functions
+// for sample custom sensor driver.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "Device.h"
+
+#include "Device.tmh"
+
+// Custom sensor unique ID
+// {A8B27439-C671-401E-B4EF-43D700A5B411}
+//
+// 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_CustomSensorDevice_UniqueID,
+ 0xa8b27439, 0xc671, 0x401e, 0xb4, 0xef, 0x43, 0xd7, 0x0, 0xa5, 0xb4, 0x11);
+
+// Custom sensor vendor defined type
+//
+// The following ID is defined by vendors and is unique to a custom sensor type. Each custom sensor driver should define one unique ID.
+//
+// TODO: The ID below identifies the custom sensor CO2 emulation sample driver. Please generate a new GUID for each new type of driver.
+//
+// {4025A865-638C-43AA-A688-98580961EEAE}
+DEFINE_GUID(GUID_CustomSensorDevice_VendorDefinedSubTypeID,
+ 0x4025a865, 0x638c, 0x43aa, 0xa6, 0x88, 0x98, 0x58, 0x9, 0x61, 0xee, 0xae);
+
+// Vendor defined property keys
+//
+// A property key is defined by vendors for each datafield property a custom sensor driver exposes. Property keys are defined
+// per custom sensor driver and is unique to each custom sensor type.
+//
+// The following property key represents the CO2 level datafield exposed by this driver.
+// In this example only one key is defined, but other drivers may define more than one key by rev'ing up the property key index.
+//
+// TODO: The PROPERTYKEY below identifies the custom sensor CO2 level property key. Please generate a new GUID for each new type of driver.
+//
+// {74879888-a3cc-45c6-9ea9-058838256433} 1
+DEFINE_PROPERTYKEY(PKEY_CustomSensorSampleData_CO2Level,
+ 0x74879888, 0xa3cc, 0x45c6, 0x9e, 0xa9, 0x5, 0x88, 0x38, 0x25, 0x64, 0x33, 1); //[VT_R4]
+
+
+
+// This routine initializes the sensor to its default properties
+NTSTATUS CustomSensorDevice::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;
+
+ SENSOR_FunctionEnter();
+
+ // Store device and instance
+ m_FxDevice = Device;
+ m_SensorInstance = SensorInstance;
+ m_Started = FALSE;
+
+ // Initialize the CO2 simulator
+ HardwareSimulator::Initialize(Device, &m_SimulatorInstance);
+
+ // Create Lock
+ Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("CSTM %!FUNC! WdfWaitLockCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Create timer object for polling sensor samples
+ WDF_TIMER_CONFIG_INIT(&TimerConfig, CustomSensorDevice::OnTimerExpire);
+ WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes);
+ TimerAttributes.ParentObject = SensorInstance;
+ TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive;
+
+ Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("CSTM %!FUNC! WdfTimerCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // 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,
+ SENSORV2_POOL_TAG_CUSTOM_SENSOR,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pEnumerationProperties));
+ if (!NT_SUCCESS(Status) || nullptr == m_pEnumerationProperties)
+ {
+ TraceError("CSTM %!FUNC! WdfMemoryCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size);
+ m_pEnumerationProperties->Count = SENSOR_ENUMERATION_PROPERTIES_COUNT;
+
+ // The sensor type must be GUID_SensorType_Custom, the driver must also define and "vendor defined subtype"
+ m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type;
+ InitPropVariantFromCLSID(GUID_SensorType_Custom,
+ &(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"CO2 based sample Custom sensor V2",
+ &(m_pEnumerationProperties->List[SENSOR_MODEL].Value));
+
+ m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId;
+ InitPropVariantFromCLSID(GUID_CustomSensorDevice_UniqueID,
+ &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value));
+
+ m_pEnumerationProperties->List[SENSOR_CATEGORY].Key = DEVPKEY_Sensor_Category;
+ InitPropVariantFromCLSID(GUID_SensorCategory_Other,
+ &(m_pEnumerationProperties->List[SENSOR_CATEGORY].Value));
+
+ m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary;
+ InitPropVariantFromBoolean(FALSE,
+ &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); // This value should be set to TRUE if multiple custom sensors
+ // with the same vendor defined type exist on the system and
+ // this sensor is the primary sensor
+
+ m_pEnumerationProperties->List[SENSOR_VENDOR_DEFINED_TYPE].Key = DEVPKEY_Sensor_VendorDefinedSubType;
+ InitPropVariantFromCLSID(GUID_CustomSensorDevice_VendorDefinedSubTypeID,
+ &(m_pEnumerationProperties->List[SENSOR_VENDOR_DEFINED_TYPE].Value));
+
+ // Supported Data-Fields
+ Size = SENSOR_PROPERTY_LIST_SIZE(CSTM_DATA_COUNT);
+
+ MemoryHandle = NULL;
+ WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes);
+ MemoryAttributes.ParentObject = SensorInstance;
+ Status = WdfMemoryCreate(&MemoryAttributes,
+ PagedPool,
+ SENSORV2_POOL_TAG_CUSTOM_SENSOR,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pSupportedDataFields));
+ if (!NT_SUCCESS(Status) || nullptr == m_pSupportedDataFields)
+ {
+ TraceError("CSTM %!FUNC! WdfMemoryCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size);
+ m_pSupportedDataFields->Count = CSTM_DATA_COUNT;
+
+ m_pSupportedDataFields->List[CSTM_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp;
+ m_pSupportedDataFields->List[CSTM_DATA_CO2_LEVEL_PERCENT] = PKEY_CustomSensorSampleData_CO2Level;
+
+ // Data
+ Size = SENSOR_COLLECTION_LIST_SIZE(CSTM_DATA_COUNT);
+
+ MemoryHandle = NULL;
+ WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes);
+ MemoryAttributes.ParentObject = SensorInstance;
+ Status = WdfMemoryCreate(&MemoryAttributes,
+ PagedPool,
+ SENSORV2_POOL_TAG_CUSTOM_SENSOR,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pData));
+ if (!NT_SUCCESS(Status) || nullptr == m_pData)
+ {
+ TraceError("CSTM %!FUNC! WdfMemoryCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ SENSOR_COLLECTION_LIST_INIT(m_pData, Size);
+ m_pData->Count = CSTM_DATA_COUNT;
+
+ m_pData->List[CSTM_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp;
+ GetSystemTimePreciseAsFileTime(&Time);
+ InitPropVariantFromFileTime(&Time, &(m_pData->List[CSTM_DATA_TIMESTAMP].Value));
+
+ // Initialize the sample, at this point of time the sensor is not started yet,
+ // So, initialize the sample to a default value
+ m_pData->List[CSTM_DATA_CO2_LEVEL_PERCENT].Key = PKEY_CustomSensorSampleData_CO2Level;
+ InitPropVariantFromFloat(CustomSensorDevice_Minimum_CO2Level, &(m_pData->List[CSTM_DATA_CO2_LEVEL_PERCENT].Value));
+
+ // Sensor Properties
+ m_Interval = Cstm_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,
+ SENSORV2_POOL_TAG_CUSTOM_SENSOR,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pProperties));
+ if (!NT_SUCCESS(Status) || nullptr == m_pProperties)
+ {
+ TraceError("CSTM %!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(Cstm_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_Custom,
+ &(m_pProperties->List[SENSOR_PROPERTY_SENSOR_TYPE].Value));
+
+ // Data filed 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,
+ SENSORV2_POOL_TAG_CUSTOM_SENSOR,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pDataFieldProperties));
+ if (!NT_SUCCESS(Status) || nullptr == m_pDataFieldProperties)
+ {
+ TraceError("CSTM %!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;
+ InitPropVariantFromFloat((float)CustomSensorDevice_Resolution,
+ &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value));
+
+ m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum;
+ InitPropVariantFromFloat(CustomSensorDevice_Minimum_CO2Level,
+ &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value));
+
+ m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum;
+ InitPropVariantFromFloat(CustomSensorDevice_Maximum_CO2Level,
+ &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value));
+
+
+ // Reset the FirstSample flag
+ m_FirstSample = TRUE;
+
+Exit:
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+
+
+// This routine is the AddDevice entry point for the custom sensor 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 CustomSensorDevice::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("CSTM %!FUNC! SensorsCxDeviceInitConfig failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Register the PnP callbacks with the framework.
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);
+ Callbacks.EvtDevicePrepareHardware = CustomSensorDevice::OnPrepareHardware;
+ Callbacks.EvtDeviceReleaseHardware = CustomSensorDevice::OnReleaseHardware;
+ Callbacks.EvtDeviceD0Entry = CustomSensorDevice::OnD0Entry;
+ Callbacks.EvtDeviceD0Exit = CustomSensorDevice::OnD0Exit;
+
+ WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &Callbacks);
+
+ // Call the framework to create the device
+ Status = WdfDeviceCreate(&pDeviceInit, &FdoAttributes, &Device);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("CSTM %!FUNC! WdfDeviceCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Register CLX callback function pointers
+ SENSOR_CONTROLLER_CONFIG_INIT(&SensorConfig);
+ SensorConfig.DriverIsPowerPolicyOwner = WdfUseDefault;
+
+ SensorConfig.EvtSensorStart = CustomSensorDevice::OnStart;
+ SensorConfig.EvtSensorStop = CustomSensorDevice::OnStop;
+ SensorConfig.EvtSensorGetSupportedDataFields = CustomSensorDevice::OnGetSupportedDataFields;
+ SensorConfig.EvtSensorGetDataInterval = CustomSensorDevice::OnGetDataInterval;
+ SensorConfig.EvtSensorSetDataInterval = CustomSensorDevice::OnSetDataInterval;
+ SensorConfig.EvtSensorGetDataFieldProperties = CustomSensorDevice::OnGetDataFieldProperties;
+ SensorConfig.EvtSensorGetDataThresholds = CustomSensorDevice::OnGetDataThresholds;
+ SensorConfig.EvtSensorSetDataThresholds = CustomSensorDevice::OnSetDataThresholds;
+ SensorConfig.EvtSensorGetProperties = CustomSensorDevice::OnGetProperties;
+ SensorConfig.EvtSensorDeviceIoControl = CustomSensorDevice::OnIoControl;
+
+ // Set up power capabilities and IO queues
+ Status = SensorsCxDeviceInitialize(Device, &SensorConfig);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("CSTM %!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
+CustomSensorDevice::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.
+
+{
+ PCustomSensorDevice 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, CustomSensorDevice);
+
+ // Register sensor instance with clx
+ Status = SensorsCxSensorCreate(Device, &SensorAttr, &SensorInstance);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("CSTM %!FUNC! SensorsCxSensorCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("CSTM %!FUNC! GetCustomSensorContextFromSensorInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Fill out properties
+ Status = pDevice->Initialize(Device, SensorInstance);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("CSTM %!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("CSTM %!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.
+NTSTATUS
+CustomSensorDevice::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;
+ PCustomSensorDevice 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("CSTM %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! GetCustomSensorContextFromSensorInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Delete lock
+ if (pDevice->m_Lock)
+ {
+ WdfObjectDelete(pDevice->m_Lock);
+ pDevice->m_Lock = NULL;
+ }
+
+ // Cleanup the CO2 simulator
+ pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance);
+ if (nullptr == pSimulator)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("CSTM %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ 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
+CustomSensorDevice::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
+{
+ PCustomSensorDevice pDevice;
+ SENSOROBJECT SensorInstance = nullptr;
+ 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("CSTM %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! GetCustomSensorContextFromSensorInstance 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
+CustomSensorDevice::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
+{
+ PCustomSensorDevice pDevice;
+ SENSOROBJECT SensorInstance = nullptr;
+ 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("CSTM %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance);
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("CSTM %!FUNC! GetCustomSensorContextFromSensorInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Power off sensor
+ pDevice->m_PoweredOn = FALSE;
+
+Exit:
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
diff --git a/sensors/CustomSensors/driver.cpp b/sensors/CustomSensors/driver.cpp
new file mode 100644
index 00000000..7c0512dc
--- /dev/null
+++ b/sensors/CustomSensors/driver.cpp
@@ -0,0 +1,80 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of entry and exit point of sample custom sensor 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 = SENSORV2_POOL_TAG_CUSTOM_SENSOR;
+
+ //
+ // Initialize the driver configuration structure.
+ //
+ WDF_DRIVER_CONFIG_INIT(&DriverConfig, CustomSensorDevice::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("CSTM %!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/CustomSensors/hardwaresimulator.cpp b/sensors/CustomSensors/hardwaresimulator.cpp
new file mode 100644
index 00000000..e5bdb91c
--- /dev/null
+++ b/sensors/CustomSensors/hardwaresimulator.cpp
@@ -0,0 +1,249 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of the custom sensor sample
+// hardware simulator.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "HardwareSimulator.h"
+
+#include "HardwareSimulator.tmh"
+
+// Simulated atmospheric CO2 levels measured in Mole fraction (umol/mol)
+const FLOAT SimulatorData[] = {
+ 396.2f, 396.8f, 397.3f, 397.5f, 398.7f, 399.6f, 397.9f, 396.5f, 395.2f, 395.5f, 395.8f, 397.1f
+};
+
+HardwareSimulator::_HardwareSimulator() :
+ m_Index(0),
+ m_Lock(NULL),
+ m_State(SimulatorState_NotInitialized),
+ m_SimulatorInstance(NULL),
+ m_Timer(NULL)
+{
+}
+
+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("CSTM %!FUNC! WdfObjectCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pSimulator = GetHardwareSimulatorContextFromInstance(*SimulatorInstance);
+ if (nullptr == pSimulator)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("CSTM %!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 Lock
+ Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock);
+ if (!NT_SUCCESS(Status))
+ {
+ m_Lock = NULL;
+
+ TraceError("CSTM %!FUNC! WdfWaitLockCreate 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("CSTM %!FUNC! WdfTimerCreate 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;
+ }
+
+ // 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("CSTM %!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);
+ 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
+FLOAT
+HardwareSimulator::GetSample()
+{
+ FLOAT Sample = 0.0f;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ WdfWaitLockAcquire(m_Lock, NULL);
+ Sample = SimulatorData[m_Index];
+ WdfWaitLockRelease(m_Lock);
+
+ SENSOR_FunctionExit(Status);
+
+ return Sample;
+} \ No newline at end of file
diff --git a/sensors/Pedometer/Device.h b/sensors/Pedometer/Device.h
new file mode 100644
index 00000000..008c3ef6
--- /dev/null
+++ b/sensors/Pedometer/Device.h
@@ -0,0 +1,211 @@
+//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,
+ SENSOR_ISPRIMARY,
+
+ // 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;
+ ULONGLONG m_SampleCount;
+
+ 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/Gallery.xml b/sensors/Pedometer/Gallery.xml
new file mode 100644
index 00000000..ba572bcf
--- /dev/null
+++ b/sensors/Pedometer/Gallery.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="../../buildx/script2/preview.xslt"?>
+<gallery_sample xmlns="http://microsoft.com/wdcml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://microsoft.com/wdcml ../../buildx/schema/xsd/wdcml.xsd">
+ <metadata id="gallery_samples.107a_gallery" type="gallery_sample" msdnID="7cba6311-f0db-4c3d-8f1f-25de8648b353">
+ <title>Pedometer</title>
+ <!-- Add a devlang for each programming language in all versions of the sample. -->
+ <devlang value="cpp" />
+ <!-- Do not change tech value -->
+ <tech value="gallery_samples" />
+ <index />
+ <sample_langs>
+ <!-- Describes the languages to which the sample code itself has been localized. -->
+ <sample_lang xml:lang="en-us" />
+ </sample_langs>
+ </metadata>
+ <content>
+ <desc>
+ <p><abstract>The Pedometer sample shows how to write a UMDF v2 driver to control a virtual Pedometer sensor.</abstract></p>
+ </desc>
+ <outline />
+ <license_info>
+ <default_license />
+ </license_info>
+ <programming_models>
+ <programming_model value="win32" />
+ </programming_models>
+ <application_frameworks>
+ </application_frameworks>
+ <!-- For Driver Samples Only -->
+ <driver_models>
+ <!-- possible values: kmdf, umdf, wdm, ndis, wddm -->
+ <driver_model value="UMDF" />
+ </driver_models>
+ <driver_techs>
+ <driver_tech value="Windows Driver" />
+ </driver_techs>
+ <related_techs>
+ </related_techs>
+ <os_requirements>
+ <min_os>
+ <client name="winblue"/>
+ <server name="wbluesrv"/>
+ </min_os>
+ </os_requirements>
+ <required_sdks>
+ <min_sdk>
+ <tla rid="windows_driver_kit_8" />
+ </min_sdk>
+ </required_sdks>
+ <supported_ides>
+ <supported_ide>
+ <tla rid="tla_visualstu2012" />
+ </supported_ide>
+ </supported_ides>
+ <build_info>
+ <authored_instructions>
+ <section>
+ <!-- Include any special instructions for compiling your sample -->
+ <sectioncontents>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </build_info>
+ <run_info>
+ <authored_instructions>
+ <section>
+ <sectioncontents>
+ <p>To install the sample driver, follow these steps:</p>
+ <proch>
+ <item>Ensure that the driver builds without errors.</item>
+ <item>Copy the DLL and INF files to a separate folder.</item>
+ <item>Enter the command "<inline_code devlang="cmd">devcon.exe update Pedometer.inf ACPI\&lt;HWID&gt;</inline_code>" to install the driver on an existing device node. You can find the devcon.exe program in the tools\devcon folder where you installed the WDK.</item>
+ </proch>
+ </sectioncontents>
+ </section>
+ <section>
+ <title>File manifest</title>
+ <sectioncontents>
+ <p>The following source files are in the src\Sensors\Pedometer folder and are used to build the Pedometer.dll and Pedometer.inf files.</p>
+ <table>
+ <tr>
+ <th>File</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>
+ <p>device.h, device.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's WDF PnP event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>client.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's callback functions from the class extension to pedometer sensors.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>driver.h, driver.cpp</p>
+ </td>
+ <td>
+ <p>WDF driver entry event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>hardwaresimulator.h, hardwaresimulator.cpp</p>
+ </td>
+ <td>
+ <p>Hardware simulator implementation</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>makefile.inc</p>
+ </td>
+ <td>
+ <p>Defines custom build actions. Includes the conversion of the .INX file into a .INF file.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>SensorsTrace.h</p>
+ </td>
+ <td>
+ <p>Implementation the sensor traces files.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>Pedometer.ctl</p>
+ </td>
+ <td>
+ <p>Declaration of driver's tracing GUID</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>Pedometer.inx</p>
+ </td>
+ <td>
+ <p>Describes the installation of the driver. The build process converts this into a .INF.</p>
+ </td>
+ </tr>
+ </table>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </run_info>
+ </content>
+ <!-- List the component compcentral path -->
+ <feature_teams>
+ <feature_team_info comp_central_path="CORE-OS Core\SiGMa-Silicon, Graphics and Media\SiPlat - Silicon Platform\Sensors" dev_owner="osamasal" writer_owner="ericdoku" />
+ </feature_teams>
+ <workflow_control_host />
+</gallery_sample>
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..4aea1609
--- /dev/null
+++ b/sensors/Pedometer/Pedometer.inx
Binary files differ
diff --git a/sensors/Pedometer/Pedometer.sln b/sensors/Pedometer/Pedometer.sln
new file mode 100644
index 00000000..f2d1b250
--- /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", "{2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}"
+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
+ {2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}.Debug|Win32.Build.0 = Debug|Win32
+ {2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}.Release|Win32.ActiveCfg = Release|Win32
+ {2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}.Release|Win32.Build.0 = Release|Win32
+ {2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}.Debug|x64.ActiveCfg = Debug|x64
+ {2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}.Debug|x64.Build.0 = Debug|x64
+ {2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}.Release|x64.ActiveCfg = Release|x64
+ {2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}.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..ee5738d7
--- /dev/null
+++ b/sensors/Pedometer/Pedometer.vcxproj
@@ -0,0 +1,204 @@
+<?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>{2D98FAA6-F523-420D-9F3A-480CD7C3F9CA}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{63E5D8E2-D2E3-4B7E-9F5A-78DA39FA9BED}</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'" />
+ </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..e36ebf64
--- /dev/null
+++ b/sensors/Pedometer/Pedometer.vcxproj.Filters
@@ -0,0 +1,43 @@
+<?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>{47BC76FB-31D6-4043-A1F0-24C8EE1EC77D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{822384CB-A39F-4A21-8529-34A65C4CE181}</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>{C6D84098-A64B-429D-8EE2-D8ED8C5BF2FE}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{A379ED39-5FF0-4DB2-A773-BDEA4FB77D87}</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>
+ <Inf Include="Pedometer.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/sensors/Pedometer/SensorsTrace.h b/sensors/Pedometer/SensorsTrace.h
new file mode 100644
index 00000000..9c6f30e5
--- /dev/null
+++ b/sensors/Pedometer/SensorsTrace.h
@@ -0,0 +1,102 @@
+//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()*/; \
+ }
+
+
+
+// WPP Recorder -------------------------------------------------------------------------------------------
+//
+// The following two macros are required to enable WPP Recorder functionality for clients of the Sensor Class Extension
+//
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_FILTER(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS)
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_ARGS(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/sensors/Pedometer/client.cpp b/sensors/Pedometer/client.cpp
new file mode 100644
index 00000000..debce7d1
--- /dev/null
+++ b/sensors/Pedometer/client.cpp
@@ -0,0 +1,1242 @@
+//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);
+ }
+
+ m_SampleCount = 0;
+
+ 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
+ {
+ pDevice->m_SampleCount++;
+ if (CurrentTimeMs > (pDevice->m_StartTime + (pDevice->m_Interval * (pDevice->m_SampleCount + 1))))
+ {
+ // If we skipped two or more beats, reschedule the timer with a zero due time to catch up on missing samples
+ WaitTimeHundredNanoseconds = 0;
+ }
+ else
+ {
+ WaitTimeHundredNanoseconds = (pDevice->m_StartTime +
+ (pDevice->m_Interval * (pDevice->m_SampleCount + 1))) - CurrentTimeMs;
+ }
+ 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(0x%p) parameter is invalid. Failed %!STATUS!", 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(0x%p) parameter is invalid. Failed %!STATUS!", 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(0x%p) parameter is invalid. Failed %!STATUS!", 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(0x%p) parameter is invalid. Failed %!STATUS!", 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(0x%p) parameter is invalid. Failed %!STATUS!", 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(0x%p) parameter is invalid. Failed %!STATUS!", 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(0x%p), pDevice (0x%p), pBytesWritten (0x%p). Failed %!STATUS!", SensorInstance, pDevice, 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(0x%p) parameter is invalid. pDevice is null", 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(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ goto Exit;
+ }
+
+ if (nullptr == DataRateMs)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("PED %!FUNC! DataRateMs(0x%p) parameter is invalid. Failed %!STATUS!", 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)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("PED %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ goto Exit;
+ }
+
+ if (Pedometer_Default_MinDataInterval_Ms > DataRateMs)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("PED %!FUNC! DataRateMs(%d) parameter is smaller than the minimum data interval. Failed %!STATUS!", DataRateMs, 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(0x%p) parameter is invalid. Failed %!STATUS!", 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..b543dc2c
--- /dev/null
+++ b/sensors/Pedometer/device.cpp
@@ -0,0 +1,743 @@
+//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;
+ GetSystemTimePreciseAsFileTime(&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_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary;
+ InitPropVariantFromBoolean(FALSE,
+ &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); // This value should be set to TRUE if multiple pedometers
+ // exist on the system and this sensor is the primary sensor
+
+ 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_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..6ab45953
--- /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);
+
+ GetSystemTimePreciseAsFileTime(&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;
+}
+
diff --git a/sensors/SimpleDeviceOrientationSensor/Device.h b/sensors/SimpleDeviceOrientationSensor/Device.h
new file mode 100644
index 00000000..b75b5ceb
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/Device.h
@@ -0,0 +1,137 @@
+//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>
+
+#include "HardwareSimulator.h"
+
+#include <windows.devices.sensors.h>
+
+#define SENSORV2_POOL_TAG_SDO 'sodS'
+
+#define Sdo_Mininum_DataInterval (20) // 50Hz
+#define Sdo_Default_DataInterval (200) // 5Hz
+
+//
+// Sensor Common Properties
+//
+typedef enum
+{
+ SENSOR_PROPERTY_STATE = 0,
+ SENSOR_PROPERTY_MIN_INTERVAL,
+ SENSOR_PROPERTY_MAX_DATAFIELDSIZE,
+ SENSOR_PROPERTY_SENSOR_TYPE,
+ SENSOR_PROPERTIES_COUNT
+} SENSOR_COMMON_PROPERTIES_INDEX;
+
+//
+// Sensor Enumeration Properties
+//
+typedef enum
+{
+ SENSOR_TYPE_GUID = 0,
+ SENSOR_MANUFACTURER,
+ SENSOR_MODEL,
+ SENSOR_PERSISTENT_UNIQUEID,
+ SENSOR_ISPRIMARY,
+ SENSOR_ENUMERATION_PROPERTIES_COUNT
+} SENSOR_ENUMERATION_PROPERTIES_INDEX;
+
+//
+// Supported Data Fields
+//
+typedef enum
+{
+ SDO_DATA_TIMESTAMP = 0,
+ SDO_DATA_SIMPLEDEVICEORIENTATION,
+ SDO_DATA_COUNT
+} SDO_DATA_INDEX;
+
+
+//
+// Simple Device Orientation Driver Class
+//
+
+typedef class _SdoDevice
+{
+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;
+
+ // Sensor Specific Properties
+ PSENSOR_PROPERTY_LIST m_pSupportedDataFields;
+ PSENSOR_COLLECTION_LIST m_pEnumerationProperties;
+ PSENSOR_COLLECTION_LIST m_pProperties;
+ PSENSOR_COLLECTION_LIST m_pEmptyThreshold;
+
+ //
+ // SDO Operation ----------------------------------------------------
+ //
+
+ ULONG m_Interval;
+ BOOLEAN m_FirstSample;
+ ULONG m_StartTime;
+ ULONGLONG m_SampleCount;
+
+ PSENSOR_COLLECTION_LIST m_pData; // Sdo data that is going to push to clx
+ ABI::Windows::Devices::Sensors::SimpleOrientation m_LastSample;
+
+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;
+
+private:
+
+ NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj);
+ NTSTATUS GetData();
+
+} SdoDevice, *PSdoDevice;
+
+//
+// Set up accessor function to retrieve device context
+//
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(SdoDevice, GetSdoContextFromSensorInstance);
diff --git a/sensors/SimpleDeviceOrientationSensor/Driver.h b/sensors/SimpleDeviceOrientationSensor/Driver.h
new file mode 100644
index 00000000..9718080c
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/Driver.h
@@ -0,0 +1,19 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved
+//
+//Abstract:
+//
+// This module contains the type definitions for the simple device orientation sensor
+// 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/SimpleDeviceOrientationSensor/Gallery.xml b/sensors/SimpleDeviceOrientationSensor/Gallery.xml
new file mode 100644
index 00000000..8fbb8b8c
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/Gallery.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="../../buildx/script2/preview.xslt"?>
+<gallery_sample xmlns="http://microsoft.com/wdcml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://microsoft.com/wdcml ../../buildx/schema/xsd/wdcml.xsd">
+ <metadata id="gallery_samples.107a_gallery" type="gallery_sample" msdnID="7cba6311-f0db-4c3d-8f1f-25de8648b353">
+ <title>SimpleDeviceOrientationSensor</title>
+ <!-- Add a devlang for each programming language in all versions of the sample. -->
+ <devlang value="cpp" />
+ <!-- Do not change tech value -->
+ <tech value="gallery_samples" />
+ <index />
+ <sample_langs>
+ <!-- Describes the languages to which the sample code itself has been localized. -->
+ <sample_lang xml:lang="en-us" />
+ </sample_langs>
+ </metadata>
+ <content>
+ <desc>
+ <p><abstract>The SimpleDeviceOrientationSensor sample shows how to write a UMDF v2 sensor driver to output Simple Device Orientation values.</abstract></p>
+ </desc>
+ <outline />
+ <license_info>
+ <default_license />
+ </license_info>
+ <programming_models>
+ <programming_model value="win32" />
+ </programming_models>
+ <application_frameworks>
+ </application_frameworks>
+ <!-- For Driver Samples Only -->
+ <driver_models>
+ <!-- possible values: kmdf, umdf, wdm, ndis, wddm -->
+ <driver_model value="UMDF" />
+ </driver_models>
+ <driver_techs>
+ <driver_tech value="Windows Driver" />
+ </driver_techs>
+ <related_techs>
+ </related_techs>
+ <os_requirements>
+ <min_os>
+ <client name="winblue"/>
+ <server name="wbluesrv"/>
+ </min_os>
+ </os_requirements>
+ <required_sdks>
+ <min_sdk>
+ <tla rid="windows_driver_kit_8" />
+ </min_sdk>
+ </required_sdks>
+ <supported_ides>
+ <supported_ide>
+ <tla rid="tla_visualstu2012" />
+ </supported_ide>
+ </supported_ides>
+ <build_info>
+ <authored_instructions>
+ <section>
+ <!-- Include any special instructions for compiling your sample -->
+ <sectioncontents>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </build_info>
+ <run_info>
+ <authored_instructions>
+ <section>
+ <sectioncontents>
+ <p>To install the sample driver, follow these steps:</p>
+ <proch>
+ <item>Ensure that the driver builds without errors.</item>
+ <item>Copy the DLL and INF files to a separate folder.</item>
+ <item>Enter the command "<inline_code devlang="cmd">devcon.exe update SimpleDeviceOrientationSensor.inf ACPI\&lt;HWID&gt;</inline_code>" to install the driver on an existing device node. You can find the devcon.exe program in the tools\devcon folder where you installed the WDK.</item>
+ </proch>
+ </sectioncontents>
+ </section>
+ <section>
+ <title>File manifest</title>
+ <sectioncontents>
+ <p>The following source files are in the src\Sensors\SimpleDeviceOrientationSensor folder and are used to build the SimpleDeviceOrientationSensor.dll and SimpleDeviceOrientationSensor.inf files.</p>
+ <table>
+ <tr>
+ <th>File</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>
+ <p>device.h, device.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's WDF PnP event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>client.cpp</p>
+ </td>
+ <td>
+ <p>Implements the driver's callback functions from the class extension to simple device orientation sensors.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>driver.h, driver.cpp</p>
+ </td>
+ <td>
+ <p>WDF driver entry event callbacks and helper methods</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>hardwaresimulator.h, hardwaresimulator.cpp</p>
+ </td>
+ <td>
+ <p>Hardware simulator implementation</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>makefile.inc</p>
+ </td>
+ <td>
+ <p>Defines custom build actions. Includes the conversion of the .INX file into a .INF file.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>SensorsTrace.h</p>
+ </td>
+ <td>
+ <p>Implementation the sensor traces files.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>SimpleDeviceOrientationSensor.ctl</p>
+ </td>
+ <td>
+ <p>Declaration of driver's tracing GUID</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <p>SimpleDeviceOrientationSensor.inx</p>
+ </td>
+ <td>
+ <p>Describes the installation of the driver. The build process converts this into a .INF.</p>
+ </td>
+ </tr>
+ </table>
+ </sectioncontents>
+ </section>
+ </authored_instructions>
+ </run_info>
+ </content>
+ <!-- List the component compcentral path -->
+ <feature_teams>
+ <feature_team_info comp_central_path="CORE-OS Core\SiGMa-Silicon, Graphics and Media\SiPlat - Silicon Platform\Sensors" dev_owner="osamasal" writer_owner="ericdoku" />
+ </feature_teams>
+ <workflow_control_host />
+</gallery_sample>
diff --git a/sensors/SimpleDeviceOrientationSensor/HardwareSimulator.h b/sensors/SimpleDeviceOrientationSensor/HardwareSimulator.h
new file mode 100644
index 00000000..8f96b902
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/HardwareSimulator.h
@@ -0,0 +1,58 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved
+//
+//Abstract:
+//
+// This module contains the type definitions for the simple device orientation sensor sample
+// hardware simulator.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#pragma once
+
+#include <windows.h>
+#include <wdf.h>
+
+#include <SensorsTrace.h>
+#include <SensorsCx.h>
+#include <windows.devices.sensors.h>
+
+#define HardwareSimulator_HardwareInterval (1000)
+
+typedef enum _SIMULATOR_STATE
+{
+ SimulatorState_NotInitialized = 0,
+ SimulatorState_Initialized,
+ SimulatorState_Started
+} SIMULATOR_STATE;
+
+typedef class _HardwareSimulator
+{
+private:
+ WDFTIMER m_Timer;
+ ULONG m_Index;
+ WDFWAITLOCK m_Lock;
+ SIMULATOR_STATE m_State;
+ WDFOBJECT m_SimulatorInstance;
+
+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();
+ ABI::Windows::Devices::Sensors::SimpleOrientation GetOrientation();
+
+private:
+ NTSTATUS InitializeInternal(_In_ WDFOBJECT SimulatorInstance);
+
+} HardwareSimulator, *PHardwareSimulator;
+
+// Set up accessor function to retrieve device context
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(HardwareSimulator, GetHardwareSimulatorContextFromInstance);
diff --git a/sensors/SimpleDeviceOrientationSensor/SensorsTrace.h b/sensors/SimpleDeviceOrientationSensor/SensorsTrace.h
new file mode 100644
index 00000000..6098864d
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/SensorsTrace.h
@@ -0,0 +1,100 @@
+//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 - 3C773167-F26D-4F72-A1DE-95F1FD795840
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID( \
+ SimpleDeviceOrientationSensorTraceGuid, (3C773167,F26D,4F72,A1DE,95F1FD795840), \
+ 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()*/; \
+ }
+
+
+
+// WPP Recorder -------------------------------------------------------------------------------------------
+//
+// The following two macros are required to enable WPP Recorder functionality for clients of the Sensor Class Extension
+//
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_FILTER(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS)
+#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_ARGS(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.def b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.def
new file mode 100644
index 00000000..aa44c9aa
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.def
@@ -0,0 +1,6 @@
+; SimpleDeviceOrientationSensor.def : Declares the module parameters.
+
+LIBRARY SimpleDeviceOrientationSensor
+
+EXPORTS
+
diff --git a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.inx b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.inx
new file mode 100644
index 00000000..7de2e6f0
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.inx
Binary files differ
diff --git a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.sln b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.sln
new file mode 100644
index 00000000..3dc42976
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.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}") = "SimpleDeviceOrientationSensor", "SimpleDeviceOrientationSensor.vcxproj", "{EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}"
+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
+ {EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}.Debug|Win32.ActiveCfg = Debug|Win32
+ {EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}.Debug|Win32.Build.0 = Debug|Win32
+ {EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}.Release|Win32.ActiveCfg = Release|Win32
+ {EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}.Release|Win32.Build.0 = Release|Win32
+ {EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}.Debug|x64.ActiveCfg = Debug|x64
+ {EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}.Debug|x64.Build.0 = Debug|x64
+ {EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}.Release|x64.ActiveCfg = Release|x64
+ {EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj
new file mode 100644
index 00000000..ee3d87a3
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj
@@ -0,0 +1,204 @@
+<?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>{EEA3DEEA-AF9A-45E3-B6AE-070677AC1032}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{1854CF02-14B5-40BD-A09F-4C744EFB31A8}</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>SimpleDeviceOrientationSensor</WppModuleName>
+ <WppScanConfigurationData>sensorstrace.h</WppScanConfigurationData>
+ </ClCompile>
+ <Inf Include="SimpleDeviceOrientationSensor.inx">
+ <Architecture>$(InfArch)</Architecture>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <CopyOutput>.\$(IntDir)\SimpleDeviceOrientationSensor.inf</CopyOutput>
+ </Inf>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>SimpleDeviceOrientationSensor</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>SimpleDeviceOrientationSensor</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>SimpleDeviceOrientationSensor</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>SimpleDeviceOrientationSensor</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);$(SDK_INC_PATH)\ABI;$(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);$(SDK_INC_PATH)\ABI;$(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);$(SDK_INC_PATH)\ABI;$(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>SimpleDeviceOrientationSensor.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);$(SDK_INC_PATH)\ABI;$(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);$(SDK_INC_PATH)\ABI;$(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);$(SDK_INC_PATH)\ABI;$(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>SimpleDeviceOrientationSensor.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);$(SDK_INC_PATH)\ABI;$(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);$(SDK_INC_PATH)\ABI;$(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);$(SDK_INC_PATH)\ABI;$(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>SimpleDeviceOrientationSensor.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);$(SDK_INC_PATH)\ABI;$(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);$(SDK_INC_PATH)\ABI;$(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);$(SDK_INC_PATH)\ABI;$(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>SimpleDeviceOrientationSensor.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </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/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj.Filters b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj.Filters
new file mode 100644
index 00000000..45db253b
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.vcxproj.Filters
@@ -0,0 +1,43 @@
+<?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>{00557774-6CAE-4A42-9465-A85A4F048686}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{68764800-116B-4343-8B60-49693688236E}</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>{25662F7E-DB14-43DD-84A3-E8B7327B6ECE}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{372D6D06-B60D-4D04-901A-FC8530D3AC42}</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="SimpleDeviceOrientationSensor.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="SimpleDeviceOrientationSensor.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/sensors/SimpleDeviceOrientationSensor/client.cpp b/sensors/SimpleDeviceOrientationSensor/client.cpp
new file mode 100644
index 00000000..c167b6c2
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/client.cpp
@@ -0,0 +1,595 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of driver callback function
+// from clx to simple device orientation sensor.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "Device.h"
+#include <timeapi.h>
+
+#include "Client.tmh"
+
+// This routine is called by worker thread to read a single sample, compare threshold
+// and push it back to CLX.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::GetData()
+{
+ PHardwareSimulator pSimulator = nullptr;
+ FILETIME TimeStamp = {};
+ NTSTATUS Status = STATUS_SUCCESS;
+ ABI::Windows::Devices::Sensors::SimpleOrientation Sample;
+
+ SENSOR_FunctionEnter();
+
+ if (FALSE != m_FirstSample)
+ {
+ Status = GetPerformanceTime(&m_StartTime);
+ if (!NT_SUCCESS(Status))
+ {
+ m_StartTime = 0;
+ TraceError("SDOS %!FUNC! GetPerformanceTime %!STATUS!", Status);
+ }
+
+ m_SampleCount = 0;
+ }
+
+ pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance);
+ if (nullptr == pSimulator)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("SDOS %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ Sample = pSimulator->GetOrientation();
+
+ if (FALSE != m_FirstSample || m_LastSample != Sample)
+ {
+ m_LastSample = Sample;
+
+ // push to clx
+ InitPropVariantFromUInt32(m_LastSample, &(m_pData->List[SDO_DATA_SIMPLEDEVICEORIENTATION].Value));
+
+ GetSystemTimePreciseAsFileTime(&TimeStamp);
+ InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[SDO_DATA_TIMESTAMP].Value));
+
+ SensorsCxSensorDataReady(m_SensorInstance, m_pData);
+
+ m_FirstSample = FALSE;
+ }
+ else
+ {
+ Status = STATUS_DATA_NOT_ACCEPTED;
+ TraceInformation("SDOS %!FUNC! SDO Data did NOT meet the threshold");
+ }
+
+Exit:
+ SENSOR_FunctionExit(Status);
+
+ 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 SdoDevice::OnTimerExpire(
+ _In_ WDFTIMER Timer // WDF timer object
+ )
+{
+ PSdoDevice pDevice = nullptr;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ pDevice = GetSdoContextFromSensorInstance(WdfTimerGetParentObject(Timer));
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("SDOS %!FUNC! GetSdoContextFromSensorInstance failed %!STATUS!", Status);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ // Get data and push to clx
+ WdfWaitLockAcquire(pDevice->m_Lock, NULL);
+ Status = pDevice->GetData();
+ if (!NT_SUCCESS(Status) && Status != STATUS_DATA_NOT_ACCEPTED)
+ {
+ TraceError("SDOS %!FUNC! GetData Failed %!STATUS!", Status);
+ }
+ WdfWaitLockRelease(pDevice->m_Lock);
+
+ // Schedule next wake up time
+ if (Sdo_Mininum_DataInterval <= pDevice->m_Interval &&
+ FALSE != pDevice->m_PoweredOn &&
+ FALSE != pDevice->m_Started)
+ {
+ LONGLONG WaitTime = 0; // in unit of 100ns
+
+ if (0 == pDevice->m_StartTime)
+ {
+ // in case we fail to get sensor start time, use static wait time
+ WaitTime = 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("SDOS %!FUNC! GetPerformanceTime %!STATUS!", Status);
+ WaitTime = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval);
+ }
+ else
+ {
+ pDevice->m_SampleCount++;
+ if (CurrentTimeMs > (pDevice->m_StartTime + (pDevice->m_Interval * (pDevice->m_SampleCount + 1))))
+ {
+ // If we skipped two or more beats, reschedule the timer with a zero due time to catch up on missing samples
+ WaitTime = 0;
+ }
+ else
+ {
+ WaitTime = (pDevice->m_StartTime +
+ (pDevice->m_Interval * (pDevice->m_SampleCount + 1))) - CurrentTimeMs;
+ }
+ WaitTime = WDF_REL_TIMEOUT_IN_MS(WaitTime);
+ }
+ }
+ WdfTimerStart(pDevice->m_Timer, WaitTime);
+ }
+ }
+
+ SENSOR_FunctionExit(Status);
+}
+
+// Called by Sensor CLX to begin continously sampling the sensor.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::OnStart(
+ _In_ SENSOROBJECT SensorInstance // sensor device object
+ )
+{
+ PHardwareSimulator pSimulator = nullptr;
+ PSdoDevice pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ }
+ else if (0 == pDevice->m_Interval)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! Interval parameter is invalid (equal to 0). Failed %!STATUS!", Status);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ // Get the simulator context
+ pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance);
+ if (nullptr == pSimulator)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("SDOS %!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, 0);
+ }
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Called by Sensor CLX to stop continously sampling the sensor.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::OnStop(
+ _In_ SENSOROBJECT SensorInstance // sensor device object
+ )
+{
+ PHardwareSimulator pSimulator = nullptr;
+ PSdoDevice pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ // 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("SDOS %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pSimulator->Stop();
+ }
+
+Exit:
+ SENSOR_FunctionExit(Status);
+
+ return Status;
+}
+
+// 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.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::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
+ )
+{
+ PSdoDevice pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG size = 0;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! pSize: Invalid parameter! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ *pSize = 0;
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! pDevice: Invalid parameter! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ if (nullptr == pFields)
+ {
+ // Just return size
+ size = pDevice->m_pSupportedDataFields->AllocatedSizeInBytes;
+ }
+ else
+ {
+ if (pFields->AllocatedSizeInBytes < pDevice->m_pSupportedDataFields->AllocatedSizeInBytes)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("SDOS %!FUNC! Buffer is too small. Failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Fill out data
+ Status = PropertiesListCopy(pFields, pDevice->m_pSupportedDataFields);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("SDOS %!FUNC! PropertiesListCopy failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ size = pDevice->m_pSupportedDataFields->AllocatedSizeInBytes;
+ }
+
+ *pSize = size;
+
+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.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::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
+ )
+{
+ PSdoDevice pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+ ULONG size = 0;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! pSize: Invalid parameter! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ *pSize = 0;
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! pDevice: Invalid parameter! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ if (nullptr == pProperties)
+ {
+ // Just return size
+ size = CollectionsListGetMarshalledSize(pDevice->m_pProperties);
+ }
+ else
+ {
+ if (pProperties->AllocatedSizeInBytes <
+ CollectionsListGetMarshalledSize(pDevice->m_pProperties))
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("SDOS %!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("SDOS %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ size = CollectionsListGetMarshalledSize(pDevice->m_pProperties);
+ }
+
+ *pSize = size;
+
+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.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::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
+)
+{
+ PSdoDevice pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_NOT_SUPPORTED;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice || nullptr == pSize || nullptr == DataField)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! Invalid parameters! %!STATUS!", Status);
+ }
+
+ *pSize = 0;
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Called by Sensor CLX to get sampling rate of the sensor.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::OnGetDataInterval(
+ _In_ SENSOROBJECT SensorInstance, // sensor device object
+ _Out_ PULONG DataRateMs // sampling rate in milliseconds
+ )
+{
+ PSdoDevice pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ goto Exit;
+ }
+
+ if (nullptr == DataRateMs)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! DataRateMs(0x%p) parameter is invalid. Failed %!STATUS!", 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.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::OnSetDataInterval(
+ _In_ SENSOROBJECT SensorInstance, // sensor device object
+ _In_ ULONG DataRateMs // sampling rate in milliseconds
+ )
+{
+ PSdoDevice pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status);
+ goto Exit;
+ }
+
+ if (Sdo_Mininum_DataInterval > DataRateMs)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! DataRateMs(%d) parameter is smaller than the minimum data interval. Failed %!STATUS!", DataRateMs, Status);
+ goto Exit;
+ }
+
+ pDevice->m_Interval = DataRateMs;
+
+ // Restart the timer at minimum report interval to return a sample as soon as possible.
+ 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(Sdo_Mininum_DataInterval));
+ }
+
+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.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::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
+ )
+{
+ PSdoDevice pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (nullptr == pDevice || nullptr == pSize)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! Invalid parameters! %!STATUS!", Status);
+ goto Exit;
+ }
+
+ if (nullptr == pThresholds)
+ {
+ // Just return size
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pEmptyThreshold);
+ }
+ else
+ {
+ if (pThresholds->AllocatedSizeInBytes <
+ CollectionsListGetMarshalledSize(pDevice->m_pEmptyThreshold))
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("SDOS %!FUNC! Buffer is too small. Failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Fill out all data
+ Status = CollectionsListCopyAndMarshall(pThresholds, pDevice->m_pEmptyThreshold);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("SDOS %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ *pSize = CollectionsListGetMarshalledSize(pDevice->m_pEmptyThreshold);
+ }
+
+Exit:
+ if (!NT_SUCCESS(Status))
+ {
+ *pSize = 0;
+ }
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Called by Sensor CLX to set data thresholds.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::OnSetDataThresholds(
+ _In_ SENSOROBJECT /*SensorInstance*/, // sensor device object
+ _In_ PSENSOR_COLLECTION_LIST /*pThresholds*/ // pointer to a list of sensor thresholds
+ )
+{
+ NTSTATUS Status = STATUS_NOT_SUPPORTED;
+
+ SENSOR_FunctionEnter();
+
+ // Unsupported at this point in time.
+
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// Called by Sensor CLX to handle IOCTLs that clx does not support
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::OnIoControl(
+ _In_ SENSOROBJECT /*SensorInstance*/, // Sensor 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;
+}
diff --git a/sensors/SimpleDeviceOrientationSensor/device.cpp b/sensors/SimpleDeviceOrientationSensor/device.cpp
new file mode 100644
index 00000000..e9624301
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/device.cpp
@@ -0,0 +1,572 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of WDF callback functions
+// for sample simple device orientation sensor driver.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "Device.h"
+
+#include "Device.tmh"
+
+// Simple Device Orientation Sample Sensors Unique ID
+// DO NOT REUSE THIS GUID, CREATE A NEW GUID
+// {57AB5189-3D73-4E4D-AFEB-019A5CFB8F05}
+DEFINE_GUID(GUID_SdoDevice_UniqueID,
+ 0x57ab5189, 0x3d73, 0x4e4d, 0xaf, 0xeb, 0x1, 0x9a, 0x5c, 0xfb, 0x8f, 0x5);
+
+// This routine initializes the sensor to its default properties
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::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;
+
+ SENSOR_FunctionEnter();
+
+ // Store device and instance
+ m_FxDevice = Device;
+ m_SensorInstance = SensorInstance;
+ m_Started = FALSE;
+
+ m_PoweredOn = FALSE;
+ m_FirstSample = TRUE;
+
+ // Initialize the simple device orientation simulator
+ HardwareSimulator::Initialize(Device, &m_SimulatorInstance);
+
+ //
+ // Create Locks
+ //
+ {
+ Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("SDO %!FUNC! WdfWaitLockCreate m_Lock failed %!STATUS!", Status);
+ goto Exit;
+ }
+ }
+
+ //
+ // Create timer object for polling sensor samples
+ //
+ {
+ WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes);
+ TimerAttributes.ParentObject = SensorInstance;
+ TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive;
+
+ WDF_TIMER_CONFIG_INIT(&TimerConfig, OnTimerExpire);
+ Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("SDO %!FUNC! WdfTimerCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+ }
+
+ //
+ // 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,
+ SENSORV2_POOL_TAG_SDO,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pEnumerationProperties));
+ if (!NT_SUCCESS(Status) || nullptr == m_pEnumerationProperties)
+ {
+ TraceError("SDO %!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_SimpleDeviceOrientation,
+ &(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"Simple Device Orientation",
+ &(m_pEnumerationProperties->List[SENSOR_MODEL].Value));
+
+ m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId;
+ InitPropVariantFromCLSID(GUID_SdoDevice_UniqueID,
+ &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value));
+
+ m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary;
+ InitPropVariantFromBoolean(FALSE,
+ &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); // This value should be set to TRUE if multiple simple device orientation sensors
+ // exist on the system and this sensor is the primary sensor
+ }
+
+ //
+ // Supported Data-Fields
+ //
+ {
+ Size = SENSOR_PROPERTY_LIST_SIZE(SDO_DATA_COUNT);
+
+ MemoryHandle = NULL;
+ WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes);
+ MemoryAttributes.ParentObject = SensorInstance;
+ Status = WdfMemoryCreate(&MemoryAttributes,
+ PagedPool,
+ SENSORV2_POOL_TAG_SDO,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pSupportedDataFields));
+ if (!NT_SUCCESS(Status) || nullptr == m_pSupportedDataFields)
+ {
+ TraceError("SDO %!FUNC! WdfMemoryCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size);
+ m_pSupportedDataFields->Count = SDO_DATA_COUNT;
+
+ m_pSupportedDataFields->List[SDO_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp;
+ m_pSupportedDataFields->List[SDO_DATA_SIMPLEDEVICEORIENTATION] = PKEY_SensorData_SimpleDeviceOrientation;
+ }
+
+ //
+ // Data
+ //
+ {
+ Size = SENSOR_COLLECTION_LIST_SIZE(SDO_DATA_COUNT);
+
+ MemoryHandle = NULL;
+ WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes);
+ MemoryAttributes.ParentObject = SensorInstance;
+ Status = WdfMemoryCreate(&MemoryAttributes,
+ PagedPool,
+ SENSORV2_POOL_TAG_SDO,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pData));
+ if (!NT_SUCCESS(Status) || nullptr == m_pData)
+ {
+ TraceError("SDO %!FUNC! WdfMemoryCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ SENSOR_COLLECTION_LIST_INIT(m_pData, Size);
+ m_pData->Count = SDO_DATA_COUNT;
+
+ m_pData->List[SDO_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp;
+ GetSystemTimePreciseAsFileTime(&Time);
+ InitPropVariantFromFileTime(&Time, &(m_pData->List[SDO_DATA_TIMESTAMP].Value));
+
+ m_pData->List[SDO_DATA_SIMPLEDEVICEORIENTATION].Key = PKEY_SensorData_SimpleDeviceOrientation;
+ InitPropVariantFromUInt32(ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_Faceup, &(m_pData->List[SDO_DATA_SIMPLEDEVICEORIENTATION].Value));
+ }
+
+ //
+ // Sensor Properties
+ //
+ {
+ m_Interval = Sdo_Default_DataInterval;
+
+ Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_PROPERTIES_COUNT);
+
+ MemoryHandle = NULL;
+ WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes);
+ MemoryAttributes.ParentObject = SensorInstance;
+ Status = WdfMemoryCreate(&MemoryAttributes,
+ PagedPool,
+ SENSORV2_POOL_TAG_SDO,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pProperties));
+ if (!NT_SUCCESS(Status) || nullptr == m_pProperties)
+ {
+ TraceError("SDO %!FUNC! WdfMemoryCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size);
+ m_pProperties->Count = SENSOR_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(Sdo_Mininum_DataInterval,
+ &(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_SimpleDeviceOrientation,
+ &(m_pProperties->List[SENSOR_PROPERTY_SENSOR_TYPE].Value));
+ }
+
+ //
+ // Empty Threshold List
+ //
+ {
+ Size = SENSOR_COLLECTION_LIST_SIZE(0);
+
+ MemoryHandle = NULL;
+ WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes);
+ MemoryAttributes.ParentObject = SensorInstance;
+ Status = WdfMemoryCreate(&MemoryAttributes,
+ PagedPool,
+ SENSORV2_POOL_TAG_SDO,
+ Size,
+ &MemoryHandle,
+ reinterpret_cast<PVOID*>(&m_pEmptyThreshold));
+ if (!NT_SUCCESS(Status) || nullptr == m_pEmptyThreshold)
+ {
+ TraceError("SDO %!FUNC! WdfMemoryCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ SENSOR_COLLECTION_LIST_INIT(m_pEmptyThreshold, Size);
+ m_pEmptyThreshold->Count = 0;
+ }
+
+ // Reset the FirstSample flag
+ m_FirstSample = TRUE;
+
+Exit:
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
+
+// This routine is the AddDevice entry point for the SDO 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.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::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("SDOS %!FUNC! SensorsCxDeviceInitConfig failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Register the PnP callbacks with the framework.
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks);
+ Callbacks.EvtDevicePrepareHardware = SdoDevice::OnPrepareHardware;
+ Callbacks.EvtDeviceReleaseHardware = SdoDevice::OnReleaseHardware;
+ Callbacks.EvtDeviceD0Entry = SdoDevice::OnD0Entry;
+ Callbacks.EvtDeviceD0Exit = SdoDevice::OnD0Exit;
+
+ WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &Callbacks);
+
+ // Call the framework to create the device
+ Status = WdfDeviceCreate(&pDeviceInit, &FdoAttributes, &Device);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("SDOS %!FUNC! WdfDeviceCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Register CLX callback function pointers
+ SENSOR_CONTROLLER_CONFIG_INIT(&SensorConfig);
+ SensorConfig.DriverIsPowerPolicyOwner = WdfUseDefault;
+
+ SensorConfig.EvtSensorStart = SdoDevice::OnStart;
+ SensorConfig.EvtSensorStop = SdoDevice::OnStop;
+ SensorConfig.EvtSensorGetSupportedDataFields = SdoDevice::OnGetSupportedDataFields;
+ SensorConfig.EvtSensorGetDataInterval = SdoDevice::OnGetDataInterval;
+ SensorConfig.EvtSensorSetDataInterval = SdoDevice::OnSetDataInterval;
+ SensorConfig.EvtSensorGetDataFieldProperties = SdoDevice::OnGetDataFieldProperties;
+ SensorConfig.EvtSensorGetDataThresholds = SdoDevice::OnGetDataThresholds;
+ SensorConfig.EvtSensorSetDataThresholds = SdoDevice::OnSetDataThresholds;
+ SensorConfig.EvtSensorGetProperties = SdoDevice::OnGetProperties;
+ SensorConfig.EvtSensorDeviceIoControl = SdoDevice::OnIoControl;
+
+ // Set up power capabilities and IO queues
+ Status = SensorsCxDeviceInitialize(Device, &SensorConfig);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("SDOS %!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).
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::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.
+
+{
+ PSdoDevice 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, SdoDevice);
+
+ // Register sensor instance with clx
+ Status = SensorsCxSensorCreate(Device, &SensorAttr, &SensorInstance);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("SDOS %!FUNC! SensorsCxSensorCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("SDOS %!FUNC! GetSdoContextFromSensorInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ Status = pDevice->Initialize(Device, SensorInstance);
+ if (!NT_SUCCESS(Status))
+ {
+ TraceError("SDOS %!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("SDOS %!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.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::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;
+ PSdoDevice 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("SDOS %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! GetSdoContextFromSensorInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Delete lock
+ if (pDevice->m_Lock)
+ {
+ WdfObjectDelete(pDevice->m_Lock);
+ pDevice->m_Lock = NULL;
+ }
+
+ // Cleanup the simple device orientation simulator
+ pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance);
+ if (nullptr == pSimulator)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("SDOS %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ 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.
+// Returns an NTSTATUS code
+NTSTATUS SdoDevice::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
+{
+ PSdoDevice pDevice;
+ SENSOROBJECT SensorInstance = nullptr;
+ 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("SDOS %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! GetSdoContextFromSensorInstance 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.
+// Returns an NTSTATUS code
+NTSTATUS
+SdoDevice::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
+{
+ PSdoDevice pDevice;
+ SENSOROBJECT SensorInstance = nullptr;
+ 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("SDOS %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pDevice = GetSdoContextFromSensorInstance(SensorInstance);
+ if (nullptr == pDevice)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ TraceError("SDOS %!FUNC! GetSdoContextFromSensorInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ // Power off sensor
+ pDevice->m_PoweredOn = FALSE;
+
+Exit:
+ SENSOR_FunctionExit(Status);
+ return Status;
+}
diff --git a/sensors/SimpleDeviceOrientationSensor/driver.cpp b/sensors/SimpleDeviceOrientationSensor/driver.cpp
new file mode 100644
index 00000000..f3ed0045
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/driver.cpp
@@ -0,0 +1,75 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of entry and exit point of sample simple device orientation sensor 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.
+// Returns an NTSTATUS code
+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 = SENSORV2_POOL_TAG_SDO;
+
+ //
+ // Initialize the driver configuration structure.
+ //
+ WDF_DRIVER_CONFIG_INIT(&DriverConfig, SdoDevice::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("SDOS %!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(Driver);
+
+ return;
+} \ No newline at end of file
diff --git a/sensors/SimpleDeviceOrientationSensor/hardwaresimulator.cpp b/sensors/SimpleDeviceOrientationSensor/hardwaresimulator.cpp
new file mode 100644
index 00000000..759338cd
--- /dev/null
+++ b/sensors/SimpleDeviceOrientationSensor/hardwaresimulator.cpp
@@ -0,0 +1,248 @@
+//Copyright (C) Microsoft Corporation, All Rights Reserved.
+//
+//Abstract:
+//
+// This module contains the implementation of the simple device orientation sensor sample
+// hardware simulator.
+//
+//Environment:
+//
+// Windows User-Mode Driver Framework (UMDF)
+
+#include "HardwareSimulator.h"
+
+#include "HardwareSimulator.tmh"
+
+// Simulated device orientations
+const ABI::Windows::Devices::Sensors::SimpleOrientation OrientationData[] = {
+ ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_Facedown,
+ ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_NotRotated,
+ ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_Faceup,
+ ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_Rotated90DegreesCounterclockwise,
+ ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_Facedown,
+ ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_Rotated180DegreesCounterclockwise,
+ ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_Faceup,
+ ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_Rotated270DegreesCounterclockwise
+};
+
+HardwareSimulator::_HardwareSimulator() :
+ m_Index(0),
+ m_Lock(NULL),
+ m_State(SimulatorState_NotInitialized),
+ m_SimulatorInstance(NULL),
+ m_Timer(NULL)
+{
+}
+
+HardwareSimulator::~_HardwareSimulator()
+{
+}
+
+// This static routine performs simulator initialization. The routine creates a
+// timer object that periodically updates the m_Index location
+// Returns an NTSTATUS code
+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("SDOS %!FUNC! WdfObjectCreate failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pSimulator = GetHardwareSimulatorContextFromInstance(*SimulatorInstance);
+ if (nullptr == pSimulator)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ TraceError("SDOS %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status);
+ goto Exit;
+ }
+
+ pSimulator->InitializeInternal(*SimulatorInstance);
+
+Exit:
+
+ SENSOR_FunctionExit(Status);
+
+ return Status;
+}
+
+// Internal routine to perform simulator initialization
+// Returns an NTSTATUS code
+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 Lock
+ Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock);
+ if (!NT_SUCCESS(Status))
+ {
+ m_Lock = NULL;
+
+ TraceError("SDOS %!FUNC! WdfWaitLockCreate 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("SDOS %!FUNC! WdfTimerCreate 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
+// Returns an NTSTATUS code
+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;
+ }
+
+ // Set the simulator state to "not initialized"
+ m_State = SimulatorState_NotInitialized;
+
+ return status;
+}
+
+// This routine starts the simulator
+// Returns an NTSTATUS code
+NTSTATUS HardwareSimulator::Start()
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ if (SimulatorState_Initialized == m_State)
+ {
+ WdfTimerStart(m_Timer, WDF_REL_TIMEOUT_IN_MS(HardwareSimulator_HardwareInterval));
+ m_State = SimulatorState_Started;
+ }
+
+ SENSOR_FunctionExit(status);
+
+ return status;
+}
+
+// This routine stops the simulator
+// Returns an NTSTATUS code
+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("SDOS %!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 %= ARRAYSIZE(OrientationData);
+ WdfWaitLockRelease(pSimulator->m_Lock);
+
+ WdfTimerStart(pSimulator->m_Timer, WDF_REL_TIMEOUT_IN_MS(HardwareSimulator_HardwareInterval));
+ }
+
+ SENSOR_FunctionExit(Status);
+}
+
+// This routine returns the current sample from the driver at the current m_Index location.
+// Returns one of the ABI::Windows::Devices::Sensors::SimpleOrientation enum values.
+ABI::Windows::Devices::Sensors::SimpleOrientation HardwareSimulator::GetOrientation()
+{
+ ABI::Windows::Devices::Sensors::SimpleOrientation Sample = ABI::Windows::Devices::Sensors::SimpleOrientation::SimpleOrientation_Faceup;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SENSOR_FunctionEnter();
+
+ WdfWaitLockAcquire(m_Lock, NULL);
+ Sample = OrientationData[m_Index];
+ WdfWaitLockRelease(m_Lock);
+
+ SENSOR_FunctionExit(Status);
+
+ return Sample;
+} \ No newline at end of file