diff options
| author | Wei Mao <[email protected]> | 2017-03-17 19:47:04 -0700 |
|---|---|---|
| committer | Wei Mao <[email protected]> | 2017-03-17 19:47:04 -0700 |
| commit | 1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch) | |
| tree | bf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /Sensors/Activity | |
| parent | da21c8784c83c5fd614f3030323e229d6a5fb10e (diff) | |
Fix cases
Diffstat (limited to 'Sensors/Activity')
| -rw-r--r-- | Sensors/Activity/Activity.def | 6 | ||||
| -rw-r--r-- | Sensors/Activity/Activity.inx | bin | 0 -> 5180 bytes | |||
| -rw-r--r-- | Sensors/Activity/Activity.sln | 28 | ||||
| -rw-r--r-- | Sensors/Activity/Activity.vcxproj | 204 | ||||
| -rw-r--r-- | Sensors/Activity/Activity.vcxproj.Filters | 43 | ||||
| -rw-r--r-- | Sensors/Activity/Device.h | 200 | ||||
| -rw-r--r-- | Sensors/Activity/Driver.h | 16 | ||||
| -rw-r--r-- | Sensors/Activity/HardwareSimulator.h | 49 | ||||
| -rw-r--r-- | Sensors/Activity/SensorsTrace.h | 102 | ||||
| -rw-r--r-- | Sensors/Activity/client.cpp | 1021 | ||||
| -rw-r--r-- | Sensors/Activity/device.cpp | 835 | ||||
| -rw-r--r-- | Sensors/Activity/driver.cpp | 55 | ||||
| -rw-r--r-- | Sensors/Activity/hardwaresimulator.cpp | 276 |
13 files changed, 2835 insertions, 0 deletions
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/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 |
