diff options
| author | Michelle Bergeron <[email protected]> | 2017-08-17 09:56:51 -0700 |
|---|---|---|
| committer | Michelle Bergeron <[email protected]> | 2017-08-17 09:56:51 -0700 |
| commit | 75d68b365bfc5e1d17f9c69f37ff789aa30e2d79 (patch) | |
| tree | 1da8596a3a0a72438eef907befd523488889a715 | |
| parent | 836052c0d882f2a694343060e0ed89f73440b4c3 (diff) | |
Add sensors combo driver sample
32 files changed, 7308 insertions, 0 deletions
diff --git a/sensors/SensorsComboDriver/Cat/product.pbxproj b/sensors/SensorsComboDriver/Cat/product.pbxproj new file mode 100644 index 00000000..fb8943d8 --- /dev/null +++ b/sensors/SensorsComboDriver/Cat/product.pbxproj @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="ProductBuild" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup Label="PropertySheets"> + <PlatformToolset>v110</PlatformToolset> + <ConfigurationType>Utility</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" Label="FirstImport" /> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Cat/sources b/sensors/SensorsComboDriver/Cat/sources new file mode 100644 index 00000000..ad2d5c99 --- /dev/null +++ b/sensors/SensorsComboDriver/Cat/sources @@ -0,0 +1,16 @@ +!undef NT_SIGNCODE + +!undef C_DEFINES +!undef INCLUDES +!undef TARGETLIBS + +TARGETNAME=SensorsComboDriver +TARGETTYPE=CATALOG +TARGET_DESTINATION=NTTEST\drivers\Sensors\V2 + +# 8.1 = 2:6.2 +CATALOG_OS_VERSION_LIST= 2:6.2 \ + +SOURCES= \ + $(OBJ_PATH)\..\driver\$(O)\$(TARGETNAME).dll \ + $(OBJ_PATH)\..\driver\$(O)\$(TARGETNAME).inf \
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Cat/sources.dep b/sensors/SensorsComboDriver/Cat/sources.dep new file mode 100644 index 00000000..151fbb3f --- /dev/null +++ b/sensors/SensorsComboDriver/Cat/sources.dep @@ -0,0 +1,2 @@ +BUILD_PASS2_CONSUMES= \ + drivers\mobilepc\sensors\samples\sensorscombodriver\driver|PASS2 \
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/AlsClient.cpp b/sensors/SensorsComboDriver/Driver/AlsClient.cpp new file mode 100644 index 00000000..eb7080a2 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/AlsClient.cpp @@ -0,0 +1,639 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of sensor specific functions. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#include "Clients.h" + +#include "AlsClient.tmh" + +#define SENSORV2_POOL_TAG_AMBIENT_LIGHT '2LmA' + +#define Als_Initial_MinDataInterval_Ms (10) // 100Hz +#define Als_Initial_Lux_Threshold_Pct (1.0f) // Percent threshold: 100% +#define Als_Initial_Lux_Threshold_Abs (0.0f) // Absolute threshold: 0 lux +#define Als_Initial_Kelvin_Threshold_Abs (100.0f) // Absolute threshold: 100 Kelvins +#define Als_Initial_Chromaticity_X_Threshold_Abs (0.01f) // Absolute threshold: 0.01 of a CIE 1931 chromaticity x coordinate +#define Als_Initial_Chromaticity_Y_Threshold_Abs (0.01f) // Absolute threshold: 0.01 of a CIE 1931 chromaticity y coordinate + +#define AlsDevice_Minimum_Lux (-4.0f) +#define AlsDevice_Maximum_Lux (4.0f) +#define AlsDevice_Precision (65536.0f) // 65536 = 2^16, 16 bit data +#define AlsDevice_Range_Lux (AlsDevice_Maximum_Lux - AlsDevice_Minimum_Lux) +#define AlsDevice_Resolution_Lux (AlsDevice_Range_Lux / AlsDevice_Precision) + +// Ambient Light Sensor Unique ID +// {2D2A4524-51E3-4E68-9B0F-5CAEDFB12C02} +DEFINE_GUID(GUID_AlsDevice_UniqueID, + 0x2d2a4524, 0x51e3, 0x4e68, 0x9b, 0xf, 0x5c, 0xae, 0xdf, 0xb1, 0x2c, 0x2); + +// Sensor data +typedef enum +{ + ALS_DATA_TIMESTAMP = 0, + ALS_DATA_LUX, + ALS_DATA_KELVINS, + ALS_DATA_CHROMATICITY_X, + ALS_DATA_CHROMATICITY_Y, + ALS_DATA_ISVALID, + ALS_DATA_COUNT +} ALS_DATA_INDEX; + +// Sensor thresholds +typedef enum +{ + ALS_THRESHOLD_LUX_PCT = 0, + ALS_THRESHOLD_LUX_ABS, + ALS_THRESHOLD_KELVINS_ABS, + ALS_THRESHOLD_CHROMATICITY_X_ABS, + ALS_THRESHOLD_CHROMATICITY_Y_ABS, + ALS_THRESHOLD_COUNT +} ALS_THRESHOLD_INDEX; + +// +// Sensor Enumeration Properties +// + +typedef enum +{ + SENSOR_ALS_AUTOBRIGHTNESS_PREFERRED = SENSOR_ENUMERATION_PROPERTIES_COUNT, // SENSOR_ALS_ENUMERATION_PROPERTIES_INDEX is adding properties to the base SENSOR_ENUMERATION_PROPERTIES_COUNT enum. + SENSOR_ALS_COLOR_CAPABLE, // In order to keep the SENSOR_ALS_ENUMERATION_PROPERTIES_INDEX enum indexing coherent with the SENSOR_ENUMERATION_PROPERTIES_INDEX enum, + // set SENSOR_ALS_AUTOBRIGHTNESS_PREFERRED to the index of the last value in the SENSOR_ENUMERATION_PROPERTIES_INDEX enum + SENSOR_ALS_ENUMERATION_PROPERTIES_COUNT +} SENSOR_ALS_ENUMERATION_PROPERTIES_INDEX; + +typedef enum +{ + SENSOR_PROPERTY_ALS_RESPONSE_CURVE = SENSOR_COMMON_PROPERTY_COUNT, // SENSOR_ALS_PROPERTIES_INDEX is adding SENSOR_PROPERTY_ALS_RESPONSE_CURVE to the base SENSOR_COMMON_PROPERTIES_INDEX enum. + // In order to keep the SENSOR_ALS_PROPERTIES_INDEX enum indexing coherent with the SENSOR_COMMON_PROPERTIES_INDEX enum, + // set SENSOR_PROPERTY_ALS_RESPONSE_CURVE to the index of the last value in the SENSOR_COMMON_PROPERTIES_INDEX enum + SENSOR_ALS_PROPERTY_COUNT +} SENSOR_ALS_PROPERTIES_INDEX; + +//------------------------------------------------------------------------------ +// Function: Initialize +// +// This routine initializes the sensor to its default properties +// +// Arguments: +// Device: IN: WDFDEVICE object +// SensorInstance: IN: SENSOROBJECT for each sensor instance +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +AlsDevice::Initialize( + _In_ WDFDEVICE Device, + _In_ SENSOROBJECT SensorInstance + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Store device and instance + // + m_Device = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + + // + // Create Lock + // + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! ALS WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + // + // Create timer object for polling sensor samples + // + { + WDF_OBJECT_ATTRIBUTES TimerAttributes; + WDF_TIMER_CONFIG TimerConfig; + + WDF_TIMER_CONFIG_INIT(&TimerConfig, OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! ALS WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + } + + // + // Sensor Enumeration Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ALS_ENUMERATION_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_AMBIENT_LIGHT, + Size, + &MemoryHandle, + (PVOID*)&m_pEnumerationProperties); + if (!NT_SUCCESS(Status) || m_pEnumerationProperties == nullptr) + { + TraceError("COMBO %!FUNC! ALS WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); + m_pEnumerationProperties->Count = SENSOR_ALS_ENUMERATION_PROPERTIES_COUNT; + + m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_AmbientLight, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Manufacturer name", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"ALS", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType; + // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration + InitPropVariantFromUInt32(static_cast<ULONG>(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_AlsDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; + InitPropVariantFromBoolean(TRUE, + &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); + + m_pEnumerationProperties->List[SENSOR_ALS_AUTOBRIGHTNESS_PREFERRED].Key = DEVPKEY_LightSensor_AutoBrightnessPreferred; + InitPropVariantFromBoolean(TRUE, + &(m_pEnumerationProperties->List[SENSOR_ALS_AUTOBRIGHTNESS_PREFERRED].Value)); + + m_pEnumerationProperties->List[SENSOR_ALS_COLOR_CAPABLE].Key = DEVPKEY_LightSensor_ColorCapable; + InitPropVariantFromBoolean(TRUE, + &(m_pEnumerationProperties->List[SENSOR_ALS_COLOR_CAPABLE].Value)); + } + + // + // Supported Data-Fields + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(ALS_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_AMBIENT_LIGHT, + Size, + &MemoryHandle, + (PVOID*)&m_pSupportedDataFields); + if (!NT_SUCCESS(Status) || m_pSupportedDataFields == nullptr) + { + TraceError("COMBO %!FUNC! ALS WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = ALS_DATA_COUNT; + + m_pSupportedDataFields->List[ALS_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[ALS_DATA_LUX] = PKEY_SensorData_LightLevel_Lux; + m_pSupportedDataFields->List[ALS_DATA_KELVINS] = PKEY_SensorData_LightTemperature_Kelvins; + m_pSupportedDataFields->List[ALS_DATA_CHROMATICITY_X] = PKEY_SensorData_LightChromaticityX; + m_pSupportedDataFields->List[ALS_DATA_CHROMATICITY_Y] = PKEY_SensorData_LightChromaticityY; + m_pSupportedDataFields->List[ALS_DATA_ISVALID] = PKEY_SensorData_IsValid; + } + + // + // Data + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(ALS_DATA_COUNT); + FILETIME Time = {0}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_AMBIENT_LIGHT, + Size, + &MemoryHandle, + (PVOID*)&m_pData); + if (!NT_SUCCESS(Status) || m_pData == nullptr) + { + TraceError("COMBO %!FUNC! ALS WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = ALS_DATA_COUNT; + + m_pData->List[ALS_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[ALS_DATA_TIMESTAMP].Value)); + + m_pData->List[ALS_DATA_LUX].Key = PKEY_SensorData_LightLevel_Lux; + InitPropVariantFromFloat(0.0f, &(m_pData->List[ALS_DATA_LUX].Value)); + + m_pData->List[ALS_DATA_KELVINS].Key = PKEY_SensorData_LightTemperature_Kelvins; + InitPropVariantFromFloat(0.0f, &(m_pData->List[ALS_DATA_KELVINS].Value)); + + m_pData->List[ALS_DATA_CHROMATICITY_X].Key = PKEY_SensorData_LightChromaticityX; + InitPropVariantFromFloat(0.0f, &(m_pData->List[ALS_DATA_CHROMATICITY_X].Value)); + + m_pData->List[ALS_DATA_CHROMATICITY_Y].Key = PKEY_SensorData_LightChromaticityY; + InitPropVariantFromFloat(0.0f, &(m_pData->List[ALS_DATA_CHROMATICITY_Y].Value)); + + m_pData->List[ALS_DATA_ISVALID].Key = PKEY_SensorData_IsValid; + InitPropVariantFromBoolean(TRUE, &(m_pData->List[ALS_DATA_ISVALID].Value)); + + m_CachedData = { + 1.0f, // Lux + 1.0f, // Kelvins + 0.5f, // Chromaticity X + 0.5f, // Chromaticity Y + TRUE // IsValid + }; + + m_LastSample = { + 0.0f, // Lux + 0.0f, // Kelvins + 0.0f, // Chromaticity X + 0.0f, // Chromaticity Y + TRUE // IsValid + }; + } + + // + // Sensor Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ALS_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_AMBIENT_LIGHT, + Size, + &MemoryHandle, + (PVOID*)&m_pProperties); + if (!NT_SUCCESS(Status) || m_pProperties == nullptr) + { + TraceError("COMBO %!FUNC! ALS WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_ALS_PROPERTY_COUNT; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(Als_Initial_MinDataInterval_Ms, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Value)); + m_IntervalMs = Als_Initial_MinDataInterval_Ms; + m_MinimumIntervalMs = Als_Initial_MinDataInterval_Ms; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_AmbientLight, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Value)); + + ULONG responseCurve[10] = {}; // Array to contain the response curve data. + + // **************************************************************************************** + // The response curve consists of an array of byte pairs. + // The first byte contains the percentage brightness offset to be applied to the display. + // The second byte contains the corresponding ambient light value (in LUX). + // **************************************************************************************** + // (0, 10) + responseCurve[0] = 0; responseCurve[1] = 10; + // (10, 40) + responseCurve[2] = 10; responseCurve[3] = 40; + // (40, 100) + responseCurve[4] = 40; responseCurve[5] = 100; + // (68, 400) + responseCurve[6] = 68; responseCurve[7] = 400; + // (90, 1000) + responseCurve[8] = 90; responseCurve[9] = 1000; + + m_pProperties->List[SENSOR_PROPERTY_ALS_RESPONSE_CURVE].Key = PKEY_LightSensor_ResponseCurve; + InitPropVariantFromUInt32Vector(responseCurve, + 10, + &(m_pProperties->List[SENSOR_PROPERTY_ALS_RESPONSE_CURVE].Value)); + } + + // + // Data filed properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_AMBIENT_LIGHT, + Size, + &MemoryHandle, + (PVOID*)&m_pDataFieldProperties); + if (!NT_SUCCESS(Status) || m_pDataFieldProperties == nullptr) + { + TraceError("COMBO %!FUNC! ALS WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); + m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; + + m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; + InitPropVariantFromFloat(AlsDevice_Resolution_Lux, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromFloat(AlsDevice_Minimum_Lux, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromFloat(AlsDevice_Maximum_Lux, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + + // + // Set default threshold + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(ALS_THRESHOLD_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_AMBIENT_LIGHT, + Size, + &MemoryHandle, + (PVOID*)&m_pThresholds); + if (!NT_SUCCESS(Status) || m_pThresholds == nullptr) + { + TraceError("COMBO %!FUNC! ALS WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = ALS_THRESHOLD_COUNT; + + // Set lux threshold + m_pThresholds->List[ALS_THRESHOLD_LUX_PCT].Key = PKEY_SensorData_LightLevel_Lux; + InitPropVariantFromFloat(Als_Initial_Lux_Threshold_Pct, + &(m_pThresholds->List[ALS_THRESHOLD_LUX_PCT].Value)); + m_CachedThresholds.LuxPct = Als_Initial_Lux_Threshold_Pct; + + m_pThresholds->List[ALS_THRESHOLD_LUX_ABS].Key = PKEY_SensorData_LightLevel_Lux_Threshold_AbsoluteDifference; + InitPropVariantFromFloat(Als_Initial_Lux_Threshold_Abs, + &(m_pThresholds->List[ALS_THRESHOLD_LUX_ABS].Value)); + m_CachedThresholds.LuxAbs = Als_Initial_Lux_Threshold_Abs; + + // Set kelvins threshold + m_pThresholds->List[ALS_THRESHOLD_KELVINS_ABS].Key = PKEY_SensorData_LightTemperature_Kelvins; + InitPropVariantFromFloat(Als_Initial_Kelvin_Threshold_Abs, + &(m_pThresholds->List[ALS_THRESHOLD_KELVINS_ABS].Value)); + m_CachedThresholds.KelvinsAbs = Als_Initial_Kelvin_Threshold_Abs; + + // Set chromaticity x threshold + m_pThresholds->List[ALS_THRESHOLD_CHROMATICITY_X_ABS].Key = PKEY_SensorData_LightChromaticityX; + InitPropVariantFromFloat(Als_Initial_Chromaticity_X_Threshold_Abs, + &(m_pThresholds->List[ALS_THRESHOLD_CHROMATICITY_X_ABS].Value)); + m_CachedThresholds.ChromaticityXAbs = Als_Initial_Chromaticity_X_Threshold_Abs; + + // Set chromaticity y threshold + m_pThresholds->List[ALS_THRESHOLD_CHROMATICITY_Y_ABS].Key = PKEY_SensorData_LightChromaticityY; + InitPropVariantFromFloat(Als_Initial_Chromaticity_Y_Threshold_Abs, + &(m_pThresholds->List[ALS_THRESHOLD_CHROMATICITY_Y_ABS].Value)); + m_CachedThresholds.ChromaticityYAbs = Als_Initial_Chromaticity_Y_Threshold_Abs; + + m_FirstSample = TRUE; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: GetData +// +// 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. +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +AlsDevice::GetData( + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {0}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // new sample? + if (m_FirstSample != FALSE) + { + Status = GetPerformanceTime(&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! ALS GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + // Compare the change of data to threshold, and only push the data back to + // clx if the change exceeds threshold. This is usually done in HW. + if ( + ( + // Lux thresholds needs to exceed absolute and percentage + ((abs(m_CachedData.Lux - m_LastSample.Lux) >= (m_LastSample.Lux * m_CachedThresholds.LuxPct)) && + (abs(m_CachedData.Lux - m_LastSample.Lux) >= m_CachedThresholds.LuxAbs)) || + // If IsValid has changed, the sample is valid + (m_CachedData.IsValid != m_LastSample.IsValid) || + // Kelvin temperature and Chromaticity thresholds + (abs(m_CachedData.Kelvins - m_LastSample.Kelvins) >= m_CachedThresholds.KelvinsAbs) || + (abs(m_CachedData.ChromaticityX - m_LastSample.ChromaticityX) >= m_CachedThresholds.ChromaticityXAbs) || + (abs(m_CachedData.ChromaticityY - m_LastSample.ChromaticityY) >= m_CachedThresholds.ChromaticityYAbs) + ) + && + ( + // In thresholded mode, don't send sample if the last sample sent was not IsValid and current sample is also not IsValid + !((m_CachedThresholds.LuxAbs != 0.0f) && (m_CachedThresholds.LuxPct != 0.0f) && + (m_CachedThresholds.KelvinsAbs != 0.0f) && (m_CachedThresholds.ChromaticityXAbs != 0.0f) && + (m_CachedThresholds.ChromaticityYAbs != 0.0f) && !m_CachedData.IsValid && !m_LastSample.IsValid) + ) + ) + { + DataReady = TRUE; + } + } + + if (DataReady != FALSE) + { + // update last sample + m_LastSample = m_CachedData; + + // push to clx + InitPropVariantFromFloat(m_LastSample.Lux, &(m_pData->List[ALS_DATA_LUX].Value)); + + InitPropVariantFromFloat(m_LastSample.Kelvins, &(m_pData->List[ALS_DATA_KELVINS].Value)); + + InitPropVariantFromFloat(m_LastSample.ChromaticityX, &(m_pData->List[ALS_DATA_CHROMATICITY_X].Value)); + + InitPropVariantFromFloat(m_LastSample.ChromaticityY, &(m_pData->List[ALS_DATA_CHROMATICITY_Y].Value)); + + InitPropVariantFromBoolean(m_LastSample.IsValid, &(m_pData->List[ALS_DATA_ISVALID].Value)); + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[ALS_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! ALS Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +AlsDevice::UpdateCachedThreshold( + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_LightLevel_Lux, + &m_CachedThresholds.LuxPct); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! Failed to get lux pct data from cached threshold %!STATUS!", Status); + } + + if (NT_SUCCESS(Status)) + { + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_LightLevel_Lux_Threshold_AbsoluteDifference, + &m_CachedThresholds.LuxAbs); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! Failed to get lux abs data from cached threshold %!STATUS!", Status); + } + } + + if (NT_SUCCESS(Status)) + { + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_LightTemperature_Kelvins, + &m_CachedThresholds.KelvinsAbs); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! Failed to get kelvin data from cached threshold %!STATUS!", Status); + } + } + + if (NT_SUCCESS(Status)) + { + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_LightChromaticityX, + &m_CachedThresholds.ChromaticityXAbs); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! Failed to get chromaticity x data from cached threshold %!STATUS!", Status); + } + } + + if (NT_SUCCESS(Status)) + { + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_LightChromaticityY, + &m_CachedThresholds.ChromaticityYAbs); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! Failed to get chromaticity y data from cached threshold %!STATUS!", Status); + } + } + + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/BarClient.cpp b/sensors/SensorsComboDriver/Driver/BarClient.cpp new file mode 100644 index 00000000..97135c59 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/BarClient.cpp @@ -0,0 +1,464 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of sensor specific functions. +// +// Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#include "Clients.h" + +#include "BarClient.tmh" + +#define SENSORV2_POOL_TAG_BAROMETER '2RaB' + +#define Bar_Initial_MinDataInterval_Ms (10) // 100Hz +#define Bar_Initial_Threshold_Bar (0.001f) // 1 mBar ~= 10 meter + +#define BarDevice_Minimum_Bar (0.3f) +#define BarDevice_Maximum_Bar (1.1f) +#define BarDevice_Precision (65536.0f) // 65536 = 2^16, 16 bit data +#define BarDevice_Range_Bar (BarDevice_Maximum_Bar - BarDevice_Minimum_Bar) +#define BarDevice_Resolution_Bar (BarDevice_Range_Bar / BarDevice_Precision) + +// Barometer Unique ID +// {46CB48CE-272D-4402-8E09-07748F8940CA} +DEFINE_GUID(GUID_BarDevice_UniqueID, + 0x46cb48ce, 0x272d, 0x4402, 0x8e, 0x9, 0x7, 0x74, 0x8f, 0x89, 0x40, 0xca); + +// Sensor data +typedef enum +{ + BAR_DATA_TIMESTAMP = 0, + BAR_DATA_PRESSURE, + BAR_DATA_COUNT +} BAR_DATA_INDEX; + +// Sensor thresholds +typedef enum +{ + BAR_THRESHOLD_PRESSURE = 0, + BAR_THRESHOLD_COUNT +} BAR_THRESHOLD_INDEX; + + + +//------------------------------------------------------------------------------ +// Function: Initialize +// +// This routine initializes the sensor to its default properties +// +// Arguments: +// Device: IN: WDFDEVICE object +// SensorInstance: IN: SENSOROBJECT for each sensor instance +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +BarDevice::Initialize( + _In_ WDFDEVICE Device, + _In_ SENSOROBJECT SensorInstance + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Store device and instance + // + m_Device = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + + // + // Create Lock + // + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! BAR 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, OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! BAR WdfTimerCreate failed %!STATUS!", Status); + } + } + + // + // Sensor Enumeration Properties + // + if (NT_SUCCESS(Status)) + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ENUMERATION_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_BAROMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pEnumerationProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pEnumerationProperties) + { + TraceError("COMBO %!FUNC! BAR 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_Barometer, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Manufacturer name", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"Barometer", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType; + // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration + InitPropVariantFromUInt32(static_cast<ULONG>(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_BarDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; + InitPropVariantFromBoolean(FALSE, + &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); + } + } + + // + // Supported Data-Fields + // + if (NT_SUCCESS(Status)) + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(BAR_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_BAROMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pSupportedDataFields)); + if (!NT_SUCCESS(Status) || nullptr == m_pSupportedDataFields) + { + TraceError("COMBO %!FUNC! BAR WdfMemoryCreate failed %!STATUS!", Status); + } + else + { + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = BAR_DATA_COUNT; + + m_pSupportedDataFields->List[BAR_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[BAR_DATA_PRESSURE] = PKEY_SensorData_AtmosphericPressure_Bars; + } + } + + // + // Data + // + if (NT_SUCCESS(Status)) + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(BAR_DATA_COUNT); + FILETIME Time = {}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_BAROMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pData)); + if (!NT_SUCCESS(Status) || nullptr == m_pData) + { + TraceError("COMBO %!FUNC! BAR WdfMemoryCreate failed %!STATUS!", Status); + } + else + { + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = BAR_DATA_COUNT; + + m_pData->List[BAR_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[BAR_DATA_TIMESTAMP].Value)); + + m_pData->List[BAR_DATA_PRESSURE].Key = PKEY_SensorData_AtmosphericPressure_Bars; + InitPropVariantFromFloat(0.0f, &(m_pData->List[BAR_DATA_PRESSURE].Value)); + + m_CachedData = 1.013f; + m_LastSample = 0.0f; + } + } + + // + // Sensor Properties + // + if (NT_SUCCESS(Status)) + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_BAROMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pProperties) + { + TraceError("COMBO %!FUNC! BAR WdfMemoryCreate failed %!STATUS!", Status); + } + else + { + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_COMMON_PROPERTY_COUNT; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(Bar_Initial_MinDataInterval_Ms, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Value)); + m_IntervalMs = Bar_Initial_MinDataInterval_Ms; + m_MinimumIntervalMs = Bar_Initial_MinDataInterval_Ms; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_Barometer, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Value)); + } + } + + // + // Data filed properties + // + if (NT_SUCCESS(Status)) + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_BAROMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pDataFieldProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pDataFieldProperties) + { + TraceError("COMBO %!FUNC! BAR 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(BarDevice_Resolution_Bar, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromFloat(BarDevice_Minimum_Bar, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromFloat(BarDevice_Maximum_Bar, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + } + + // + // Set default threshold + // + if (NT_SUCCESS(Status)) + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(BAR_THRESHOLD_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_BAROMETER, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pThresholds)); + if (!NT_SUCCESS(Status) || nullptr == m_pThresholds) + { + TraceError("COMBO %!FUNC! BAR WdfMemoryCreate failed %!STATUS!", Status); + } + else + { + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = BAR_THRESHOLD_COUNT; + + m_pThresholds->List[BAR_THRESHOLD_PRESSURE].Key = PKEY_SensorData_AtmosphericPressure_Bars; + InitPropVariantFromFloat(Bar_Initial_Threshold_Bar, + &(m_pThresholds->List[BAR_THRESHOLD_PRESSURE].Value)); + + m_CachedThresholds = Bar_Initial_Threshold_Bar; + m_FirstSample = TRUE; + } + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: GetData +// +// 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. +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +BarDevice::GetData( + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // new sample? + if (FALSE != m_FirstSample) + { + Status = GetPerformanceTime (&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! BAR GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + // Compare the change of data to threshold, and only push the data back to + // clx if the change exceeds threshold. This is usually done in HW. + if ((abs(m_CachedData - m_LastSample) >= m_CachedThresholds)) + { + DataReady = TRUE; + } + } + + if (FALSE != DataReady) + { + // update last sample + m_LastSample = m_CachedData; + + // push to clx + InitPropVariantFromFloat(m_LastSample, &(m_pData->List[BAR_DATA_PRESSURE].Value)); + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[BAR_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! BAR Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +BarDevice::UpdateCachedThreshold( + ) +{ + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + SENSOR_FunctionEnter(); + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AtmosphericPressure_Bars, + &m_CachedThresholds); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! BAR PropKeyFindKeyGetFloat for pressure failed %!STATUS!", Status); + } + + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/Clients.cpp b/sensors/SensorsComboDriver/Driver/Clients.cpp new file mode 100644 index 00000000..4524b6b6 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/Clients.cpp @@ -0,0 +1,880 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of driver callback function +// from clx to clients. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#include "Clients.h" + +#include "Clients.tmh" + +static const UINT SYSTEM_TICK_COUNT_1MS = 1; // 1ms +//------------------------------------------------------------------------------ +// Function: OnTimerExpire +// +// 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. +// +// Arguments: +// Timer: IN: WDF timer object +// +// Return Value: +// None +//------------------------------------------------------------------------------ +VOID +OnTimerExpire( + _In_ WDFTIMER Timer + ) +{ + PComboDevice pDevice = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + pDevice = GetContextFromSensorInstance(WdfTimerGetParentObject(Timer)); + if (pDevice == nullptr) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + // Get data and push to clx + Lock(pDevice->m_Lock); + Status = pDevice->GetData(); + if (!NT_SUCCESS(Status) && Status != STATUS_DATA_NOT_ACCEPTED) + { + TraceError("COMBO %!FUNC! GetData Failed %!STATUS!", Status); + } + Unlock(pDevice->m_Lock); + + // Schedule next wake up time + if (pDevice->m_MinimumIntervalMs <= pDevice->m_IntervalMs && + FALSE != pDevice->m_PoweredOn && + FALSE != pDevice->m_Started) + { + LONGLONG WaitTime = 0; // in unit of 100ns + + if (pDevice->m_StartTime == 0) + { + // in case we fail to get sensor start time, use static wait time + WaitTime = WDF_REL_TIMEOUT_IN_MS(pDevice->m_IntervalMs); + } + else + { + ULONG CurrentTimeMs = 0; + + // dynamically calculate wait time to avoid jitter + Status = GetPerformanceTime (&CurrentTimeMs); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GetPerformanceTime %!STATUS!", Status); + WaitTime = WDF_REL_TIMEOUT_IN_MS(pDevice->m_IntervalMs); + } + else + { + pDevice->m_SampleCount++; + if (CurrentTimeMs > (pDevice->m_StartTime + (pDevice->m_IntervalMs * (pDevice->m_SampleCount + 1)))) + { + // If we skipped two or more beats, reschedule the timer with a zero due time to catch up on missing samples + WaitTime = 0; + } + else + { + // Else, just compute the remaining time + WaitTime = (pDevice->m_StartTime + + (pDevice->m_IntervalMs * (pDevice->m_SampleCount + 1))) - CurrentTimeMs; + } + + WaitTime = WDF_REL_TIMEOUT_IN_MS(WaitTime); + } + } + + WdfTimerStart(pDevice->m_Timer, WaitTime); + } + +Exit: + + SENSOR_FunctionExit(Status); +} + + + +//------------------------------------------------------------------------------ +// Function: OnStart +// +// Called by Sensor CLX to begin continously sampling the sensor. +// +// Arguments: +// SensorInstance: IN: sensor device object +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnStart( + _In_ SENSOROBJECT SensorInstance + ) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (pDevice == nullptr) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Sensor(%p) parameter is invalid. Failed %!STATUS!", static_cast<PVOID>(&SensorInstance), Status); + goto Exit; + } + + if (pDevice->m_PoweredOn == FALSE) + { + Status = STATUS_DEVICE_NOT_READY; + TraceError("COMBO %!FUNC! Sensor is not powered on! %!STATUS!", Status); + goto Exit; + } + + // + // Start worker thread + // + + pDevice->m_IntervalMs; + + pDevice->m_FirstSample = TRUE; + + // Start polling + + pDevice->m_Started = TRUE; + + InitPropVariantFromUInt32(SensorState_Active, + &(pDevice->m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + WdfTimerStart(pDevice->m_Timer, WDF_REL_TIMEOUT_IN_MS(pDevice->m_MinimumIntervalMs)); + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: OnStop +// +// Called by Sensor CLX to stop continously sampling the sensor. +// +// Arguments: +// SensorInstance: IN: sensor device object +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnStop( + _In_ SENSOROBJECT SensorInstance + ) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (pDevice == nullptr) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Sensor(%p) parameter is invalid. Failed %!STATUS!", static_cast<PVOID>(&SensorInstance), Status); + goto Exit; + } + + // Stop polling + + pDevice->m_Started = FALSE; + + WdfTimerStop(pDevice->m_Timer, TRUE); + + InitPropVariantFromUInt32(SensorState_Idle, + &(pDevice->m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + // + // Restoring system time resolution + // + if (TIMERR_NOERROR != timeEndPeriod(SYSTEM_TICK_COUNT_1MS)) + { + // not a failure, just log message + Status = STATUS_UNSUCCESSFUL; + TraceWarning("COMBO %!FUNC! timeEndPeriod failed to restore timer resolution! %!STATUS!", Status); + } + +Exit: + SENSOR_FunctionExit(Status); + + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: OnGetSupportedDataFields +// +// 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. +// +// Arguments: +// SensorInstance: IN: sensor device object +// pFields: INOUT_OPT: pointer to a list of supported properties +// pSize: OUT: number of bytes for the list of supported properties +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnGetSupportedDataFields( + _In_ SENSOROBJECT SensorInstance, + _Inout_opt_ PSENSOR_PROPERTY_LIST pFields, + _Out_ PULONG pSize + ) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || nullptr == pSize) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Invalid parameters! %!STATUS!", Status); + goto Exit; + } + + if (nullptr == pFields) + { + // Just return size + *pSize = pDevice->m_pSupportedDataFields->AllocatedSizeInBytes; + } + else + { + if (pFields->AllocatedSizeInBytes < pDevice->m_pSupportedDataFields->AllocatedSizeInBytes) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("COMBO %!FUNC! Buffer is too small. Failed %!STATUS!", Status); + goto Exit; + } + + // Fill out data + Status = PropertiesListCopy (pFields, pDevice->m_pSupportedDataFields); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! PropertiesListCopy failed %!STATUS!", Status); + goto Exit; + } + + *pSize = pDevice->m_pSupportedDataFields->AllocatedSizeInBytes; + } + +Exit: + if (!NT_SUCCESS(Status)) + { + *pSize = 0; + } + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: OnGetProperties +// +// 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. +// +// Arguments: +// SensorInstance: IN: sensor device object +// pProperties: INOUT_OPT: pointer to a list of sensor properties +// pSize: OUT: number of bytes for the list of sensor properties +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnGetProperties( + _In_ SENSOROBJECT SensorInstance, + _Inout_opt_ PSENSOR_COLLECTION_LIST pProperties, + _Out_ PULONG pSize + ) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || nullptr == pSize) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Invalid parameters! %!STATUS!", Status); + goto Exit; + } + + if (nullptr == pProperties) + { + // Just return size + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pProperties); + } + else + { + if (pProperties->AllocatedSizeInBytes < + CollectionsListGetMarshalledSize(pDevice->m_pProperties)) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("COMBO %!FUNC! Buffer is too small. Failed %!STATUS!", Status); + goto Exit; + } + + // Fill out all data + Status = CollectionsListCopyAndMarshall(pProperties, pDevice->m_pProperties); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status); + goto Exit; + } + + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pProperties); + } + +Exit: + if (!NT_SUCCESS(Status)) + { + *pSize = 0; + } + SENSOR_FunctionExit(Status); + return Status; +} + + +//------------------------------------------------------------------------------ +// Function: OnGetDataFieldProperties +// +// 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. +// +// Arguments: +// SensorInstance: IN: sensor device object +// DataField: IN: pointer to the propertykey of requested property +// pProperties: INOUT_OPT: pointer to a list of sensor properties +// pSize: OUT: number of bytes for the list of sensor properties +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnGetDataFieldProperties( + _In_ SENSOROBJECT SensorInstance, + _In_ const PROPERTYKEY *DataField, + _Inout_opt_ PSENSOR_COLLECTION_LIST pProperties, + _Out_ PULONG pSize +) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || nullptr == pSize || nullptr == DataField) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Invalid parameters! %!STATUS!", Status); + goto Exit; + } + + if (IsKeyPresentInPropertyList(pDevice->m_pSupportedDataFields, DataField) != FALSE) + { + if (nullptr == pProperties) + { + // Just return size + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties); + } + else + { + if (pProperties->AllocatedSizeInBytes < + CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties)) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("COMBO %!FUNC! Buffer is too small. Failed %!STATUS!", Status); + goto Exit; + } + + // Fill out all data + Status = CollectionsListCopyAndMarshall (pProperties, pDevice->m_pDataFieldProperties); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status); + goto Exit; + } + + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pDataFieldProperties); + } + } + else + { + Status = STATUS_NOT_SUPPORTED; + TraceError("COMBO %!FUNC! Sensor does NOT have properties for this data field. Failed %!STATUS!", Status); + goto Exit; + } + +Exit: + if (!NT_SUCCESS(Status)) + { + *pSize = 0; + } + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: OnGetDataInterval +// +// Called by Sensor CLX to get sampling rate of the sensor. +// +// Arguments: +// SensorInstance: IN: sensor device object +// DataRateMs: OUT: sampling rate in ms +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnGetDataInterval( + _In_ SENSOROBJECT SensorInstance, + _Out_ PULONG DataRateMs + ) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (pDevice == nullptr) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Invalid parameter!"); + goto Exit; + } + + if (DataRateMs == nullptr) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! DataRateMs(%p) parameter is invalid. Failed %!STATUS!", static_cast<PVOID>(DataRateMs), Status); + goto Exit; + } + + *DataRateMs = pDevice->m_IntervalMs; + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: OnSetDataInterval +// +// Called by Sensor CLX to set sampling rate of the sensor. +// +// Arguments: +// SensorInstance: IN: sensor device object +// DataRateMs: IN: sampling rate in ms +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnSetDataInterval( + _In_ SENSOROBJECT SensorInstance, + _In_ ULONG DataRateMs + ) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (pDevice == nullptr || DataRateMs == 0) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Invalid parameter!"); + goto Exit; + } + + pDevice->m_IntervalMs = 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(pDevice->m_MinimumIntervalMs)); + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: OnGetDataThresholds +// +// 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. +// +// Arguments: +// SensorInstance: IN: sensor device object +// pThresholds: INOUT_OPT: pointer to a list of sensor thresholds +// pSize: OUT: number of bytes for the list of sensor thresholds +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnGetDataThresholds( + _In_ SENSOROBJECT SensorInstance, + _Inout_opt_ PSENSOR_COLLECTION_LIST pThresholds, + _Out_ PULONG pSize + ) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice || nullptr == pSize) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Invalid parameters!"); + goto Exit; + } + + if (nullptr == pThresholds) + { + // Just return size + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pThresholds); + } + else + { + if (pThresholds->AllocatedSizeInBytes < + CollectionsListGetMarshalledSize(pDevice->m_pThresholds)) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("COMBO %!FUNC! Buffer is too small!"); + goto Exit; + } + + // Fill out all data + Status = CollectionsListCopyAndMarshall (pThresholds, pDevice->m_pThresholds); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! CollectionsListCopyAndMarshall failed %!STATUS!", Status); + goto Exit; + } + + *pSize = CollectionsListGetMarshalledSize(pDevice->m_pThresholds); + } + +Exit: + if (!NT_SUCCESS(Status)) + { + *pSize = 0; + } + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: OnSetDataThresholds +// +// Called by Sensor CLX to set data thresholds. +// +// Arguments: +// SensorInstance: IN: sensor device object +// pThresholds: IN: pointer to a list of sensor thresholds +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnSetDataThresholds( + _In_ SENSOROBJECT SensorInstance, + _In_ PSENSOR_COLLECTION_LIST pThresholds + ) +{ + ULONG Element; + BOOLEAN IsLocked = FALSE; + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (pDevice == nullptr) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Invalid parameter!"); + goto Exit; + } + + Lock(pDevice->m_Lock); + IsLocked = TRUE; + + for (Element = 0; Element < pThresholds->Count; Element++) + { + Status = PropKeyFindKeySetPropVariant(pDevice->m_pThresholds, + &(pThresholds->List[Element].Key), + TRUE, + &(pThresholds->List[Element].Value)); + if (!NT_SUCCESS(Status)) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! Sensor does NOT have threshold for this data field. Failed %!STATUS!", Status); + goto Exit; + } + } + + // Update cached threshholds + Status = pDevice->UpdateCachedThreshold(); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! UpdateCachedThreshold failed! %!STATUS!", Status); + goto Exit; + } + +Exit: + if (IsLocked) + { + Unlock(pDevice->m_Lock); + IsLocked = FALSE; + } + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: OnIoControl +// +// Called by Sensor CLX to handle IOCTLs that clx does not support +// +// Arguments: +// SensorInstance: IN: Sensor object +// Request: IN: WDF request object +// OutputBufferLength: IN: number of bytes to retrieve from output buffer +// InputBufferLength: IN: number of bytes to retrieve from input buffer +// IoControlCode: IN: IOCTL control code +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS OnIoControl( + _In_ SENSOROBJECT /*SensorInstance*/, // Sensor object + _In_ WDFREQUEST /*Request*/, // WDF request object + _In_ size_t /*OutputBufferLength*/, // number of bytes to retrieve from output buffer + _In_ size_t /*InputBufferLength*/, // number of bytes to retrieve from input buffer + _In_ ULONG /*IoControlCode*/ // IOCTL control code + ) +{ + NTSTATUS Status = STATUS_NOT_SUPPORTED; + + SENSOR_FunctionEnter(); + + SENSOR_FunctionExit(Status); + return Status; +} + + + +// Called by Sensor CLX to begin keeping history +NTSTATUS OnStartHistory(_In_ SENSOROBJECT SensorInstance) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + } + else + { + Status = pDevice->StartHistory(); + } + + SENSOR_FunctionExit(Status); + return Status; +} + +// Called by Sensor CLX to stop keeping history. +NTSTATUS OnStopHistory(_In_ SENSOROBJECT SensorInstance) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + } + else + { + Status = pDevice->StopHistory(); + } + + SENSOR_FunctionExit(Status); + return Status; +} + +// Called by Sensor CLX to enable wake +NTSTATUS OnEnableWake(_In_ SENSOROBJECT SensorInstance) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + } + else + { + pDevice->m_WakeEnabled = TRUE; + Status = pDevice->EnableWake(); + } + + SENSOR_FunctionExit(Status); + return Status; +} + +// Called by Sensor CLX to disable wake +NTSTATUS OnDisableWake(_In_ SENSOROBJECT SensorInstance) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + } + else + { + pDevice->m_WakeEnabled = FALSE; + Status = pDevice->DisableWake(); + } + + SENSOR_FunctionExit(Status); + return Status; +} + +// Called by Sensor CLX to clear all history stored in the sensor. +NTSTATUS OnClearHistory(_In_ SENSOROBJECT SensorInstance) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + } + else + { + Status = pDevice->ClearHistory(); + } + + SENSOR_FunctionExit(Status); + return Status; +} + +// Called by Sensor CLX to start retrieving history. +NTSTATUS OnStartHistoryRetrieval( + _In_ SENSOROBJECT SensorInstance, + _Inout_updates_bytes_(HistorySizeInBytes) PSENSOR_COLLECTION_LIST pHistoryBuffer, + _In_ ULONG HistorySizeInBytes) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + } + else if (sizeof(SENSOR_COLLECTION_LIST) > HistorySizeInBytes) + { + Status = STATUS_BUFFER_TOO_SMALL; + TraceError("COMBO %!FUNC! HistorySizeInBytes is too small %!STATUS!", Status); + } + else + { + Status = pDevice->StartHistoryRetrieval(pHistoryBuffer, HistorySizeInBytes); + } + + SENSOR_FunctionExit(Status); + return Status; +} + +// Called by Sensor CLX to cancel history retrieval. +NTSTATUS OnCancelHistoryRetrieval(_In_ SENSOROBJECT SensorInstance, _Out_ PULONG pBytesWritten) +{ + PComboDevice pDevice = GetContextFromSensorInstance(SensorInstance); + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + } + else + { + Status = pDevice->CancelHistoryRetrieval(pBytesWritten); + } + + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/Clients.h b/sensors/SensorsComboDriver/Driver/Clients.h new file mode 100644 index 00000000..a8992fa7 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/Clients.h @@ -0,0 +1,389 @@ +// 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 (WUDF) + +#pragma once + +#include <windows.h> +#include <wdf.h> +#include <cmath> +#include <timeapi.h> + +#include "SensorsTrace.h" +#include <SensorsCx.h> +#include <SensorsUtils.h> + +// +// CLX Callbacks +// +EVT_SENSOR_DRIVER_START_SENSOR OnStart; +EVT_SENSOR_DRIVER_STOP_SENSOR OnStop; +EVT_SENSOR_DRIVER_GET_SUPPORTED_DATA_FIELDS OnGetSupportedDataFields; +EVT_SENSOR_DRIVER_GET_PROPERTIES OnGetProperties; +EVT_SENSOR_DRIVER_GET_DATA_FIELD_PROPERTIES OnGetDataFieldProperties; +EVT_SENSOR_DRIVER_GET_DATA_INTERVAL OnGetDataInterval; +EVT_SENSOR_DRIVER_SET_DATA_INTERVAL OnSetDataInterval; +EVT_SENSOR_DRIVER_GET_DATA_THRESHOLDS OnGetDataThresholds; +EVT_SENSOR_DRIVER_SET_DATA_THRESHOLDS OnSetDataThresholds; +EVT_SENSOR_DRIVER_DEVICE_IO_CONTROL OnIoControl; +EVT_SENSOR_DRIVER_START_SENSOR_HISTORY OnStartHistory; +EVT_SENSOR_DRIVER_STOP_SENSOR_HISTORY OnStopHistory; +EVT_SENSOR_DRIVER_CLEAR_SENSOR_HISTORY OnClearHistory; +EVT_SENSOR_DRIVER_START_HISTORY_RETRIEVAL OnStartHistoryRetrieval; +EVT_SENSOR_DRIVER_CANCEL_HISTORY_RETRIEVAL OnCancelHistoryRetrieval; +EVT_SENSOR_DRIVER_ENABLE_WAKE OnEnableWake; +EVT_SENSOR_DRIVER_DISABLE_WAKE OnDisableWake; + +EVT_WDF_TIMER OnTimerExpire; + + +/*++ +Routine Description: + Critical section lock/unlock to protect shared context +Return Value: + None +--*/ +#define Lock(lock) { WdfWaitLockAcquire(lock, NULL); } +#define Unlock(lock) { WdfWaitLockRelease(lock); } + +#define SENSORV2_POOL_TAG_COMBO '2bmC' + +// +// Sensor Enumeration Properties +// +typedef enum +{ + SENSOR_TYPE_GUID = 0, + SENSOR_MANUFACTURER, + SENSOR_MODEL, + SENSOR_CONNECTION_TYPE, + SENSOR_PERSISTENT_UNIQUEID, + SENSOR_ISPRIMARY, + SENSOR_ENUMERATION_PROPERTIES_COUNT +} SENSOR_ENUMERATION_PROPERTIES_INDEX; + +enum class SensorConnectionType : ULONG +{ + Integrated = 0, + Attached = 1, + External = 2 +}; + +// +// Data-field Properties +// +typedef enum +{ + SENSOR_RESOLUTION = 0, + SENSOR_MIN_RANGE, + SENSOR_MAX_RANGE, + SENSOR_DATA_FIELD_PROPERTY_COUNT +} SENSOR_DATA_FIELD_PROPERTY_INDEX; + +// +// Sensor Common Properties +// +typedef enum +{ + SENSOR_COMMON_PROPERTY_STATE = 0, + SENSOR_COMMON_PROPERTY_MIN_INTERVAL, + SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE, + SENSOR_COMMON_PROPERTY_TYPE, + SENSOR_COMMON_PROPERTY_COUNT +} SENSOR_COMMON_PROPERTIES_INDEX; + + + +// +// Base --------------------------------------------------------------------- +// +typedef class _ComboDevice +{ +public: + // + // WDF + // + WDFDEVICE m_Device; + SENSOROBJECT m_SensorInstance; + WDFWAITLOCK m_Lock; + WDFTIMER m_Timer; + + // + // Sensor Operation + // + BOOLEAN m_PoweredOn; + BOOLEAN m_Started; + ULONG m_IntervalMs; + ULONG m_MinimumIntervalMs; + BOOLEAN m_FirstSample; + ULONG m_StartTime; + ULONGLONG m_SampleCount; + BOOLEAN m_WakeEnabled; + + // + // Sensor Specific Properties + // + PSENSOR_COLLECTION_LIST m_pEnumerationProperties; + PSENSOR_COLLECTION_LIST m_pProperties; + PSENSOR_PROPERTY_LIST m_pSupportedDataFields; + PSENSOR_COLLECTION_LIST m_pDataFieldProperties; + PSENSOR_COLLECTION_LIST m_pThresholds; + PSENSOR_COLLECTION_LIST m_pData; + +public: + // + // Sensor specific functions + // + virtual NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj) = NULL; + virtual NTSTATUS GetData() = NULL; + virtual NTSTATUS UpdateCachedThreshold() = NULL; + virtual NTSTATUS EnableWake() { return STATUS_NOT_SUPPORTED; } + virtual NTSTATUS DisableWake() { return STATUS_NOT_SUPPORTED; } + + // + // History functions - none of the sensors in this driver actually support history yet, this is for testing purpose now. + // + virtual NTSTATUS StartHistory() { return STATUS_NOT_SUPPORTED; } + virtual NTSTATUS StopHistory() { return STATUS_NOT_SUPPORTED; } + virtual NTSTATUS ClearHistory() { return STATUS_NOT_SUPPORTED; } + virtual NTSTATUS StartHistoryRetrieval(_Inout_ PSENSOR_COLLECTION_LIST /*pHistoryBuffer*/, _In_ ULONG /*HistorySizeInBytes*/) { return STATUS_NOT_SUPPORTED; } + virtual NTSTATUS CancelHistoryRetrieval(_Out_ PULONG /*pBytesWritten*/) { return STATUS_NOT_SUPPORTED; } + +} ComboDevice, *PComboDevice; + +// Set up accessor function to retrieve device context +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ComboDevice, GetContextFromSensorInstance); + + +// +// Ambient Light -------------------------------------------------------------- +// +typedef class _AlsDevice : public _ComboDevice +{ +private: + // Internal struct used to store readings + typedef struct _AlsData + { + FLOAT Lux; + FLOAT Kelvins; + FLOAT ChromaticityX; + FLOAT ChromaticityY; + BOOL IsValid; + } AlsData, *PAlsData; + + // Internal struct used to store thresholds + typedef struct _AlsThresholdData + { + FLOAT LuxPct; + FLOAT LuxAbs; + FLOAT KelvinsAbs; + FLOAT ChromaticityXAbs; + FLOAT ChromaticityYAbs; + } AlsThresholdData; + +private: + + AlsThresholdData m_CachedThresholds; + AlsData m_CachedData; + AlsData m_LastSample; + +public: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + NTSTATUS UpdateCachedThreshold(); + +} AlsDevice, *PAlsDevice; + + + +// +// Barometer -------------------------------------------------------------- +// +typedef class _BarDevice : public _ComboDevice +{ +private: + + FLOAT m_CachedThresholds; + FLOAT m_CachedData; + FLOAT m_LastSample; + +public: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + NTSTATUS UpdateCachedThreshold(); + +} BarDevice, *PBarDevice; + + + +// +// Gyroscope ------------------------------------------------------------------ +// +typedef class _GyrDevice : public _ComboDevice +{ +private: + + VEC3D m_CachedThresholds; + VEC3D m_CachedData; + VEC3D m_LastSample; + +public: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + NTSTATUS UpdateCachedThreshold(); + +} GyrDevice, *PGyrDevice; + + + +// +// Magnetometer --------------------------------------------------------------- +// +typedef struct _MagData +{ + VEC3D Axis; + ULONG Accuracy; +} MagData, *PMagData; + +typedef class _MagDevice : public _ComboDevice +{ +private: + + VEC3D m_CachedThresholds; + MagData m_CachedData; + MagData m_LastSample; + +public: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + NTSTATUS UpdateCachedThreshold(); + +} MagDevice, *PMagDevice; + + + +// +// Proximity ------------------------------------------------------------------ +// +typedef struct +{ + BOOL Detected; + ULONG DistanceMillimeters; +} PrxData, *PPrxData; + +typedef class _PrxDevice : public _ComboDevice +{ +private: + + PrxData m_CachedData; + PrxData m_LastSample; + +public: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + NTSTATUS UpdateCachedThreshold(); + +} PrxDevice, *PPrxDevice; + + + +// +// Relative Fusion ------------------------------------------------------------------ +// +typedef class _RelativeFusionDevice : public _ComboDevice +{ +private: + + QUATERNION m_CachedThresholds; + QUATERNION m_CachedData; + QUATERNION m_LastSample; + +public: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + NTSTATUS UpdateCachedThreshold(); + +} RelativeFusionDevice, *PRelativeFusionDevice; + +// +// Linear Accelerometer -------------------------------------------------------------- +// +typedef class _LinearAccelerometerDevice : public _ComboDevice +{ +private: + + typedef struct _LinearAccelerometerSample + { + VEC3D Axis; + BOOL Shake; + } LinearAccelerometerSample, *PLinearAccelerometerSample; + + LinearAccelerometerSample m_CachedThresholds; + LinearAccelerometerSample m_CachedData; + LinearAccelerometerSample m_LastSample; + +public: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + NTSTATUS UpdateCachedThreshold(); + +} LinearAccelerometerDevice, *PLinearAccelerometerDevice; + +// +// Gravity Vector -------------------------------------------------------------- +// +typedef class _GravityVectorDevice : public _ComboDevice +{ +private: + + VEC3D m_CachedThresholds; + VEC3D m_CachedData; + VEC3D m_LastSample; + +public: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + NTSTATUS UpdateCachedThreshold(); + +} GravityVectorDevice, *PGravityVectorDevice; + +// +// Geomagnetic Orientation ------------------------------------------------------------------ +// +typedef class _GeomagneticOrientationDevice : public _ComboDevice +{ +private: + + typedef struct _GeomagneticOrientationSample + { + QUATERNION Quaternion; + FLOAT RotationAngle_Degrees; + FLOAT DeclinationAngle_Degrees; + } GeomagneticOrientationSample, *PGeomagneticOrientationSample; + + GeomagneticOrientationSample m_CachedThresholds; + GeomagneticOrientationSample m_CachedData; + GeomagneticOrientationSample m_LastSample; + +public: + + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(); + NTSTATUS UpdateCachedThreshold(); + +} GeomagneticOrientationDevice, *PGeomagneticOrientationDevice; diff --git a/sensors/SensorsComboDriver/Driver/Device.cpp b/sensors/SensorsComboDriver/Driver/Device.cpp new file mode 100644 index 00000000..b93bbbd1 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/Device.cpp @@ -0,0 +1,477 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of WDF callback functions +// for combo driver. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#include "Clients.h" +#include "Driver.h" + +#include <new.h> + +#include "Device.tmh" + +//--------------------------------------- +// Declare and map devices below +//--------------------------------------- +enum Device +{ + Device_Als = 0, + Device_Bar, + Device_GeomagneticOrientation, + Device_GravityVector, + Device_Gyr, + Device_LinearAccelerometer, + Device_Mag, + Device_Prx, + Device_RelativeFusion, + // Keep this last + Device_Count +}; + +static const ULONG SensorInstanceCount = Device_Count; +static SENSOROBJECT SensorInstancesBuffer[SensorInstanceCount]; // Global buffer to avoid allocate and free + +inline size_t GetDeviceSizeAtIndex( + _In_ ULONG Index) +{ + size_t result = 0; + switch (static_cast<Device>(Index)) + { + case Device_Als: result = sizeof(AlsDevice); break; + case Device_Bar: result = sizeof(BarDevice); break; + case Device_GeomagneticOrientation: result = sizeof(GeomagneticOrientationDevice); break; + case Device_GravityVector: result = sizeof(GravityVectorDevice); break; + case Device_Gyr: result = sizeof(GyrDevice); break; + case Device_LinearAccelerometer: result = sizeof(LinearAccelerometerDevice); break; + case Device_Mag: result = sizeof(MagDevice); break; + case Device_Prx: result = sizeof(PrxDevice); break; + case Device_RelativeFusion: result = sizeof(RelativeFusionDevice); break; + default: break; // invalid + } + return result; +} + +void AllocateDeviceAtIndex( + _In_ ULONG Index, + _Inout_ PComboDevice* ppDevice + ) +{ + switch (static_cast<Device>(Index)) + { + case Device_Als: *ppDevice = new(*ppDevice) AlsDevice; break; + case Device_Bar: *ppDevice = new(*ppDevice) BarDevice; break; + case Device_GeomagneticOrientation: *ppDevice = new(*ppDevice) GeomagneticOrientationDevice; break; + case Device_GravityVector: *ppDevice = new(*ppDevice) GravityVectorDevice; break; + case Device_Gyr: *ppDevice = new(*ppDevice) GyrDevice; break; + case Device_LinearAccelerometer: *ppDevice = new(*ppDevice) LinearAccelerometerDevice; break; + case Device_Mag: *ppDevice = new(*ppDevice) MagDevice; break; + case Device_Prx: *ppDevice = new(*ppDevice) PrxDevice; break; + case Device_RelativeFusion: *ppDevice = new(*ppDevice) RelativeFusionDevice; break; + + default: break; // invalid (let driver fail) + } +} + +//------------------------------------------------------------------------------ +// +// Function: OnDeviceAdd +// +// This routine is the AddDevice entry point for the combo 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. +// +// Arguments: +// Driver: IN: Supplies a handle to the driver object created in DriverEntry +// DeviceInit: IN: Supplies a pointer to a framework-allocated WDFDEVICE_INIT structure +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnDeviceAdd( + _In_ WDFDRIVER /*Driver*/, + _Inout_ PWDFDEVICE_INIT pDeviceInit + ) +{ + WDF_PNPPOWER_EVENT_CALLBACKS Callbacks; + WDFDEVICE Device; + WDF_OBJECT_ATTRIBUTES FdoAttributes; + ULONG Flag = 0; + SENSOR_CONTROLLER_CONFIG SensorConfig; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + WDF_OBJECT_ATTRIBUTES_INIT(&FdoAttributes); + + // + // Initialize FDO attributes and set up file object with sensor extension + // + Status = SensorsCxDeviceInitConfig(pDeviceInit, &FdoAttributes, Flag); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! SensorsCxDeviceInitConfig failed %!STATUS!", Status); + goto Exit; + } + + // + // Register the PnP callbacks with the framework. + // + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&Callbacks); + Callbacks.EvtDevicePrepareHardware = OnPrepareHardware; + Callbacks.EvtDeviceReleaseHardware = OnReleaseHardware; + Callbacks.EvtDeviceD0Entry = OnD0Entry; + Callbacks.EvtDeviceD0Exit = OnD0Exit; + + WdfDeviceInitSetPnpPowerEventCallbacks(pDeviceInit, &Callbacks); + + // + // Call the framework to create the device + // + Status = WdfDeviceCreate(&pDeviceInit, &FdoAttributes, &Device); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! WdfDeviceCreate failed %!STATUS!", Status); + goto Exit; + } + + // + // Register CLX callback function pointers + // + SENSOR_CONTROLLER_CONFIG_INIT(&SensorConfig); + SensorConfig.DriverIsPowerPolicyOwner = WdfUseDefault; + + SensorConfig.EvtSensorStart = OnStart; + SensorConfig.EvtSensorStop = OnStop; + SensorConfig.EvtSensorGetSupportedDataFields = OnGetSupportedDataFields; + SensorConfig.EvtSensorGetDataInterval = OnGetDataInterval; + SensorConfig.EvtSensorSetDataInterval = OnSetDataInterval; + SensorConfig.EvtSensorGetDataFieldProperties = OnGetDataFieldProperties; + SensorConfig.EvtSensorGetDataThresholds = OnGetDataThresholds; + SensorConfig.EvtSensorSetDataThresholds = OnSetDataThresholds; + SensorConfig.EvtSensorGetProperties = OnGetProperties; + SensorConfig.EvtSensorDeviceIoControl = OnIoControl; + SensorConfig.EvtSensorStartHistory = OnStartHistory; + SensorConfig.EvtSensorStopHistory = OnStopHistory; + SensorConfig.EvtSensorClearHistory = OnClearHistory; + SensorConfig.EvtSensorStartHistoryRetrieval = OnStartHistoryRetrieval; + SensorConfig.EvtSensorCancelHistoryRetrieval = OnCancelHistoryRetrieval; + SensorConfig.EvtSensorEnableWake = OnEnableWake; + SensorConfig.EvtSensorDisableWake = OnDisableWake; + + // + // Set up power capabilities and IO queues + // + Status = SensorsCxDeviceInitialize(Device, &SensorConfig); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! SensorDeviceInitialize failed %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + +//------------------------------------------------------------------------------ +// +// Function: OnPrepareHardware +// +// 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). +// +// Argument: +// Device: IN: Supplies a handle to the framework device object +// ResourcesRaw: IN: 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. +// ResourcesTranslated: IN: Supplies a handle to a collection of framework +// resource objects. This collection identifies the translated +// (system-physical) hardware resources that have been assigned to the +// device. The resources appear from the CPU's point of view. +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnPrepareHardware( + _In_ WDFDEVICE Device, + _In_ WDFCMRESLIST /*ResourcesRaw*/, + _In_ WDFCMRESLIST /*ResourcesTranslated*/ + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + for (ULONG Count = 0; Count < SensorInstanceCount; Count++) + { + PComboDevice pDevice = nullptr; + WDF_OBJECT_ATTRIBUTES SensorAttr; + SENSOR_CONFIG SensorConfig; + SENSOROBJECT SensorInstance; + + // Create WDFOBJECT for the sensor + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&SensorAttr, ComboDevice); + SensorAttr.ContextSizeOverride = GetDeviceSizeAtIndex(Count); + + // Register sensor instance with clx + Status = SensorsCxSensorCreate(Device, &SensorAttr, &SensorInstance); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! SensorsCxSensorCreate failed %!STATUS!", Status); + goto Exit; + } + + pDevice = GetContextFromSensorInstance(SensorInstance); + if (nullptr == pDevice) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + AllocateDeviceAtIndex(Count, &pDevice); + + // Fill out properties + Status = pDevice->Initialize(Device, SensorInstance); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! Initialize device object failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_CONFIG_INIT(&SensorConfig); + SensorConfig.pEnumerationList = pDevice->m_pEnumerationProperties; + Status = SensorsCxSensorInitialize(SensorInstance, &SensorConfig); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! SensorsCxSensorInitialize failed %!STATUS!", Status); + goto Exit; + } + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// +// Function: OnReleaseHardware +// +// This routine is called by the framework when the PnP manager is revoking +// ownership of our resources. This may be in response to either +// IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. This routine is responsible for +// performing cleanup of resources allocated in PrepareHardware callback. +// This callback is invoked before passing the request down to the lower driver. +// This routine will also be invoked by the framework if the prepare hardware +// callback returns a failure. +// +// Argument: +// Device: IN: Supplies a handle to the framework device object +// ResourcesTranslated: IN: Supplies a handle to a collection of framework +// resource objects. This collection identifies the translated +// (system-physical) hardware resources that have been assigned to the +// device. The resources appear from the CPU's point of view. +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnReleaseHardware( + _In_ WDFDEVICE Device, + _In_ WDFCMRESLIST /*ResourcesTranslated*/ + ) +{ + ULONG Count = SensorInstanceCount; + PComboDevice pDevice = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + Status = SensorsCxDeviceGetSensorList(Device, SensorInstancesBuffer, &Count); + if (!NT_SUCCESS(Status)) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status); + goto Exit; + } + + for (Count = 0; Count < SensorInstanceCount; Count++) + { + pDevice = GetContextFromSensorInstance(SensorInstancesBuffer[Count]); + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + // Delete lock + if (NULL != pDevice->m_Lock) + { + WdfObjectDelete(pDevice->m_Lock); + pDevice->m_Lock = NULL; + } + + // Delete sensor instance + if (NULL != pDevice->m_SensorInstance) + { + WdfObjectDelete(pDevice->m_SensorInstance); + // The pDevice context created using WdfMemoryCreate and parented to m_SensorInstance is automatically + // destroyed when m_SensorInstance is deleted. pDevice is therefore no longer accessible beyond the above call to WdfObjectDelete. + // We can therefore not set the m_SensorInstance member back to NULL. We instead set pDevice to nullptr. + pDevice = nullptr; + } + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// +// Function: OnD0Entry +// +// 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. +// +// Argument: +// Device: IN: Supplies a handle to the framework device object +// PreviousState: IN: WDF_POWER_DEVICE_STATE-typed enumerator that identifies +// the device power state that the device was in before this transition to D0 +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnD0Entry( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE /*PreviousState*/ + ) +{ + ULONG Count = SensorInstanceCount; + PComboDevice pDevice = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Get sensor instances + // + Status = SensorsCxDeviceGetSensorList(Device, SensorInstancesBuffer, &Count); + if (!NT_SUCCESS(Status)) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status); + goto Exit; + } + + // + // Powering on all sensor instances + // + for (Count = 0; Count < SensorInstanceCount; Count++) + { + pDevice = GetContextFromSensorInstance(SensorInstancesBuffer[Count]); + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + pDevice->m_PoweredOn = TRUE; + InitPropVariantFromUInt32(SensorState_Idle, + &(pDevice->m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// +// Function: OnD0Exit +// +// 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. +// +// Argument: +// Device: IN: Supplies a handle to the framework device object +// TargetState: IN: Supplies the device power state which the device will be put +// in once the callback is complete +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +OnD0Exit( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE /*TargetState*/ + ) +{ + ULONG Count = SensorInstanceCount; + PComboDevice pDevice = nullptr; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Get sensor instances + // + Status = SensorsCxDeviceGetSensorList(Device, SensorInstancesBuffer, &Count); + if (!NT_SUCCESS(Status)) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! SensorsCxDeviceGetSensorList failed %!STATUS!", Status); + goto Exit; + } + + // + // Powering off all sensor instances + // + for (Count = 0; Count < SensorInstanceCount; Count++) + { + pDevice = GetContextFromSensorInstance(SensorInstancesBuffer[Count]); + if (nullptr == pDevice) + { + Status = STATUS_INVALID_PARAMETER; + TraceError("COMBO %!FUNC! GetContextFromSensorInstance failed %!STATUS!", Status); + goto Exit; + } + + pDevice->m_PoweredOn = FALSE; + InitPropVariantFromUInt32(SensorState_Idle, + &(pDevice->m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} diff --git a/sensors/SensorsComboDriver/Driver/Driver.cpp b/sensors/SensorsComboDriver/Driver/Driver.cpp new file mode 100644 index 00000000..1ebc7a01 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/Driver.cpp @@ -0,0 +1,100 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of entry and exit point of combo driver. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#include "Clients.h" +#include "Driver.h" + +#include "Driver.tmh" + +//------------------------------------------------------------------------------ +// Function: DriverEntry +// +// This routine is the driver initialization entry point. +// +// Arguments: +// DriverObject: IN: Pointer to the driver object created by the I/O manager +// RegistryPath: IN: Pointer to the driver specific registry key +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +{ + WDF_DRIVER_CONFIG DriverConfig; + NTSTATUS Status = STATUS_SUCCESS; + + // + // Initialize WPP Tracing + // + WPP_INIT_TRACING(DriverObject, NULL); + + SENSOR_FunctionEnter(); + + DriverConfig.DriverPoolTag = SENSORV2_POOL_TAG_COMBO; + + // + // Initialize the driver configuration structure. + // + WDF_DRIVER_CONFIG_INIT(&DriverConfig, 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("COMBO %!FUNC! WdfDriverCreate failed: %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: OnDriverUnload +// +// This routine is called when the driver unloads. +// +// Arguments: +// Driver: IN: driver object +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +VOID +OnDriverUnload( + _In_ WDFDRIVER Driver + ) +{ + SENSOR_FunctionEnter(); + + UNREFERENCED_PARAMETER(Driver); + + SENSOR_FunctionExit(STATUS_SUCCESS); + + WPP_CLEANUP(Driver); + + return; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/Driver.h b/sensors/SensorsComboDriver/Driver/Driver.h new file mode 100644 index 00000000..de307270 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/Driver.h @@ -0,0 +1,31 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved +// +// Abstract: +// +// This module contains the type definitions for the combo +// driver callback class. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#pragma once + +WDF_EXTERN_C_START + +// +// Driver Entry/Exit Functions +// +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_UNLOAD OnDriverUnload; + +// +// WDF Device Callbacks +// +EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; +EVT_WDF_DEVICE_PREPARE_HARDWARE OnPrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE OnReleaseHardware; +EVT_WDF_DEVICE_D0_ENTRY OnD0Entry; +EVT_WDF_DEVICE_D0_EXIT OnD0Exit; + +WDF_EXTERN_C_END
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/GeomagneticOrientationClient.cpp b/sensors/SensorsComboDriver/Driver/GeomagneticOrientationClient.cpp new file mode 100644 index 00000000..b20339a7 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/GeomagneticOrientationClient.cpp @@ -0,0 +1,485 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of sensor specific functions. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#include "Clients.h" + +#include "GeomagneticOrientationClient.tmh" + +#define SENSORV2_POOL_TAG_GEOMAGNETIC_ORIENTATION '9OeG' + +#define GeomagneticOrientation_Initial_MinDataInterval_Ms (10) // 100Hz + +#define GeomagneticOrientation_Quarternion_Maximum (1.0f) +#define GeomagneticOrientation_Quarternion_Minimum (-1.0f) +#define GeomagneticOrientation_Quarternion_Resolution ((GeomagneticOrientation_Quarternion_Maximum-GeomagneticOrientation_Quarternion_Minimum)/65536) + +// Geomagnetic Orientation Sensor Unique ID +// {E4F5FDEA-F268-480F-9D88-A368D381C4C2} +DEFINE_GUID(GUID_GeomagneticOrientationDevice_UniqueID, + 0xe4f5fdea, 0xf268, 0x480f, 0x9d, 0x88, 0xa3, 0x68, 0xd3, 0x81, 0xc4, 0xc2); + +// Sensor data +typedef enum +{ + GEOMAGNETIC_ORIENTATION_DATA_TIMESTAMP = 0, + GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_W, + GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_X, + GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Y, + GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Z, + GEOMAGNETIC_ORIENTATION_DATA_ROTATION_ANGLE_DEGREES, + GEOMAGNETIC_ORIENTATION_DATA_DECLINATION_ANGLE_DEGREES, + GEOMAGNETIC_ORIENTATION_DATA_COUNT +} GEOMAGNETIC_ORIENTATION_DATA_INDEX; + +// Sensor thresholds +typedef enum +{ + GEOMAGNETIC_ORIENTATION_THRESHOLD_ROTATION_ANGLES_DEGREES = 0, + GEOMAGNETIC_ORIENTATION_THRESHOLD_COUNT +} GEOMAGNETIC_ORIENTATION_THRESHOLD_INDEX; + +//------------------------------------------------------------------------------ +// Function: Initialize +// +// This routine initializes the sensor to its default properties +// +// Arguments: +// Device: IN: WDFDEVICE object +// SensorInstance: IN: SENSOROBJECT for each sensor instance +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +GeomagneticOrientationDevice::Initialize( + _In_ WDFDEVICE Device, + _In_ SENSOROBJECT SensorInstance + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Store device and instance + // + m_Device = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + + // + // Create Lock + // + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! Geomagnetic Orientation WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + // + // Create timer object for polling sensor samples + // + { + WDF_OBJECT_ATTRIBUTES TimerAttributes; + WDF_TIMER_CONFIG TimerConfig; + + WDF_TIMER_CONFIG_INIT(&TimerConfig, OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GeomagneticOrientationDevice WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + } + + // + // Sensor Enumeration Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ENUMERATION_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GEOMAGNETIC_ORIENTATION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pEnumerationProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pEnumerationProperties) + { + TraceError("COMBO %!FUNC! GeomagneticOrientationDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); + m_pEnumerationProperties->Count = SENSOR_ENUMERATION_PROPERTIES_COUNT; + + m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_GeomagneticOrientation, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Manufacturer name", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"Geomagnetic Orientation Sensor", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType; + // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration + InitPropVariantFromUInt32(static_cast<ULONG>(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_GeomagneticOrientationDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; + InitPropVariantFromBoolean(FALSE, + &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); + } + + // + // Supported Data-Fields + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(GEOMAGNETIC_ORIENTATION_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GEOMAGNETIC_ORIENTATION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pSupportedDataFields)); + if (!NT_SUCCESS(Status) || nullptr == m_pSupportedDataFields) + { + TraceError("COMBO %!FUNC! GeomagneticOrientationDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = GEOMAGNETIC_ORIENTATION_DATA_COUNT; + + m_pSupportedDataFields->List[GEOMAGNETIC_ORIENTATION_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_W] = PKEY_SensorData_QuaternionW; + m_pSupportedDataFields->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_X] = PKEY_SensorData_QuaternionX; + m_pSupportedDataFields->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Y] = PKEY_SensorData_QuaternionY; + m_pSupportedDataFields->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Z] = PKEY_SensorData_QuaternionZ; + m_pSupportedDataFields->List[GEOMAGNETIC_ORIENTATION_DATA_ROTATION_ANGLE_DEGREES] = PKEY_SensorData_RotationAngle_Degrees; + m_pSupportedDataFields->List[GEOMAGNETIC_ORIENTATION_DATA_DECLINATION_ANGLE_DEGREES] = PKEY_SensorData_DeclinationAngle_Degrees; + } + + // + // Data + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(GEOMAGNETIC_ORIENTATION_DATA_COUNT); + FILETIME Time = {0}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GEOMAGNETIC_ORIENTATION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pData)); + if (!NT_SUCCESS(Status) || nullptr == m_pData) + { + TraceError("COMBO %!FUNC! GeomagneticOrientationDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = GEOMAGNETIC_ORIENTATION_DATA_COUNT; + + m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_TIMESTAMP].Value)); + + m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_W].Key = PKEY_SensorData_QuaternionW; + InitPropVariantFromFloat(1.0, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_W].Value)); + + m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_X].Key = PKEY_SensorData_QuaternionX; + InitPropVariantFromFloat(0.0, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_X].Value)); + + m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Y].Key = PKEY_SensorData_QuaternionY; + InitPropVariantFromFloat(0.0, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Y].Value)); + + m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Z].Key = PKEY_SensorData_QuaternionZ; + InitPropVariantFromFloat(0.0, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Z].Value)); + + m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_ROTATION_ANGLE_DEGREES].Key = PKEY_SensorData_RotationAngle_Degrees; + InitPropVariantFromFloat(0.0, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_ROTATION_ANGLE_DEGREES].Value)); + + m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_DECLINATION_ANGLE_DEGREES].Key = PKEY_SensorData_DeclinationAngle_Degrees; + InitPropVariantFromFloat(0.0, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_DECLINATION_ANGLE_DEGREES].Value)); + + ZeroMemory(&m_LastSample, sizeof(m_LastSample)); + ZeroMemory(&m_CachedData, sizeof(m_CachedData)); + m_CachedData.Quaternion.W = 1.0f; // This is the initial position + m_CachedData.Quaternion.X = 0.0f; // This is the initial position + m_CachedData.Quaternion.Y = 0.0f; // This is the initial position + m_CachedData.Quaternion.Z = 0.0f; // This is the initial position + m_CachedData.RotationAngle_Degrees = 0.0f; // This is the initial position + m_CachedData.DeclinationAngle_Degrees = 0.0f; // This is the initial position + } + + // + // Sensor Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GEOMAGNETIC_ORIENTATION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pProperties) + { + TraceError("COMBO %!FUNC! GeomagneticOrientationDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_COMMON_PROPERTY_COUNT; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(GeomagneticOrientation_Initial_MinDataInterval_Ms, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Value)); + m_IntervalMs = GeomagneticOrientation_Initial_MinDataInterval_Ms; + m_MinimumIntervalMs = GeomagneticOrientation_Initial_MinDataInterval_Ms; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_GeomagneticOrientation, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Value)); + } + + // + // Data filed properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GEOMAGNETIC_ORIENTATION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pDataFieldProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pDataFieldProperties) + { + TraceError("COMBO %!FUNC! GeomagneticOrientationDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); + m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; + + m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; + InitPropVariantFromFloat(GeomagneticOrientation_Quarternion_Resolution, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromFloat(GeomagneticOrientation_Quarternion_Minimum, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromFloat(GeomagneticOrientation_Quarternion_Maximum, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + + // + // Set default threshold + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(GEOMAGNETIC_ORIENTATION_THRESHOLD_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GEOMAGNETIC_ORIENTATION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pThresholds)); + if (!NT_SUCCESS(Status) || nullptr == m_pThresholds) + { + TraceError("COMBO %!FUNC! GeomagneticOrientationDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = GEOMAGNETIC_ORIENTATION_THRESHOLD_COUNT; + + m_pThresholds->List[GEOMAGNETIC_ORIENTATION_THRESHOLD_ROTATION_ANGLES_DEGREES].Key = PKEY_SensorData_RotationAngle_Degrees; + InitPropVariantFromFloat(0.0f, &(m_pThresholds->List[GEOMAGNETIC_ORIENTATION_THRESHOLD_ROTATION_ANGLES_DEGREES].Value)); + + ZeroMemory(&m_CachedThresholds, sizeof(m_CachedThresholds)); + m_FirstSample = TRUE; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: GetData +// +// 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. +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +GeomagneticOrientationDevice::GetData( + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {0}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // new sample? + if (FALSE != m_FirstSample) + { + Status = GetPerformanceTime (&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! GeomagneticOrientationDevice GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + // Compare the change of data to threshold, and only push the data back to + // clx if the change exceeds threshold. This is usually done in HW. + if ((abs(m_CachedData.RotationAngle_Degrees - m_LastSample.RotationAngle_Degrees) >= m_CachedThresholds.RotationAngle_Degrees)) + { + DataReady = TRUE; + } + } + + if (FALSE != DataReady) + { + // update last sample + m_LastSample = m_CachedData; + + // push to clx + InitPropVariantFromFloat(m_LastSample.Quaternion.W, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_W].Value)); + InitPropVariantFromFloat(m_LastSample.Quaternion.X, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_X].Value)); + InitPropVariantFromFloat(m_LastSample.Quaternion.Y, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Y].Value)); + InitPropVariantFromFloat(m_LastSample.Quaternion.Z, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_QUATERNION_Z].Value)); + InitPropVariantFromFloat(m_LastSample.RotationAngle_Degrees, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_ROTATION_ANGLE_DEGREES].Value)); + InitPropVariantFromFloat(m_LastSample.DeclinationAngle_Degrees, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_DECLINATION_ANGLE_DEGREES].Value)); + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[GEOMAGNETIC_ORIENTATION_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! GeomagneticOrientationDevice Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +GeomagneticOrientationDevice::UpdateCachedThreshold( + ) +{ + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + SENSOR_FunctionEnter(); + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_RotationAngle_Degrees, + &m_CachedThresholds.RotationAngle_Degrees); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GeomagneticOrientationDevice PropKeyFindKeyGetFloat for Rotation Angle failed! %!STATUS!", Status); + goto Exit; + } +Exit: + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/GravityVectorClient.cpp b/sensors/SensorsComboDriver/Driver/GravityVectorClient.cpp new file mode 100644 index 00000000..4dc53d7e --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/GravityVectorClient.cpp @@ -0,0 +1,499 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of sensor specific functions. +// +// Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#include "Clients.h" + +#include "GravityVectorClient.tmh" + + + +#define SENSORV2_POOL_TAG_GRAVITY_VECTOR '6ArG' + +#define GravityVectorDevice_Default_MinDataInterval (4) +#define GravityVectorDevice_Default_Axis_Threshold (1.0f) +#define GravityVectorDevice_Axis_Resolution (4.0f / 65536.0f) // in delta g +#define GravityVectorDevice_Axis_Minimum (-2.0f) // in g +#define GravityVectorDevice_Axis_Maximum (2.0f) // in g + + +// Linear Accelerometer Unique ID +// {56E11473-2BB7-41E4-863A-DA014200C0DC} +DEFINE_GUID(GUID_GravityVectorDevice_UniqueID, + 0x56e11473, 0x2bb7, 0x41e4, 0x86, 0x3a, 0xda, 0x1, 0x42, 0x0, 0xc0, 0xdc); + +// Sensor data +typedef enum +{ + GRAVITY_VECTOR_DATA_X = 0, + GRAVITY_VECTOR_DATA_Y, + GRAVITY_VECTOR_DATA_Z, + GRAVITY_VECTOR_DATA_TIMESTAMP, + GRAVITY_VECTOR_DATA_COUNT +} GRAVITY_VECTOR_DATA_INDEX; + +//------------------------------------------------------------------------------ +// Function: Initialize +// +// This routine initializes the sensor to its default properties +// +// Arguments: +// Device: IN: WDFDEVICE object +// SensorInstance: IN: SENSOROBJECT for each sensor instance +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +GravityVectorDevice::Initialize( + _In_ WDFDEVICE Device, + _In_ SENSOROBJECT SensorInstance + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Store device and instance + // + m_Device = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + + // + // Create Lock + // + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GRA WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + // + // Create timer object for polling sensor samples + // + { + WDF_OBJECT_ATTRIBUTES TimerAttributes; + WDF_TIMER_CONFIG TimerConfig; + + WDF_TIMER_CONFIG_INIT(&TimerConfig, OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + TimerConfig.TolerableDelay = 0; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GRA WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + } + + // + // Sensor Enumeration Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ENUMERATION_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GRAVITY_VECTOR, + Size, + &MemoryHandle, + (PVOID*)&m_pEnumerationProperties); + if (!NT_SUCCESS(Status) || m_pEnumerationProperties == nullptr) + { + TraceError("COMBO %!FUNC! GRA WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); + m_pEnumerationProperties->Count = SENSOR_ENUMERATION_PROPERTIES_COUNT; + + m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_GravityVector, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Manufacturer name", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"Gravity Vector Sensor", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType; + // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration + InitPropVariantFromUInt32(static_cast<ULONG>(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_GravityVectorDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; + InitPropVariantFromBoolean(FALSE, + &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); + } + + // + // Supported Data-Fields + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(GRAVITY_VECTOR_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GRAVITY_VECTOR, + Size, + &MemoryHandle, + (PVOID*)&m_pSupportedDataFields); + if (!NT_SUCCESS(Status) || m_pSupportedDataFields == nullptr) + { + TraceError("COMBO %!FUNC! GRA WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = GRAVITY_VECTOR_DATA_COUNT; + + m_pSupportedDataFields->List[GRAVITY_VECTOR_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[GRAVITY_VECTOR_DATA_X] = PKEY_SensorData_AccelerationX_Gs; + m_pSupportedDataFields->List[GRAVITY_VECTOR_DATA_Y] = PKEY_SensorData_AccelerationY_Gs; + m_pSupportedDataFields->List[GRAVITY_VECTOR_DATA_Z] = PKEY_SensorData_AccelerationZ_Gs; + } + + // + // Data + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(GRAVITY_VECTOR_DATA_COUNT); + FILETIME Time = {0}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GRAVITY_VECTOR, + Size, + &MemoryHandle, + (PVOID*)&m_pData); + if (!NT_SUCCESS(Status) || m_pData == nullptr) + { + TraceError("COMBO %!FUNC! GRA WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = GRAVITY_VECTOR_DATA_COUNT; + + m_pData->List[GRAVITY_VECTOR_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[GRAVITY_VECTOR_DATA_TIMESTAMP].Value)); + + m_pData->List[GRAVITY_VECTOR_DATA_X].Key = PKEY_SensorData_AccelerationX_Gs; + InitPropVariantFromFloat(0.0, &(m_pData->List[GRAVITY_VECTOR_DATA_X].Value)); + + m_pData->List[GRAVITY_VECTOR_DATA_Y].Key = PKEY_SensorData_AccelerationY_Gs; + InitPropVariantFromFloat(0.0, &(m_pData->List[GRAVITY_VECTOR_DATA_Y].Value)); + + m_pData->List[GRAVITY_VECTOR_DATA_Z].Key = PKEY_SensorData_AccelerationZ_Gs; + InitPropVariantFromFloat(0.0, &(m_pData->List[GRAVITY_VECTOR_DATA_Z].Value)); + + m_CachedData.X = 0.0f; + m_CachedData.Y = 0.0f; + m_CachedData.Z = 0.0f; + + m_LastSample.X = 0.0f; + m_LastSample.Y = 0.0f; + m_LastSample.Z = 0.0f; + } + + // + // Sensor Properties + // + { + m_IntervalMs = GravityVectorDevice_Default_MinDataInterval; + + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GRAVITY_VECTOR, + Size, + &MemoryHandle, + (PVOID*)&m_pProperties); + if (!NT_SUCCESS(Status) || m_pProperties == nullptr) + { + TraceError("GRA %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_COMMON_PROPERTY_COUNT; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(GravityVectorDevice_Default_MinDataInterval, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_GravityVector, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Value)); + } + + // + // Data field properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GRAVITY_VECTOR, + Size, + &MemoryHandle, + (PVOID*)&m_pDataFieldProperties); + if (!NT_SUCCESS(Status) || m_pDataFieldProperties == nullptr) + { + TraceError("COMBO %!FUNC! GRA WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); + m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; + + m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; + InitPropVariantFromFloat(GravityVectorDevice_Axis_Resolution, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromFloat(GravityVectorDevice_Axis_Minimum, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromFloat(GravityVectorDevice_Axis_Maximum, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + + // + // Set default threshold + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(GRAVITY_VECTOR_DATA_COUNT - 1); // Timestamp does not have thresholds + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GRAVITY_VECTOR, + Size, + &MemoryHandle, + (PVOID*)&m_pThresholds); + if (!NT_SUCCESS(Status) || m_pThresholds == nullptr) + { + TraceError("COMBO %!FUNC! GRA WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = GRAVITY_VECTOR_DATA_COUNT - 1; + + m_pThresholds->List[GRAVITY_VECTOR_DATA_X].Key = PKEY_SensorData_AccelerationX_Gs; + InitPropVariantFromFloat(GravityVectorDevice_Default_Axis_Threshold, + &(m_pThresholds->List[GRAVITY_VECTOR_DATA_X].Value)); + + m_pThresholds->List[GRAVITY_VECTOR_DATA_Y].Key = PKEY_SensorData_AccelerationY_Gs; + InitPropVariantFromFloat(GravityVectorDevice_Default_Axis_Threshold, + &(m_pThresholds->List[GRAVITY_VECTOR_DATA_Y].Value)); + + m_pThresholds->List[GRAVITY_VECTOR_DATA_Z].Key = PKEY_SensorData_AccelerationZ_Gs; + InitPropVariantFromFloat(GravityVectorDevice_Default_Axis_Threshold, + &(m_pThresholds->List[GRAVITY_VECTOR_DATA_Z].Value)); + + m_CachedThresholds.X = GravityVectorDevice_Default_Axis_Threshold; + m_CachedThresholds.Y = GravityVectorDevice_Default_Axis_Threshold; + m_CachedThresholds.Z = GravityVectorDevice_Default_Axis_Threshold; + + m_FirstSample = TRUE; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: GetData +// +// 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. +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +GravityVectorDevice::GetData( + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {0}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // new sample? + if (m_FirstSample != FALSE) + { + Status = GetPerformanceTime (&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! GRA GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + // Compare the change of data to threshold, and only push the data back to + // clx if the change exceeds threshold. This is usually done in HW. + if ( (abs(m_CachedData.X - m_LastSample.X) >= m_CachedThresholds.X) || + (abs(m_CachedData.Y - m_LastSample.Y) >= m_CachedThresholds.Y) || + (abs(m_CachedData.Z - m_LastSample.Z) >= m_CachedThresholds.Z)) + { + DataReady = TRUE; + } + } + + if (DataReady != FALSE) + { + // update last sample + m_LastSample.X = m_CachedData.X; + m_LastSample.Y = m_CachedData.Y; + m_LastSample.Z = m_CachedData.Z; + + // push to clx + InitPropVariantFromFloat(m_LastSample.X, &(m_pData->List[GRAVITY_VECTOR_DATA_X].Value)); + InitPropVariantFromFloat(m_LastSample.Y, &(m_pData->List[GRAVITY_VECTOR_DATA_Y].Value)); + InitPropVariantFromFloat(m_LastSample.Z, &(m_pData->List[GRAVITY_VECTOR_DATA_Z].Value)); + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[GRAVITY_VECTOR_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! GRA Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +GravityVectorDevice::UpdateCachedThreshold( + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AccelerationX_Gs, + &m_CachedThresholds.X); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GRA PropKeyFindKeyGetFloat for X failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AccelerationY_Gs, + &m_CachedThresholds.Y); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GRA PropKeyFindKeyGetFloat for Y failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AccelerationZ_Gs, + &m_CachedThresholds.Z); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GRA PropKeyFindKeyGetFloat for Z failed! %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/GyrClient.cpp b/sensors/SensorsComboDriver/Driver/GyrClient.cpp new file mode 100644 index 00000000..389e6e8e --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/GyrClient.cpp @@ -0,0 +1,510 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of sensor specific functions. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#include "Clients.h" + +#include "GyrClient.tmh" + +#define SENSORV2_POOL_TAG_GYROSCOPE '2oyG' + +// Chasis says 5-250Hz but unit test fails if below 250Hz??? +#define Gyr_MinDataInterval_Ms (4) // 250Hz +#define Gyr_Initial_Threshold_DegreesPerSecond (10.0f) + +#define GyrDevice_Minimum_DegreesPerSecond (-2000.0f) +#define GyrDevice_Maximum_DegreesPerSecond (2000.0f) +#define GyrDevice_Precision (65536.0f) // 65536 = 2^16, 16 bit data +#define GyrDevice_Range_DegreesPerSecond \ + (GyrDevice_Maximum_DegreesPerSecond - GyrDevice_Minimum_DegreesPerSecond) +#define GyrDevice_Resolution_DegreesPerSecond \ + (GyrDevice_Range_DegreesPerSecond / GyrDevice_Precision) + +// Gyroscope Unique ID +// {61A61B96-1E4C-47C6-8697-654680101446} +DEFINE_GUID(GUID_GyrDevice_UniqueID, + 0x61a61b96, 0x1e4c, 0x47c6, 0x86, 0x97, 0x65, 0x46, 0x80, 0x10, 0x14, 0x46); + +// Sensor data +typedef enum +{ + GYR_DATA_TIMESTAMP = 0, + GYR_DATA_X, + GYR_DATA_Y, + GYR_DATA_Z, + GYR_DATA_COUNT +} GYR_DATA_INDEX; + +// Sensor thresholds +typedef enum +{ + GYR_THRESHOLD_X = 0, + GYR_THRESHOLD_Y, + GYR_THRESHOLD_Z, + GYR_THRESHOLD_COUNT +} GYR_THRESHOLD_INDEX; + +//------------------------------------------------------------------------------ +// Function: Initialize +// +// This routine initializes the sensor to its default properties +// +// Arguments: +// Device: IN: WDFDEVICE object +// SensorInstance: IN: SENSOROBJECT for each sensor instance +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +GyrDevice::Initialize( + _In_ WDFDEVICE Device, + _In_ SENSOROBJECT SensorInstance + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Store device and instance + // + m_Device = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + + // + // Create Lock + // + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GYR WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + // + // Create timer object for polling sensor samples + // + { + WDF_OBJECT_ATTRIBUTES TimerAttributes; + WDF_TIMER_CONFIG TimerConfig; + + WDF_TIMER_CONFIG_INIT(&TimerConfig, OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + TimerConfig.TolerableDelay = 0; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GYR WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + } + + // + // Sensor Enumeration Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ENUMERATION_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GYROSCOPE, + Size, + &MemoryHandle, + (PVOID*)&m_pEnumerationProperties); + if (!NT_SUCCESS(Status) || m_pEnumerationProperties == nullptr) + { + TraceError("COMBO %!FUNC! GYR WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); + m_pEnumerationProperties->Count = SENSOR_ENUMERATION_PROPERTIES_COUNT; + + m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_Gyrometer3D, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Manufacturer name", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"GYR", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType; + // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration + InitPropVariantFromUInt32(static_cast<ULONG>(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_GyrDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; + InitPropVariantFromBoolean(FALSE, + &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); + } + + // + // Supported Data-Fields + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(GYR_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GYROSCOPE, + Size, + &MemoryHandle, + (PVOID*)&m_pSupportedDataFields); + if (!NT_SUCCESS(Status) || m_pSupportedDataFields == nullptr) + { + TraceError("COMBO %!FUNC! GYR WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = GYR_DATA_COUNT; + + m_pSupportedDataFields->List[GYR_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[GYR_DATA_X] = PKEY_SensorData_AngularVelocityX_DegreesPerSecond; + m_pSupportedDataFields->List[GYR_DATA_Y] = PKEY_SensorData_AngularVelocityY_DegreesPerSecond; + m_pSupportedDataFields->List[GYR_DATA_Z] = PKEY_SensorData_AngularVelocityZ_DegreesPerSecond; + } + + // + // Data + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(GYR_DATA_COUNT); + FILETIME Time = {0}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GYROSCOPE, + Size, + &MemoryHandle, + (PVOID*)&m_pData); + if (!NT_SUCCESS(Status) || m_pData == nullptr) + { + TraceError("COMBO %!FUNC! GYR WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = GYR_DATA_COUNT; + + m_pData->List[GYR_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[GYR_DATA_TIMESTAMP].Value)); + + m_pData->List[GYR_DATA_X].Key = PKEY_SensorData_AngularVelocityX_DegreesPerSecond; + InitPropVariantFromFloat(0.0f, &(m_pData->List[GYR_DATA_X].Value)); + + m_pData->List[GYR_DATA_Y].Key = PKEY_SensorData_AngularVelocityY_DegreesPerSecond; + InitPropVariantFromFloat(0.0f, &(m_pData->List[GYR_DATA_Y].Value)); + + m_pData->List[GYR_DATA_Z].Key = PKEY_SensorData_AngularVelocityZ_DegreesPerSecond; + InitPropVariantFromFloat(0.0f, &(m_pData->List[GYR_DATA_Z].Value)); + + m_CachedData.X = 0.0f; + m_CachedData.Y = 0.0f; + m_CachedData.Z = 0.0f; + + m_LastSample.X = 0.0f; + m_LastSample.Y = 0.0f; + m_LastSample.Z = 0.0f; + } + + // + // Sensor Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GYROSCOPE, + Size, + &MemoryHandle, + (PVOID*)&m_pProperties); + if (!NT_SUCCESS(Status) || m_pProperties == nullptr) + { + TraceError("COMBO %!FUNC! GYR WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_COMMON_PROPERTY_COUNT; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(Gyr_MinDataInterval_Ms, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Value)); + m_IntervalMs = Gyr_MinDataInterval_Ms; + m_MinimumIntervalMs = Gyr_MinDataInterval_Ms; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_Gyrometer3D, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Value)); + } + + // + // Data filed properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GYROSCOPE, + Size, + &MemoryHandle, + (PVOID*)&m_pDataFieldProperties); + if (!NT_SUCCESS(Status) || m_pDataFieldProperties == nullptr) + { + TraceError("COMBO %!FUNC! GYR WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); + m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; + + m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; + InitPropVariantFromFloat(GyrDevice_Resolution_DegreesPerSecond, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromFloat(GyrDevice_Minimum_DegreesPerSecond, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromFloat(GyrDevice_Maximum_DegreesPerSecond, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + + // + // Set default threshold + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(GYR_THRESHOLD_COUNT); // Timestamp and shake do not have thresholds + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_GYROSCOPE, + Size, + &MemoryHandle, + (PVOID*)&m_pThresholds); + if (!NT_SUCCESS(Status) || m_pThresholds == nullptr) + { + TraceError("COMBO %!FUNC! GYR WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = GYR_THRESHOLD_COUNT; + + m_pThresholds->List[GYR_THRESHOLD_X].Key = PKEY_SensorData_AngularVelocityX_DegreesPerSecond; + InitPropVariantFromFloat(Gyr_Initial_Threshold_DegreesPerSecond, + &(m_pThresholds->List[GYR_THRESHOLD_X].Value)); + + m_pThresholds->List[GYR_THRESHOLD_Y].Key = PKEY_SensorData_AngularVelocityY_DegreesPerSecond; + InitPropVariantFromFloat(Gyr_Initial_Threshold_DegreesPerSecond, + &(m_pThresholds->List[GYR_THRESHOLD_Y].Value)); + + m_pThresholds->List[GYR_THRESHOLD_Z].Key = PKEY_SensorData_AngularVelocityZ_DegreesPerSecond; + InitPropVariantFromFloat(Gyr_Initial_Threshold_DegreesPerSecond, + &(m_pThresholds->List[GYR_THRESHOLD_Z].Value)); + + m_CachedThresholds.X = Gyr_Initial_Threshold_DegreesPerSecond; + m_CachedThresholds.Y = Gyr_Initial_Threshold_DegreesPerSecond; + m_CachedThresholds.Z = Gyr_Initial_Threshold_DegreesPerSecond; + + m_FirstSample = TRUE; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: GetData +// +// 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. +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +GyrDevice::GetData( + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {0}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // new sample? + if (m_FirstSample != FALSE) + { + Status = GetPerformanceTime (&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! GYR GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + // Compare the change of data to threshold, and only push the data back to + // clx if the change exceeds threshold. This is usually done in HW. + if ( (abs(m_CachedData.X - m_LastSample.X) >= m_CachedThresholds.X) || + (abs(m_CachedData.Y - m_LastSample.Y) >= m_CachedThresholds.Y) || + (abs(m_CachedData.Z - m_LastSample.Z) >= m_CachedThresholds.Z)) + { + DataReady = TRUE; + } + } + + if (DataReady != FALSE) + { + // update last sample + m_LastSample.X = m_CachedData.X; + m_LastSample.Y = m_CachedData.Y; + m_LastSample.Z = m_CachedData.Z; + + // push to clx + InitPropVariantFromFloat(m_LastSample.X, &(m_pData->List[GYR_DATA_X].Value)); + InitPropVariantFromFloat(m_LastSample.Y, &(m_pData->List[GYR_DATA_Y].Value)); + InitPropVariantFromFloat(m_LastSample.Z, &(m_pData->List[GYR_DATA_Z].Value)); + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[GYR_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! GYR Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +GyrDevice::UpdateCachedThreshold( + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AngularVelocityX_DegreesPerSecond, + &m_CachedThresholds.X); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GYR PropKeyFindKeyGetFloat for X failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AngularVelocityY_DegreesPerSecond, + &m_CachedThresholds.Y); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GYR PropKeyFindKeyGetFloat for Y failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AngularVelocityZ_DegreesPerSecond, + &m_CachedThresholds.Z); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GYR PropKeyFindKeyGetFloat for Z failed! %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/MagClient.cpp b/sensors/SensorsComboDriver/Driver/MagClient.cpp new file mode 100644 index 00000000..5768cbc5 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/MagClient.cpp @@ -0,0 +1,537 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of sensor specific functions. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#include "Clients.h" + +#include "MagClient.tmh" + +#define SENSORV2_POOL_TAG_MAGNETOMETER '2ngM' + +#define Mag_Initial_MinDataInterval_Ms (10) // 100Hz +#define Mag_Initial_Threshold_Microteslas (5.0f) // 5uT + +#define MagDevice_Minimum_Microteslas (-2000.0f) +#define MagDevice_Maximum_Microteslas (2000.0f) +#define MagDevice_Precision (65536.0f) // 65536 = 2^16, 16 bit data +#define MagDevice_Range_Microteslas \ + (MagDevice_Maximum_Microteslas - MagDevice_Minimum_Microteslas) +#define MagDevice_Resolution_Microteslas \ + (MagDevice_Range_Microteslas / MagDevice_Precision) + +// Magnetometer Sensor Unique ID +// {0746712D-DFB1-42A7-8AAE-6089D2423CDE} +DEFINE_GUID(GUID_MagDevice_UniqueID, + 0x746712d, 0xdfb1, 0x42a7, 0x8a, 0xae, 0x60, 0x89, 0xd2, 0x42, 0x3c, 0xde); + +// Sensor data +typedef enum +{ + MAG_DATA_TIMESTAMP = 0, + MAG_DATA_X, + MAG_DATA_Y, + MAG_DATA_Z, + MAG_DATA_ACCURACY, + MAG_DATA_COUNT +} MAG_DATA_INDEX; + +// Sensor thresholds +typedef enum +{ + MAG_THRESHOLD_X = 0, + MAG_THRESHOLD_Y, + MAG_THRESHOLD_Z, + MAG_THRESHOLD_COUNT +} MAG_THRESHOLD_INDEX; + +// +// Sensor Enumeration Properties +// +typedef enum +{ + SENSOR_MAG_NAME = SENSOR_ENUMERATION_PROPERTIES_COUNT, // SENSOR_MAG_ENUMERATION_PROPERTIES_INDEX is adding SENSOR_MAG_NAME to the base SENSOR_ENUMERATION_PROPERTIES_INDEX enum. + // In order to keep the SENSOR_MAG_ENUMERATION_PROPERTIES_INDEX enum indexing coherent with the SENSOR_ENUMERATION_PROPERTIES_INDEX enum, + // set SENSOR_MAG_NAME to the index of the last value in the SENSOR_ENUMERATION_PROPERTIES_INDEX enum + SENSOR_MAG_ENUMERATION_PROPERTIES_COUNT +} SENSOR_MAG_ENUMERATION_PROPERTIES_INDEX; + + + +//------------------------------------------------------------------------------ +// Function: Initialize +// +// This routine initializes the sensor to its default properties +// +// Arguments: +// Device: IN: WDFDEVICE object +// SensorInstance: IN: SENSOROBJECT for each sensor instance +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +MagDevice::Initialize( + _In_ WDFDEVICE Device, + _In_ SENSOROBJECT SensorInstance + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Store device and instance + // + m_Device = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + + // + // Create Lock + // + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! GYR WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + // + // Create timer object for polling sensor samples + // + { + WDF_OBJECT_ATTRIBUTES TimerAttributes; + WDF_TIMER_CONFIG TimerConfig; + + WDF_TIMER_CONFIG_INIT(&TimerConfig, OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! MAG WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + } + + // + // Sensor Enumeration Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_MAG_ENUMERATION_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_MAGNETOMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pEnumerationProperties); + if (!NT_SUCCESS(Status) || m_pEnumerationProperties == nullptr) + { + TraceError("COMBO %!FUNC! MAG WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); + m_pEnumerationProperties->Count = SENSOR_MAG_ENUMERATION_PROPERTIES_COUNT; + + m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_Magnetometer3D, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Manufacturer name", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"MAG", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType; + // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration + InitPropVariantFromUInt32(static_cast<ULONG>(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_MagDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; + InitPropVariantFromBoolean(FALSE, + &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); + // + // Alternate name used by SensorOpen + // + + m_pEnumerationProperties->List[SENSOR_MAG_NAME].Key = DEVPKEY_Sensor_Name; + InitPropVariantFromString(L"\\\\.\\Mag", + &(m_pEnumerationProperties->List[SENSOR_MAG_NAME].Value)); + } + + // + // Supported Data-Fields + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(MAG_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_MAGNETOMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pSupportedDataFields); + if (!NT_SUCCESS(Status) || m_pSupportedDataFields == nullptr) + { + TraceError("COMBO %!FUNC! MAG WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = MAG_DATA_COUNT; + + m_pSupportedDataFields->List[MAG_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[MAG_DATA_X] = PKEY_SensorData_MagneticFieldStrengthX_Microteslas; + m_pSupportedDataFields->List[MAG_DATA_Y] = PKEY_SensorData_MagneticFieldStrengthY_Microteslas; + m_pSupportedDataFields->List[MAG_DATA_Z] = PKEY_SensorData_MagneticFieldStrengthZ_Microteslas; + m_pSupportedDataFields->List[MAG_DATA_ACCURACY] = PKEY_SensorData_MagnetometerAccuracy; + } + + // + // Data + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(MAG_DATA_COUNT); + FILETIME Time = {0}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_MAGNETOMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pData); + if (!NT_SUCCESS(Status) || m_pData == nullptr) + { + TraceError("COMBO %!FUNC! MAG WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = MAG_DATA_COUNT; + + m_pData->List[MAG_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[MAG_DATA_TIMESTAMP].Value)); + + m_pData->List[MAG_DATA_X].Key = PKEY_SensorData_MagneticFieldStrengthX_Microteslas; + InitPropVariantFromFloat(0.0f, &(m_pData->List[MAG_DATA_X].Value)); + + m_pData->List[MAG_DATA_Y].Key = PKEY_SensorData_MagneticFieldStrengthY_Microteslas; + InitPropVariantFromFloat(0.0f, &(m_pData->List[MAG_DATA_Y].Value)); + + m_pData->List[MAG_DATA_Z].Key = PKEY_SensorData_MagneticFieldStrengthZ_Microteslas; + InitPropVariantFromFloat(0.0f, &(m_pData->List[MAG_DATA_Z].Value)); + + m_pData->List[MAG_DATA_ACCURACY].Key = PKEY_SensorData_MagnetometerAccuracy; + InitPropVariantFromUInt32(MagnetometerAccuracy_Unknown, &(m_pData->List[MAG_DATA_ACCURACY].Value)); + + m_CachedData.Axis.X = 0.0f; + m_CachedData.Axis.Y = 1.0f; + m_CachedData.Axis.Z = 0.0f; + m_CachedData.Accuracy = MagnetometerAccuracy_High; + + m_LastSample.Axis.X = 0.0f; + m_LastSample.Axis.Y = 0.0f; + m_LastSample.Axis.Z = 0.0f; + m_LastSample.Accuracy = MagnetometerAccuracy_Unknown; + } + + // + // Sensor Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_MAGNETOMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pProperties); + if (!NT_SUCCESS(Status) || m_pProperties == nullptr) + { + TraceError("COMBO %!FUNC! MAG WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_COMMON_PROPERTY_COUNT; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(Mag_Initial_MinDataInterval_Ms, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Value)); + m_IntervalMs = Mag_Initial_MinDataInterval_Ms; + m_MinimumIntervalMs = Mag_Initial_MinDataInterval_Ms; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_Magnetometer3D, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Value)); + } + + // + // Data field properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_MAGNETOMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pDataFieldProperties); + if (!NT_SUCCESS(Status) || m_pDataFieldProperties == nullptr) + { + TraceError("COMBO %!FUNC! MAG WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); + m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; + + m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; + InitPropVariantFromFloat(MagDevice_Resolution_Microteslas, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromFloat(MagDevice_Minimum_Microteslas, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromFloat(MagDevice_Maximum_Microteslas, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + + // + // Set default threshold + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(MAG_THRESHOLD_COUNT); // Timestamp and shake do not have thresholds + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_MAGNETOMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pThresholds); + if (!NT_SUCCESS(Status) || m_pThresholds == nullptr) + { + TraceError("COMBO %!FUNC! MAG WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = MAG_THRESHOLD_COUNT; + + m_pThresholds->List[MAG_THRESHOLD_X].Key = PKEY_SensorData_MagneticFieldStrengthX_Microteslas; + InitPropVariantFromFloat(Mag_Initial_Threshold_Microteslas, + &(m_pThresholds->List[MAG_THRESHOLD_X].Value)); + + m_pThresholds->List[MAG_THRESHOLD_Y].Key = PKEY_SensorData_MagneticFieldStrengthY_Microteslas; + InitPropVariantFromFloat(Mag_Initial_Threshold_Microteslas, + &(m_pThresholds->List[MAG_THRESHOLD_Y].Value)); + + m_pThresholds->List[MAG_THRESHOLD_Z].Key = PKEY_SensorData_MagneticFieldStrengthZ_Microteslas; + InitPropVariantFromFloat(Mag_Initial_Threshold_Microteslas, + &(m_pThresholds->List[MAG_THRESHOLD_Z].Value)); + + m_CachedThresholds.X = Mag_Initial_Threshold_Microteslas; + m_CachedThresholds.Y = Mag_Initial_Threshold_Microteslas; + m_CachedThresholds.Z = Mag_Initial_Threshold_Microteslas; + + m_FirstSample = TRUE; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: GetData +// +// 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. +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +MagDevice::GetData( + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {0}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // new sample? + if (m_FirstSample != FALSE) + { + Status = GetPerformanceTime (&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! MAG GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + // Compare the change of data to threshold, and only push the data back to + // clx if the change exceeds threshold. This is usually done in HW. + if ( (abs(m_CachedData.Axis.X - m_LastSample.Axis.X) >= m_CachedThresholds.X) || + (abs(m_CachedData.Axis.Y - m_LastSample.Axis.Y) >= m_CachedThresholds.Y) || + (abs(m_CachedData.Axis.Z - m_LastSample.Axis.Z) >= m_CachedThresholds.Z)) + { + DataReady = TRUE; + } + } + + if (DataReady != FALSE) + { + // update last sample + m_LastSample.Axis.X = m_CachedData.Axis.X; + m_LastSample.Axis.Y = m_CachedData.Axis.Y; + m_LastSample.Axis.Z = m_CachedData.Axis.Z; + m_LastSample.Accuracy = m_CachedData.Accuracy; + + // push to clx + InitPropVariantFromFloat (m_LastSample.Axis.X, &(m_pData->List[MAG_DATA_X].Value)); + InitPropVariantFromFloat (m_LastSample.Axis.Y, &(m_pData->List[MAG_DATA_Y].Value)); + InitPropVariantFromFloat (m_LastSample.Axis.Z, &(m_pData->List[MAG_DATA_Z].Value)); + InitPropVariantFromUInt32(m_LastSample.Accuracy, &(m_pData->List[MAG_DATA_ACCURACY].Value)); + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[MAG_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! MAG Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +MagDevice::UpdateCachedThreshold( + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_MagneticFieldStrengthX_Microteslas, + &m_CachedThresholds.X); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! MAG PropKeyFindKeyGetFloat for X failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_MagneticFieldStrengthY_Microteslas, + &m_CachedThresholds.Y); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! MAG PropKeyFindKeyGetFloat for Y failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_MagneticFieldStrengthZ_Microteslas, + &m_CachedThresholds.Z); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! MAG PropKeyFindKeyGetFloat for Z failed! %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/PrxClient.cpp b/sensors/SensorsComboDriver/Driver/PrxClient.cpp new file mode 100644 index 00000000..fa10e095 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/PrxClient.cpp @@ -0,0 +1,458 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of sensor specific functions. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#include "Clients.h" + +#include "PrxClient.tmh" + +#define SENSORV2_POOL_TAG_PROXIMITY '2ixP' + +static const ULONG Prx_MinDataInterval_Ms = 10; // 100Hz + +static const ULONG PrxDevice_Minimum_Millimeters = 3; +static const ULONG PrxDevice_Maximum_Millimeters = 50; +static const ULONG PrxDevice_Resolution_Millimeters = 1; + +// Proximity Sensor Unique ID +// {4B6BE805-2432-4B6B-A5E3-DEA67CA43225} +DEFINE_GUID(GUID_PrxDevice_UniqueID, + 0x4b6be805, 0x2432, 0x4b6b, 0xa5, 0xe3, 0xde, 0xa6, 0x7c, 0xa4, 0x32, 0x25); + +// Sensor data +typedef enum +{ + PRX_DATA_TIMESTAMP = 0, + PRX_DATA_DETECT, + PRX_DATA_DISTANCE, + PRX_DATA_COUNT +} PRX_DATA_INDEX; + +static const ULONG PRX_THRESHOLD_COUNT = 0; // proxmity sensor has no threshold + +// +// Additional Sensor Properties +// +typedef enum +{ + SENSOR_PROPERTY_PRX_TYPE = SENSOR_ENUMERATION_PROPERTIES_COUNT, // SENSOR_PRX_PROPERTIES_INDEX is adding SENSOR_PROPERTY_PRX_TYPE to the base SENSOR_PROPERTIES_INDEX enum. + // In order to keep the SENSOR_PRX_PROPERTIES_INDEX enum indexing coherent with the SENSOR_PROPERTIES_INDEX enum, + // set SENSOR_PROPERTY_PRX_TYPE to the index of the last value in the SENSOR_PROPERTIES_INDEX enum + SENSOR_ISWAKECAPABLE = SENSOR_PROPERTY_PRX_TYPE + 1, + SENSOR_PRX_ENUMERATION_PROPERTY_COUNT +} SENSOR_PRX_PROPERTIES_INDEX; + +//------------------------------------------------------------------------------ +// Function: Initialize +// +// This routine initializes the sensor to its default properties +// +// Arguments: +// Device: IN: WDFDEVICE object +// SensorInstance: IN: SENSOROBJECT for each sensor instance +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +PrxDevice::Initialize( + _In_ WDFDEVICE Device, + _In_ SENSOROBJECT SensorInstance + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Store device and instance + // + m_Device = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + + // + // Create Lock + // + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! PRX WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + // + // Create timer object for polling sensor samples + // + { + WDF_OBJECT_ATTRIBUTES TimerAttributes; + WDF_TIMER_CONFIG TimerConfig; + + WDF_TIMER_CONFIG_INIT(&TimerConfig, OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! PRX WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + } + + // + // Sensor Enumeration Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_PRX_ENUMERATION_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_PROXIMITY, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pEnumerationProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pEnumerationProperties) + { + TraceError("COMBO %!FUNC! PRX WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); + m_pEnumerationProperties->Count = SENSOR_ENUMERATION_PROPERTIES_COUNT; + m_pEnumerationProperties->Count = SENSOR_PRX_ENUMERATION_PROPERTY_COUNT; + + m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_Proximity, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Manufacturer name", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"PRX", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType; + // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration + InitPropVariantFromUInt32(static_cast<ULONG>(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_PrxDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; + InitPropVariantFromBoolean(FALSE, + &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); + + m_pEnumerationProperties->List[SENSOR_PROPERTY_PRX_TYPE].Key = DEVPKEY_Sensor_ProximityType; + InitPropVariantFromUInt32(PROXIMITY_TYPE::ProximityType_HumanProximity, + &(m_pEnumerationProperties->List[SENSOR_PROPERTY_PRX_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_ISWAKECAPABLE].Key = PKEY_Sensor_WakeCapable; + InitPropVariantFromBoolean(FALSE, + &(m_pEnumerationProperties->List[SENSOR_ISWAKECAPABLE].Value)); + + } + + // + // Supported Data-Fields + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(PRX_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_PROXIMITY, + Size, + &MemoryHandle, + (PVOID*)&m_pSupportedDataFields); + if (!NT_SUCCESS(Status) || m_pSupportedDataFields == nullptr) + { + TraceError("COMBO %!FUNC! PRX WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = PRX_DATA_COUNT; + + m_pSupportedDataFields->List[PRX_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[PRX_DATA_DETECT] = PKEY_SensorData_ProximityDetection; + m_pSupportedDataFields->List[PRX_DATA_DISTANCE] = PKEY_SensorData_ProximityDistanceMillimeters; + } + + // + // Data + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(PRX_DATA_COUNT); + FILETIME Time = {}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_PROXIMITY, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pData)); + if (!NT_SUCCESS(Status) || nullptr == m_pData) + { + TraceError("COMBO %!FUNC! PRX WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = PRX_DATA_COUNT; + + m_pData->List[PRX_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[PRX_DATA_TIMESTAMP].Value)); + + m_pData->List[PRX_DATA_DETECT].Key = PKEY_SensorData_ProximityDetection; + InitPropVariantFromBoolean(FALSE, &(m_pData->List[PRX_DATA_DETECT].Value)); + + m_pData->List[PRX_DATA_DISTANCE].Key = PKEY_SensorData_ProximityDistanceMillimeters; + InitPropVariantFromUInt32(FALSE, &(m_pData->List[PRX_DATA_DISTANCE].Value)); + + m_CachedData.Detected = FALSE; + m_CachedData.DistanceMillimeters = PrxDevice_Maximum_Millimeters; + + m_LastSample.Detected = FALSE; + m_LastSample.DistanceMillimeters = PrxDevice_Maximum_Millimeters; + } + + // + // Sensor Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_PROXIMITY, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pProperties) + { + TraceError("COMBO %!FUNC! PRX WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_COMMON_PROPERTY_COUNT; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(Prx_MinDataInterval_Ms, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Value)); + m_IntervalMs = Prx_MinDataInterval_Ms; + m_MinimumIntervalMs = Prx_MinDataInterval_Ms; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_Proximity, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Value)); + } + + // + // Data field properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_PROXIMITY, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pDataFieldProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pDataFieldProperties) + { + TraceError("COMBO %!FUNC! PRX WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); + m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; + + m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; + InitPropVariantFromUInt32(PrxDevice_Resolution_Millimeters, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromUInt32(PrxDevice_Minimum_Millimeters, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromUInt32(PrxDevice_Maximum_Millimeters, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + + // + // Set default threshold + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(PRX_THRESHOLD_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_PROXIMITY, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pThresholds)); + if (!NT_SUCCESS(Status) || nullptr == m_pThresholds) + { + TraceError("COMBO %!FUNC! PRX WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + + m_FirstSample = TRUE; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: GetData +// +// 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. +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +PrxDevice::GetData( + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {0}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // new sample? + if (m_FirstSample != FALSE) + { + Status = GetPerformanceTime(&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! PRX GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + // Compare the change of detection state, and only push the data back to + // clx. This is usually done in HW. + if (m_CachedData.Detected != m_LastSample.Detected) + { + DataReady = TRUE; + } + } + + if (DataReady != FALSE) + { + // update last sample + m_LastSample = m_CachedData; + + // push to clx + InitPropVariantFromBoolean(m_LastSample.Detected, &(m_pData->List[PRX_DATA_DETECT].Value)); + InitPropVariantFromUInt32(m_LastSample.DistanceMillimeters, &(m_pData->List[PRX_DATA_DISTANCE].Value)); + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[PRX_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! PRX Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +PrxDevice::UpdateCachedThreshold( + ) +{ + TraceInformation("COMBO %!FUNC! PRX do not have threshold!"); + + return STATUS_SUCCESS; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/SensorsComboDriver.ctl b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.ctl new file mode 100644 index 00000000..5b5dff98 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.ctl @@ -0,0 +1 @@ +3C773167,F26D,4F72,A1DE,95F1FD795840 SimpleDeviceOrientationSensorTraceGuid diff --git a/sensors/SensorsComboDriver/Driver/SensorsComboDriver.def b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.def new file mode 100644 index 00000000..5273e711 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.def @@ -0,0 +1,6 @@ +; SensorsComboDriver.def : Declares the module parameters. + +LIBRARY SensorsComboDriver + +EXPORTS + diff --git a/sensors/SensorsComboDriver/Driver/SensorsComboDriver.inx b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.inx Binary files differnew file mode 100644 index 00000000..50326f48 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.inx diff --git a/sensors/SensorsComboDriver/Driver/SensorsComboDriver.vcxproj b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.vcxproj new file mode 100644 index 00000000..15e5d0a5 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.vcxproj @@ -0,0 +1,200 @@ +<?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>{C3964BD1-B485-4236-8BB4-E2981B800AC1}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{5E23E5F0-A79D-451A-A6E3-AA8ECD5B1E10}</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="AlsClient.cpp; BarClient.cpp; Clients.cpp; device.cpp; driver.cpp; GeomagneticOrientationClient.cpp; GravityVectorClient.cpp; GyrClient.cpp; linearaccelerometerclient.cpp; MagClient.cpp; PrxClient.cpp; relativefusionclient.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppModuleName>SensorsComboDriver</WppModuleName> + <WppScanConfigurationData>sensorstrace.h</WppScanConfigurationData> + </ClCompile> + <Inf Include="SensorsComboDriver.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\SensorsComboDriver.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>SensorsComboDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>SensorsComboDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>SensorsComboDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>SensorsComboDriver</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>Sync</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>SensorsComboDriver.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>Sync</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>SensorsComboDriver.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>Sync</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>SensorsComboDriver.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>Sync</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>SensorsComboDriver.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/SensorsComboDriver/Driver/SensorsComboDriver.vcxproj.Filters b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.vcxproj.Filters new file mode 100644 index 00000000..7e7513b9 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/SensorsComboDriver.vcxproj.Filters @@ -0,0 +1,67 @@ +<?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>{657C491B-7C92-4AB8-B003-546E3A3A86FF}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{9D074C38-4627-4BCD-A647-8CEDAA88C3B0}</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>{F78FFA14-EFF9-47BC-83D9-680F26ED1E81}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{BC2DC265-BF39-4FD7-AF86-19C090D6C725}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="AlsClient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="BarClient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Clients.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="GeomagneticOrientationClient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="GravityVectorClient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="GyrClient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="linearaccelerometerclient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="MagClient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="PrxClient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="relativefusionclient.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="SensorsComboDriver.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <Inf Include="SensorsComboDriver.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/SensorsTrace.h b/sensors/SensorsComboDriver/Driver/SensorsTrace.h new file mode 100644 index 00000000..85a8b811 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/SensorsTrace.h @@ -0,0 +1,100 @@ +//Copyright (C) Microsoft Corporation, All Rights Reserved +// +//Abstract: +// +// Header file for the debug tracing related function defintions and macros. +// +//Environment: +// +// User mode + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +// Define the tracing flags. +// +// Tracing GUID - 3C773167-F26D-4F72-A1DE-95F1FD795840 + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + SimpleDeviceOrientationSensorTraceGuid, (3C773167,F26D,4F72,A1DE,95F1FD795840), \ + WPP_DEFINE_BIT(EntryExit) \ + WPP_DEFINE_BIT(DataFlow) \ + WPP_DEFINE_BIT(Verbose) \ + WPP_DEFINE_BIT(Information) \ + WPP_DEFINE_BIT(Warning) \ + WPP_DEFINE_BIT(Error) \ + WPP_DEFINE_BIT(Fatal) \ + WPP_DEFINE_BIT(DriverStatus) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) (WPP_LEVEL_ENABLED(flag) && WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +#define WPP_LEVEL_FLAGS_LOGGER(level,flags) WPP_LEVEL_LOGGER(flags) + +#define WPP_LEVEL_FLAGS_ENABLED(level, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= level) + +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// +// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); +// +// FUNC TraceFatal{LEVEL=TRACE_LEVEL_FATAL,FLAGS=Fatal}(MSG,...); +// FUNC TraceError{LEVEL=TRACE_LEVEL_ERROR,FLAGS=Error}(MSG,...); +// FUNC TraceWarning{LEVEL=TRACE_LEVEL_WARNING,FLAGS=Warning}(MSG,...); +// FUNC TraceInformation{LEVEL=TRACE_LEVEL_INFORMATION,FLAGS=Information}(MSG,...); +// FUNC TraceVerbose{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=Verbose}(MSG,...); +// FUNC TracePerformance{PERF=DUMMY,LEVEL=TRACE_LEVEL_PERF}(FLAGS,MSG,...); +// +// FUNC TraceData{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=DataFlow}(MSG,...); +// +// FUNC TraceDriverStatus{LEVEL=TRACE_LEVEL_INFORMATION,FLAGS=DriverStatus}(MSG,...); +// +// end_wpp + +// SENSOR ------------------------------------------------------------------------------------------------ + +// MACRO: SENSOR_FunctionEnter +// +// begin_wpp config +// USEPREFIX (SENSOR_FunctionEnter, "%!STDPREFIX! SENSOR %!FUNC! FunctionEnter"); +// FUNC SENSOR_FunctionEnter{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=EntryExit}(...); +// end_wpp + + +// MACRO: SENSOR_FunctionExit +// +// begin_wpp config +// USEPREFIX (SENSOR_FunctionExit, "%!STDPREFIX! SENSOR %!FUNC! FunctionExit: %!STATUS!", __status); +// FUNC SENSOR_FunctionExit{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=EntryExit}(SENSOREXIT); +// end_wpp +#define WPP_LEVEL_FLAGS_SENSOREXIT_ENABLED(LEVEL, FLAGS, status) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_SENSOREXIT_LOGGER(LEVEL, FLAGS, status) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_SENSOREXIT_PRE(LEVEL, FLAGS, status) { \ + NTSTATUS __status = status; +#define WPP_LEVEL_FLAGS_SENSOREXIT_POST(LEVEL, FLAGS, status) /*TraceMessage()*/; \ + } + + + +// WPP Recorder ------------------------------------------------------------------------------------------- +// +// The following two macros are required to enable WPP Recorder functionality for clients of the Sensor Class Extension +// +#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_FILTER(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_SENSOREXIT_ARGS(LEVEL, FLAGS, status) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) + + +#ifdef __cplusplus +} +#endif + + diff --git a/sensors/SensorsComboDriver/Driver/linearaccelerometerclient.cpp b/sensors/SensorsComboDriver/Driver/linearaccelerometerclient.cpp new file mode 100644 index 00000000..036c294f --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/linearaccelerometerclient.cpp @@ -0,0 +1,507 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of sensor specific functions. +// +// Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#include "Clients.h" + +#include "LinearAccelerometerClient.tmh" + +#define SENSORV2_POOL_TAG_LINEAR_ACCELEROMETER '2CaL' + +#define LinearAccelerometerDevice_Default_MinDataInterval (4) +#define LinearAccelerometerDevice_Default_Axis_Threshold (1.0f) +#define LinearAccelerometerDevice_Axis_Resolution (4.0f / 65536.0f) // in delta g +#define LinearAccelerometerDevice_Axis_Minimum (-2.0f) // in g +#define LinearAccelerometerDevice_Axis_Maximum (2.0f) // in g + +// Linear Accelerometer Unique ID +// {2BAAA1A7-6795-42A0-B830-82526CFD28D1} +DEFINE_GUID(GUID_LinearAccelerometerDevice_UniqueID, + 0x2baaa1a7, 0x6795, 0x42a0, 0xb8, 0x30, 0x82, 0x52, 0x6c, 0xfd, 0x28, 0xd1); + +// Sensor data +typedef enum +{ + LINEAR_ACCELEROMETER_DATA_X = 0, + LINEAR_ACCELEROMETER_DATA_Y, + LINEAR_ACCELEROMETER_DATA_Z, + LINEAR_ACCELEROMETER_DATA_TIMESTAMP, + LINEAR_ACCELEROMETER_DATA_SHAKE, + LINEAR_ACCELEROMETER_DATA_COUNT +} LINEAR_ACCELEROMETER_DATA_INDEX; + +//------------------------------------------------------------------------------ +// Function: Initialize +// +// This routine initializes the sensor to its default properties +// +// Arguments: +// Device: IN: WDFDEVICE object +// SensorInstance: IN: SENSOROBJECT for each sensor instance +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +LinearAccelerometerDevice::Initialize( + _In_ WDFDEVICE Device, + _In_ SENSOROBJECT SensorInstance + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Store device and instance + // + m_Device = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + + // + // Create Lock + // + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! LAC WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + // + // Create timer object for polling sensor samples + // + { + WDF_OBJECT_ATTRIBUTES TimerAttributes; + WDF_TIMER_CONFIG TimerConfig; + + WDF_TIMER_CONFIG_INIT(&TimerConfig, OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + TimerConfig.TolerableDelay = 0; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! LAC WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + } + + // + // Sensor Enumeration Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ENUMERATION_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_LINEAR_ACCELEROMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pEnumerationProperties); + if (!NT_SUCCESS(Status) || m_pEnumerationProperties == nullptr) + { + TraceError("COMBO %!FUNC! LAC WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); + m_pEnumerationProperties->Count = SENSOR_ENUMERATION_PROPERTIES_COUNT; + + m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_LinearAccelerometer, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Manufacturer name", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"Linear Accelerometer", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType; + // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration + InitPropVariantFromUInt32(static_cast<ULONG>(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_LinearAccelerometerDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; + InitPropVariantFromBoolean(FALSE, + &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); + } + + // + // Supported Data-Fields + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(LINEAR_ACCELEROMETER_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_LINEAR_ACCELEROMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pSupportedDataFields); + if (!NT_SUCCESS(Status) || m_pSupportedDataFields == nullptr) + { + TraceError("COMBO %!FUNC! LAC WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = LINEAR_ACCELEROMETER_DATA_COUNT; + + m_pSupportedDataFields->List[LINEAR_ACCELEROMETER_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[LINEAR_ACCELEROMETER_DATA_X] = PKEY_SensorData_AccelerationX_Gs; + m_pSupportedDataFields->List[LINEAR_ACCELEROMETER_DATA_Y] = PKEY_SensorData_AccelerationY_Gs; + m_pSupportedDataFields->List[LINEAR_ACCELEROMETER_DATA_Z] = PKEY_SensorData_AccelerationZ_Gs; + m_pSupportedDataFields->List[LINEAR_ACCELEROMETER_DATA_SHAKE] = PKEY_SensorData_Shake; + } + + // + // Data + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(LINEAR_ACCELEROMETER_DATA_COUNT); + FILETIME Time = {0}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_LINEAR_ACCELEROMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pData); + if (!NT_SUCCESS(Status) || m_pData == nullptr) + { + TraceError("COMBO %!FUNC! LAC WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = LINEAR_ACCELEROMETER_DATA_COUNT; + + m_pData->List[LINEAR_ACCELEROMETER_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_TIMESTAMP].Value)); + + m_pData->List[LINEAR_ACCELEROMETER_DATA_X].Key = PKEY_SensorData_AccelerationX_Gs; + InitPropVariantFromFloat(0.0, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_X].Value)); + + m_pData->List[LINEAR_ACCELEROMETER_DATA_Y].Key = PKEY_SensorData_AccelerationY_Gs; + InitPropVariantFromFloat(0.0, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_Y].Value)); + + m_pData->List[LINEAR_ACCELEROMETER_DATA_Z].Key = PKEY_SensorData_AccelerationZ_Gs; + InitPropVariantFromFloat(0.0, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_Z].Value)); + + m_pData->List[LINEAR_ACCELEROMETER_DATA_SHAKE].Key = PKEY_SensorData_Shake; + InitPropVariantFromBoolean(FALSE, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_SHAKE].Value)); + + m_CachedData.Axis.X = 0.0f; + m_CachedData.Axis.Y = 0.0f; + m_CachedData.Axis.Z = -1.0f; + m_CachedData.Shake = FALSE; + + m_LastSample.Axis.X = 0.0f; + m_LastSample.Axis.Y = 0.0f; + m_LastSample.Axis.Z = 0.0f; + m_LastSample.Shake = FALSE; + } + + // + // Sensor Properties + // + { + m_IntervalMs = LinearAccelerometerDevice_Default_MinDataInterval; + + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_LINEAR_ACCELEROMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pProperties); + if (!NT_SUCCESS(Status) || m_pProperties == nullptr) + { + TraceError("LAC %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_COMMON_PROPERTY_COUNT; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(LinearAccelerometerDevice_Default_MinDataInterval, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_LinearAccelerometer, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Value)); + } + + // + // Data field properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_LINEAR_ACCELEROMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pDataFieldProperties); + if (!NT_SUCCESS(Status) || m_pDataFieldProperties == nullptr) + { + TraceError("COMBO %!FUNC! LAC WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); + m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; + + m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; + InitPropVariantFromFloat(LinearAccelerometerDevice_Axis_Resolution, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromFloat(LinearAccelerometerDevice_Axis_Minimum, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromFloat(LinearAccelerometerDevice_Axis_Maximum, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + + // + // Set default threshold + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(LINEAR_ACCELEROMETER_DATA_COUNT - 2); // Timestamp and shake do not have thresholds + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_LINEAR_ACCELEROMETER, + Size, + &MemoryHandle, + (PVOID*)&m_pThresholds); + if (!NT_SUCCESS(Status) || m_pThresholds == nullptr) + { + TraceError("COMBO %!FUNC! LAC WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = LINEAR_ACCELEROMETER_DATA_COUNT - 2; + + m_pThresholds->List[LINEAR_ACCELEROMETER_DATA_X].Key = PKEY_SensorData_AccelerationX_Gs; + InitPropVariantFromFloat(LinearAccelerometerDevice_Default_Axis_Threshold, + &(m_pThresholds->List[LINEAR_ACCELEROMETER_DATA_X].Value)); + + m_pThresholds->List[LINEAR_ACCELEROMETER_DATA_Y].Key = PKEY_SensorData_AccelerationY_Gs; + InitPropVariantFromFloat(LinearAccelerometerDevice_Default_Axis_Threshold, + &(m_pThresholds->List[LINEAR_ACCELEROMETER_DATA_Y].Value)); + + m_pThresholds->List[LINEAR_ACCELEROMETER_DATA_Z].Key = PKEY_SensorData_AccelerationZ_Gs; + InitPropVariantFromFloat(LinearAccelerometerDevice_Default_Axis_Threshold, + &(m_pThresholds->List[LINEAR_ACCELEROMETER_DATA_Z].Value)); + + m_CachedThresholds.Axis.X = LinearAccelerometerDevice_Default_Axis_Threshold; + m_CachedThresholds.Axis.Y = LinearAccelerometerDevice_Default_Axis_Threshold; + m_CachedThresholds.Axis.Z = LinearAccelerometerDevice_Default_Axis_Threshold; + + m_FirstSample = TRUE; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: GetData +// +// 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. +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +LinearAccelerometerDevice::GetData( + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {0}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // new sample? + if (m_FirstSample != FALSE) + { + Status = GetPerformanceTime (&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! LAC GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + // Compare the change of data to threshold, and only push the data back to + // clx if the change exceeds threshold. This is usually done in HW. + if ( (abs(m_CachedData.Axis.X - m_LastSample.Axis.X) >= m_CachedThresholds.Axis.X) || + (abs(m_CachedData.Axis.Y - m_LastSample.Axis.Y) >= m_CachedThresholds.Axis.Y) || + (abs(m_CachedData.Axis.Z - m_LastSample.Axis.Z) >= m_CachedThresholds.Axis.Z)) + { + DataReady = TRUE; + } + } + + if (DataReady != FALSE) + { + // update last sample + m_LastSample.Axis.X = m_CachedData.Axis.X; + m_LastSample.Axis.Y = m_CachedData.Axis.Y; + m_LastSample.Axis.Z = m_CachedData.Axis.Z; + + m_LastSample.Shake = m_CachedData.Shake; + + // push to clx + InitPropVariantFromFloat(m_LastSample.Axis.X, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_X].Value)); + InitPropVariantFromFloat(m_LastSample.Axis.Y, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_Y].Value)); + InitPropVariantFromFloat(m_LastSample.Axis.Z, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_Z].Value)); + + InitPropVariantFromBoolean(m_LastSample.Shake, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_SHAKE].Value)); + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[LINEAR_ACCELEROMETER_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! LAC Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +LinearAccelerometerDevice::UpdateCachedThreshold( + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AccelerationX_Gs, + &m_CachedThresholds.Axis.X); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! LAC PropKeyFindKeyGetFloat for X failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AccelerationY_Gs, + &m_CachedThresholds.Axis.Y); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! LAC PropKeyFindKeyGetFloat for Y failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_AccelerationZ_Gs, + &m_CachedThresholds.Axis.Z); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! LAC PropKeyFindKeyGetFloat for Z failed! %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/product.pbxproj b/sensors/SensorsComboDriver/Driver/product.pbxproj new file mode 100644 index 00000000..c127ac09 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/product.pbxproj @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="ProductBuild" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup Label="PropertySheets"> + <PlatformToolset>v110</PlatformToolset> + <ConfigurationType>Utility</ConfigurationType> + </PropertyGroup> + <PropertyGroup> + <EnableDriverInfs>true</EnableDriverInfs> + <GenerateAndPackageAllDriverManifests>true</GenerateAndPackageAllDriverManifests> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" Label="FirstImport" /> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ItemGroup> + <DriverInf Include="combodriver.inf"> + <HasResourceManifest>true</HasResourceManifest> + </DriverInf> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/relativefusionclient.cpp b/sensors/SensorsComboDriver/Driver/relativefusionclient.cpp new file mode 100644 index 00000000..872099a6 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/relativefusionclient.cpp @@ -0,0 +1,515 @@ +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of sensor specific functions. +// +// Environment: +// +// Windows User-Mode Driver Framework (WUDF) + +#include "Clients.h" + +#include "RelativeFusionClient.tmh" + +#define SENSORV2_POOL_TAG_RELATIVE_FUSION '2FsR' + +#define RelativeFusion_Initial_MinDataInterval_Ms (10) // 100Hz + +#define RelativeFusion_Quarternion_Maximum (1.0f) +#define RelativeFusion_Quarternion_Minimum (-1.0f) +#define RelativeFusion_Quarternion_Resolution ((RelativeFusion_Quarternion_Maximum-RelativeFusion_Quarternion_Minimum)/65536) + +// Relative Fusion Sensor Unique ID +// {0D324DDF-05AD-4285-875A-B2BCF565D2BA} +DEFINE_GUID(GUID_RelativeFusionDevice_UniqueID, + 0xd324ddf, 0x5ad, 0x4285, 0x87, 0x5a, 0xb2, 0xbc, 0xf5, 0x65, 0xd2, 0xba); + + +// Sensor data +typedef enum +{ + RELATIVE_FUSION_DATA_TIMESTAMP = 0, + RELATIVE_FUSION_DATA_QUATERNION_W, + RELATIVE_FUSION_DATA_QUATERNION_X, + RELATIVE_FUSION_DATA_QUATERNION_Y, + RELATIVE_FUSION_DATA_QUATERNION_Z, + RELATIVE_FUSION_DATA_COUNT +} RELATIVE_FUSION_DATA_INDEX; + +// Sensor thresholds +typedef enum +{ + RELATIVE_FUSION_THRESHOLD_QUATERNION_W = 0, + RELATIVE_FUSION_THRESHOLD_QUATERNION_X, + RELATIVE_FUSION_THRESHOLD_QUATERNION_Y, + RELATIVE_FUSION_THRESHOLD_QUATERNION_Z, + RELATIVE_FUSION_THRESHOLD_COUNT +} RELATIVE_FUSION_THRESHOLD_INDEX; + + + +//------------------------------------------------------------------------------ +// Function: Initialize +// +// This routine initializes the sensor to its default properties +// +// Arguments: +// Device: IN: WDFDEVICE object +// SensorInstance: IN: SENSOROBJECT for each sensor instance +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +RelativeFusionDevice::Initialize( + _In_ WDFDEVICE Device, + _In_ SENSOROBJECT SensorInstance + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // + // Store device and instance + // + m_Device = Device; + m_SensorInstance = SensorInstance; + m_Started = FALSE; + + // + // Create Lock + // + Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! Relative Fusion WdfWaitLockCreate failed %!STATUS!", Status); + goto Exit; + } + + // + // Create timer object for polling sensor samples + // + { + WDF_OBJECT_ATTRIBUTES TimerAttributes; + WDF_TIMER_CONFIG TimerConfig; + + WDF_TIMER_CONFIG_INIT(&TimerConfig, OnTimerExpire); + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = SensorInstance; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice WdfTimerCreate failed %!STATUS!", Status); + goto Exit; + } + } + + // + // Sensor Enumeration Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ENUMERATION_PROPERTIES_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_RELATIVE_FUSION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pEnumerationProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pEnumerationProperties) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); + m_pEnumerationProperties->Count = SENSOR_ENUMERATION_PROPERTIES_COUNT; + + m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_RelativeOrientation, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Manufacturer name", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"Relative Fusion Device", + &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); + + m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Key = DEVPKEY_Sensor_ConnectionType; + // The DEVPKEY_Sensor_ConnectionType values match the SensorConnectionType enumeration + InitPropVariantFromUInt32(static_cast<ULONG>(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_RelativeFusionDevice_UniqueID, + &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); + + m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; + InitPropVariantFromBoolean(FALSE, + &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); + } + + // + // Supported Data-Fields + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(RELATIVE_FUSION_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_RELATIVE_FUSION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pSupportedDataFields)); + if (!NT_SUCCESS(Status) || nullptr == m_pSupportedDataFields) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = RELATIVE_FUSION_DATA_COUNT; + + m_pSupportedDataFields->List[RELATIVE_FUSION_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[RELATIVE_FUSION_DATA_QUATERNION_W] = PKEY_SensorData_QuaternionW; + m_pSupportedDataFields->List[RELATIVE_FUSION_DATA_QUATERNION_X] = PKEY_SensorData_QuaternionX; + m_pSupportedDataFields->List[RELATIVE_FUSION_DATA_QUATERNION_Y] = PKEY_SensorData_QuaternionY; + m_pSupportedDataFields->List[RELATIVE_FUSION_DATA_QUATERNION_Z] = PKEY_SensorData_QuaternionZ; + } + + // + // Data + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(RELATIVE_FUSION_DATA_COUNT); + FILETIME Time = {0}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_RELATIVE_FUSION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pData)); + if (!NT_SUCCESS(Status) || nullptr == m_pData) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = RELATIVE_FUSION_DATA_COUNT; + + m_pData->List[RELATIVE_FUSION_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[RELATIVE_FUSION_DATA_TIMESTAMP].Value)); + + m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_W].Key = PKEY_SensorData_QuaternionW; + InitPropVariantFromFloat(0.0, &(m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_W].Value)); + + m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_X].Key = PKEY_SensorData_QuaternionX; + InitPropVariantFromFloat(0.0, &(m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_X].Value)); + + m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_Y].Key = PKEY_SensorData_QuaternionY; + InitPropVariantFromFloat(0.0, &(m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_Y].Value)); + + m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_Z].Key = PKEY_SensorData_QuaternionZ; + InitPropVariantFromFloat(0.0, &(m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_Z].Value)); + + ZeroMemory(&m_LastSample, sizeof(m_LastSample)); + ZeroMemory(&m_CachedData, sizeof(m_CachedData)); + m_CachedData.W = 1.0f; // This is the initial position + } + + // + // Sensor Properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_RELATIVE_FUSION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pProperties) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); + m_pProperties->Count = SENSOR_COMMON_PROPERTY_COUNT; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Key = PKEY_Sensor_State; + InitPropVariantFromUInt32(SensorState_Initializing, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_STATE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; + InitPropVariantFromUInt32(RelativeFusion_Initial_MinDataInterval_Ms, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MIN_INTERVAL].Value)); + m_IntervalMs = RelativeFusion_Initial_MinDataInterval_Ms; + m_MinimumIntervalMs = RelativeFusion_Initial_MinDataInterval_Ms; + + m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; + InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_MAX_DATAFIELDSIZE].Value)); + + m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Key = PKEY_Sensor_Type; + InitPropVariantFromCLSID(GUID_SensorType_RelativeOrientation, + &(m_pProperties->List[SENSOR_COMMON_PROPERTY_TYPE].Value)); + } + + // + // Data filed properties + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_RELATIVE_FUSION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pDataFieldProperties)); + if (!NT_SUCCESS(Status) || nullptr == m_pDataFieldProperties) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); + m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; + + m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; + InitPropVariantFromFloat(RelativeFusion_Quarternion_Resolution, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromFloat(RelativeFusion_Quarternion_Minimum, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromFloat(RelativeFusion_Quarternion_Maximum, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + + // + // Set default threshold + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(RELATIVE_FUSION_THRESHOLD_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + SENSORV2_POOL_TAG_RELATIVE_FUSION, + Size, + &MemoryHandle, + reinterpret_cast<PVOID*>(&m_pThresholds)); + if (!NT_SUCCESS(Status) || nullptr == m_pThresholds) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = RELATIVE_FUSION_THRESHOLD_COUNT; + + m_pThresholds->List[RELATIVE_FUSION_THRESHOLD_QUATERNION_W].Key = PKEY_SensorData_QuaternionW; + InitPropVariantFromFloat(0.0f, &(m_pThresholds->List[RELATIVE_FUSION_THRESHOLD_QUATERNION_W].Value)); + + m_pThresholds->List[RELATIVE_FUSION_THRESHOLD_QUATERNION_X].Key = PKEY_SensorData_QuaternionX; + InitPropVariantFromFloat(0.0f, &(m_pThresholds->List[RELATIVE_FUSION_THRESHOLD_QUATERNION_X].Value)); + + m_pThresholds->List[RELATIVE_FUSION_THRESHOLD_QUATERNION_Y].Key = PKEY_SensorData_QuaternionY; + InitPropVariantFromFloat(0.0f, &(m_pThresholds->List[RELATIVE_FUSION_THRESHOLD_QUATERNION_Y].Value)); + + m_pThresholds->List[RELATIVE_FUSION_THRESHOLD_QUATERNION_Z].Key = PKEY_SensorData_QuaternionZ; + InitPropVariantFromFloat(0.0f, &(m_pThresholds->List[RELATIVE_FUSION_THRESHOLD_QUATERNION_Z].Value)); + + ZeroMemory(&m_CachedThresholds, sizeof(m_CachedThresholds)); + m_FirstSample = TRUE; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: GetData +// +// 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. +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +RelativeFusionDevice::GetData( + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {0}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + // new sample? + if (FALSE != m_FirstSample) + { + Status = GetPerformanceTime (&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! RelativeFusionDevice GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + // Compare the change of data to threshold, and only push the data back to + // clx if the change exceeds threshold. This is usually done in HW. + if ((abs(m_CachedData.W - m_LastSample.W) >= m_CachedThresholds.W) || + (abs(m_CachedData.X - m_LastSample.X) >= m_CachedThresholds.X) || + (abs(m_CachedData.Y - m_LastSample.Y) >= m_CachedThresholds.Y) || + (abs(m_CachedData.Z - m_LastSample.Z) >= m_CachedThresholds.Z)) + { + DataReady = TRUE; + } + } + + if (FALSE != DataReady) + { + // update last sample + m_LastSample = m_CachedData; + + // push to clx + InitPropVariantFromFloat(m_LastSample.W, &(m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_W].Value)); + InitPropVariantFromFloat(m_LastSample.X, &(m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_X].Value)); + InitPropVariantFromFloat(m_LastSample.Y, &(m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_Y].Value)); + InitPropVariantFromFloat(m_LastSample.Z, &(m_pData->List[RELATIVE_FUSION_DATA_QUATERNION_Z].Value)); + + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[RELATIVE_FUSION_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! RelativeFusionDevice Data did NOT meet the threshold"); + } + + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +RelativeFusionDevice::UpdateCachedThreshold( + ) +{ + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + SENSOR_FunctionEnter(); + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_QuaternionW, + &m_CachedThresholds.W); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice PropKeyFindKeyGetFloat for W failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_QuaternionX, + &m_CachedThresholds.X); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice PropKeyFindKeyGetFloat for X failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_QuaternionY, + &m_CachedThresholds.Y); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice PropKeyFindKeyGetFloat for Y failed! %!STATUS!", Status); + goto Exit; + } + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_QuaternionZ, + &m_CachedThresholds.Z); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! RelativeFusionDevice PropKeyFindKeyGetFloat for Z failed! %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +}
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Driver/sources b/sensors/SensorsComboDriver/Driver/sources new file mode 100644 index 00000000..cdee3b36 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/sources @@ -0,0 +1,56 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. + +TARGETNAME = SensorsComboDriver +TARGETTYPE = DYNLINK +TARGET_DESTINATION = NTTEST\drivers\Sensors\V2 + +DLLDEF = SensorsComboDriver.def + +MINIMUM_NT_TARGET_VERSION = $(_NT_TARGET_VERSION_WINV64) +DDK_TARGET_PLATFORM = Universal + +USE_UNICRT = 1 +USE_MSVCRT = 1 + +UMDF_VERSION_MAJOR = 2 + +C_DEFINES = $(C_DEFINES)\ + /D_UNICODE \ + /DUNICODE \ + /DWPP_MACRO_USE_KM_VERSION_FOR_UM \ + +MSC_WARNING_LEVEL = /W4 /WX + +INCLUDES = $(INCLUDES); \ + $(SDK_INC_PATH); \ +### Point to the public version of Windows.Devices.Sensors.h + $(SDK_INC_PATH)\ABI; \ + $(DDK_INC_PATH)\sensors\1.1; \ + $(SDK_INC_PATH)\sensors\1.1; \ + +TARGETLIBS = $(TARGETLIBS) \ + $(ONECORE_SDK_LIB_VPATH)\onecoreuap.lib \ + $(SDK_LIB_PATH)\propsys.lib \ + $(MINCORE_SDK_LIB_VPATH)\api-ms-win-mm-time-l1.lib \ + $(SDK_LIB_PATH)\sensorsutils.lib \ + $(SDK_LIB_PATH)\sensors\$(SENSORS_VER_PATH)\sensorscxstub.lib \ + +SOURCES = \ + alsclient.cpp \ + barclient.cpp \ + clients.cpp \ + device.cpp \ + driver.cpp \ + geomagneticorientationclient.cpp \ + gravityvectorclient.cpp \ + gyrclient.cpp \ + linearaccelerometerclient.cpp \ + magclient.cpp \ + prxclient.cpp \ + relativefusionclient.cpp \ + +RUN_WPP = $(SOURCES) -dll \ + -p:SensorsComboDriver \ + -scan:sensorstrace.h + +GENERIC_INFS = SensorsComboDriver.inx diff --git a/sensors/SensorsComboDriver/Driver/sources.dep b/sensors/SensorsComboDriver/Driver/sources.dep new file mode 100644 index 00000000..d8383c18 --- /dev/null +++ b/sensors/SensorsComboDriver/Driver/sources.dep @@ -0,0 +1,3 @@ +PUBLIC_PASS0_CONSUMES= \ + onecore\drivers\mobilepc\sensors\drivers\sensorsv2\inc|PASS0 \ + diff --git a/sensors/SensorsComboDriver/Metadata/SensorsComboDriver-gallery.xml b/sensors/SensorsComboDriver/Metadata/SensorsComboDriver-gallery.xml new file mode 100644 index 00000000..67db4cb6 --- /dev/null +++ b/sensors/SensorsComboDriver/Metadata/SensorsComboDriver-gallery.xml @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?xml-stylesheet type="text/xsl" href="../../buildx/script2/preview.xslt"?> +<gallery_sample xmlns="http://microsoft.com/wdcml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://microsoft.com/wdcml ../../buildx/schema/xsd/wdcml.xsd"> + <metadata id="gallery_samples.107a_gallery" type="gallery_sample" msdnID="7cba6311-f0db-4c3d-8f1f-25de8648b353"> + <title>Sensors Combo Driver</title> + <!-- Add a devlang for each programming language in all versions of the sample. --> + <devlang value="cpp" /> + <!-- Do not change tech value --> + <tech value="gallery_samples" /> + <index /> + <sample_langs> + <!-- Describes the languages to which the sample code itself has been localized. --> + <sample_lang xml:lang="en-us" /> + </sample_langs> + </metadata> + <content> + <desc> + <p><abstract>The sensors combo driver sensor sample shows how to write UMDF v2 drivers to control various types of virtual sensors such as Ambient Light, Barometer, Gyroscope, Magnetometer, Geomagnetic, Gravity Vector, Proximity, Linear Accelerometer and Relative Fusion.</abstract></p> + </desc> + <outline /> + <license_info> + <default_license /> + </license_info> + <programming_models> + <programming_model value="win32" /> + </programming_models> + <application_frameworks> + </application_frameworks> + <!-- For Driver Samples Only --> + <driver_models> + <!-- possible values: kmdf, umdf, wdm, ndis, wddm --> + <driver_model value="UMDF" /> + </driver_models> + <driver_techs> + <driver_tech value="Windows Driver" /> + </driver_techs> + <related_techs> + </related_techs> + <os_requirements> + <min_os> + <client name="winblue"/> + <server name="wbluesrv"/> + </min_os> + </os_requirements> + <required_sdks> + <min_sdk> + <tla rid="windows_driver_kit_8" /> + </min_sdk> + </required_sdks> + <supported_ides> + <supported_ide> + <tla rid="tla_visualstu2012" /> + </supported_ide> + </supported_ides> + <build_info> + <authored_instructions> + <section> + <!-- Include any special instructions for compiling your sample --> + <sectioncontents> + </sectioncontents> + </section> + </authored_instructions> + </build_info> + <run_info> + <authored_instructions> + <section> + <sectioncontents> + <p>To install the sample driver, follow these steps:</p> + <proch> + <item>Ensure that the driver builds without errors.</item> + <item>Copy the DLL and INF files to a separate folder.</item> + <item>Enter the command "<inline_code devlang="cmd">devcon.exe install SensorsComboDriver.inf ACPI\<HWID></inline_code>" to install the driver on an existing device node. You can find the devcon.exe program in the tools\devcon folder where you installed the WDK.</item> + </proch> + </sectioncontents> + </section> + <section> + <title>File manifest</title> + <sectioncontents> + <p>The following source files are in the src\Sensors\SensorsComboDriver folder and are used to build the SensorsComboDriver.dll and SensorsComboDriver.inf files.</p> + <table> + <tr> + <th>File</th> + <th>Description</th> + </tr> + <tr> + <td> + <p>device.h, device.cpp</p> + </td> + <td> + <p>Implements the driver's WDF PnP event callbacks and helper methods</p> + </td> + </tr> + <tr> + <td> + <p>Clients.cpp</p> + </td> + <td> + <p>Implements the driver's callback functions from the class extension to the various sensors inside the combo driver.</p> + </td> + </tr> + <tr> + <td> + <p>driver.h, driver.cpp</p> + </td> + <td> + <p>WDF driver entry event callbacks and helper methods</p> + </td> + </tr> + <tr> + <td> + <p>makefile.inc</p> + </td> + <td> + <p>Defines custom build actions. Includes the conversion of the .INX file into a .INF file.</p> + </td> + </tr> + <tr> + <td> + <p>SensorsTrace.h</p> + </td> + <td> + <p>Implementation of the sensor traces files.</p> + </td> + </tr> + <tr> + <td> + <p>SensorsComboDriver.ctl</p> + </td> + <td> + <p>Declaration of driver's tracing GUID</p> + </td> + </tr> + <tr> + <td> + <p>SensorsComboDriver.inx</p> + </td> + <td> + <p>Describes the installation of the driver. The build process converts this into a .INF.</p> + </td> + </tr> + <tr> + <td> + <p>Trace.h</p> + </td> + <td> + <p>Sets up WPP tracing.</p> + </td> + </tr> + </table> + </sectioncontents> + </section> + </authored_instructions> + </run_info> + </content> + <!-- List the component compcentral path --> + <feature_teams> + <feature_team_info comp_central_path="CORE-OS Core\SiGMa-Silicon, Graphics and Media\SiPlat - Silicon Platform\Sensors" dev_owner="wensh" writer_owner="sensorsdev" /> + </feature_teams> + <workflow_control_host /> +</gallery_sample> diff --git a/sensors/SensorsComboDriver/Metadata/SensorsComboDriver.kml b/sensors/SensorsComboDriver/Metadata/SensorsComboDriver.kml new file mode 100644 index 00000000..517e6bbd --- /dev/null +++ b/sensors/SensorsComboDriver/Metadata/SensorsComboDriver.kml @@ -0,0 +1,129 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes'?> +<Content xmlns="http://microsoft.com/schemas/Windows/Kits/Manifest"> + <ContentGroup + BuildArchitecture="x86" + BuildType="fre" + Destination="Sensors\SensorsComboDriver" + Source="..\Driver" + > + <FeatureReference Name="WDK Samples"/> + <TextFile Name="Clients.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="Clients.h"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="SensorsComboDriver.inx"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="SensorsComboDriver.def"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="device.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="driver.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="Driver.h"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="AlsClient.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="BarClient.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="GeomagneticOrientationClient.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="GravityVectorClient.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="GyrClient.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="linearaccelerometerclient.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="MagClient.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="PrxClient.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="relativefusionclient.cpp"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="SensorsTrace.h"> + <HSplit + Operation="Split" + Tag="DDKSPLIT" + /> + </TextFile> + <TextFile Name="SensorsComboDriver.vcxproj"/> + <TextFile Name="SensorsComboDriver.vcxproj.Filters"/> + </ContentGroup> + <!-- Gallery.xml - . - Sensors\SensorsComboDriver --> + <ContentGroup + BuildArchitecture="x86" + BuildType="fre" + Destination="Sensors\SensorsComboDriver" + Source="." + > + <FeatureReference Name="WDK Samples"/> + <TextFile + Name="SensorsComboDriver-Gallery.xml" + Rename="Gallery.xml" + /> + <TextFile Name="SensorsComboDriver.sln"/> + </ContentGroup> +</Content> diff --git a/sensors/SensorsComboDriver/Metadata/SensorsComboDriver.sln b/sensors/SensorsComboDriver/Metadata/SensorsComboDriver.sln new file mode 100644 index 00000000..e6f4e500 --- /dev/null +++ b/sensors/SensorsComboDriver/Metadata/SensorsComboDriver.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}") = "SensorsComboDriver", "SensorsComboDriver.vcxproj", "{C3964BD1-B485-4236-8BB4-E2981B800AC1}" +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 + {C3964BD1-B485-4236-8BB4-E2981B800AC1}.Debug|Win32.ActiveCfg = Debug|Win32 + {C3964BD1-B485-4236-8BB4-E2981B800AC1}.Debug|Win32.Build.0 = Debug|Win32 + {C3964BD1-B485-4236-8BB4-E2981B800AC1}.Release|Win32.ActiveCfg = Release|Win32 + {C3964BD1-B485-4236-8BB4-E2981B800AC1}.Release|Win32.Build.0 = Release|Win32 + {C3964BD1-B485-4236-8BB4-E2981B800AC1}.Debug|x64.ActiveCfg = Debug|x64 + {C3964BD1-B485-4236-8BB4-E2981B800AC1}.Debug|x64.Build.0 = Debug|x64 + {C3964BD1-B485-4236-8BB4-E2981B800AC1}.Release|x64.ActiveCfg = Release|x64 + {C3964BD1-B485-4236-8BB4-E2981B800AC1}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/sensors/SensorsComboDriver/Metadata/product.pbxproj b/sensors/SensorsComboDriver/Metadata/product.pbxproj new file mode 100644 index 00000000..fb8943d8 --- /dev/null +++ b/sensors/SensorsComboDriver/Metadata/product.pbxproj @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="ProductBuild" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup Label="PropertySheets"> + <PlatformToolset>v110</PlatformToolset> + <ConfigurationType>Utility</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" Label="FirstImport" /> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/Metadata/sources b/sensors/SensorsComboDriver/Metadata/sources new file mode 100644 index 00000000..4f324037 --- /dev/null +++ b/sensors/SensorsComboDriver/Metadata/sources @@ -0,0 +1,4 @@ +TARGETTYPE = NOTARGET + +SOURCES=\ + SensorsComboDriver.kml \
\ No newline at end of file diff --git a/sensors/SensorsComboDriver/dirs b/sensors/SensorsComboDriver/dirs new file mode 100644 index 00000000..7f4c72f7 --- /dev/null +++ b/sensors/SensorsComboDriver/dirs @@ -0,0 +1,4 @@ +DIRS = \ + Driver \ + Cat \ + Metadata \
\ No newline at end of file |
