diff options
| author | Wei Mao <[email protected]> | 2017-03-17 20:14:57 -0700 |
|---|---|---|
| committer | Wei Mao <[email protected]> | 2017-03-17 20:14:57 -0700 |
| commit | 406cf3e4c6cd251bf69cdd8d7b6433f3477d3980 (patch) | |
| tree | 15ca9253d190ab5e16cde06526dc17b486f32a22 /sensors | |
| parent | 1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (diff) | |
Use lower case
Diffstat (limited to 'sensors')
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 Binary files differnew file mode 100644 index 00000000..8d7649da --- /dev/null +++ b/sensors/ADXL345Acc/ADXL345Acc.inx 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 Binary files differnew file mode 100644 index 00000000..7f2558c1 --- /dev/null +++ b/sensors/Activity/Activity.inx 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\<HWID></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 Binary files differnew file mode 100644 index 00000000..b26b6848 --- /dev/null +++ b/sensors/CustomSensors/CustomSensors.inx 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\<HWID></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\<HWID></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 Binary files differnew file mode 100644 index 00000000..4aea1609 --- /dev/null +++ b/sensors/Pedometer/Pedometer.inx 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\<HWID></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 Binary files differnew file mode 100644 index 00000000..7de2e6f0 --- /dev/null +++ b/sensors/SimpleDeviceOrientationSensor/SimpleDeviceOrientationSensor.inx 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 |
