diff --git a/FrameworkSensors/Clients.h b/FrameworkSensors/Clients.h index fcb596d..e3abed9 100644 --- a/FrameworkSensors/Clients.h +++ b/FrameworkSensors/Clients.h @@ -261,3 +261,27 @@ typedef class _SimpleDeviceOrientationDevice : public _ComboDevice NTSTATUS UpdateCachedThreshold(); } SimpleDeviceOrientationDevice, *PSimpleDeviceOrientationDevice; + + + +// +// Hinge Angle ---------------------------------------------------------------- +// +typedef class _HingeAngleDevice : public _ComboDevice +{ +private: + typedef struct _HingeAngleSample + { + FLOAT Angle; + } HingeAngleSample; + + HingeAngleSample m_CachedThresholds; + HingeAngleSample m_CachedData; + HingeAngleSample m_LastSample; + +public: + NTSTATUS Initialize(_In_ WDFDEVICE Device, _In_ SENSOROBJECT SensorObj); + NTSTATUS GetData(_In_ HANDLE Device); + NTSTATUS UpdateCachedThreshold(); + +} HingeAngleDevice, *PHingeAngleDevice; diff --git a/FrameworkSensors/Device.cpp b/FrameworkSensors/Device.cpp index 86928a8..7db525c 100644 --- a/FrameworkSensors/Device.cpp +++ b/FrameworkSensors/Device.cpp @@ -21,49 +21,31 @@ #include "Device.tmh" -#define ENABLE_ALS_SENSOR 0 -#define ENABLE_ORIENTATION_SENSOR 0 -#define ENABLE_ACCEL_SENSOR 1 - //--------------------------------------- -// Declare and map devices below +// Dynamic sensor detection //--------------------------------------- -enum Device -{ -#if ENABLE_ALS_SENSOR - Device_Als, -#endif -#if ENABLE_ORIENTATION_SENSOR - Device_SimpleDeviceOrientation, -#endif -#if ENABLE_ACCEL_SENSOR - Device_Accelerometer, -#endif - // Keep this last - Device_Count -}; - -static const ULONG SensorInstanceCount = Device_Count; -static SENSOROBJECT SensorInstancesBuffer[SensorInstanceCount]; // Global buffer to avoid allocate and free +#define MAX_SENSOR_COUNT 4 + +typedef enum { + SENSOR_KIND_ACCELEROMETER, + SENSOR_KIND_HINGEANGLE, + SENSOR_KIND_ALS, +} SensorKind; + +static ULONG SensorInstanceCount = 0; +static SENSOROBJECT SensorInstancesBuffer[MAX_SENSOR_COUNT]; + +static size_t SensorSizes[MAX_SENSOR_COUNT]; +static SensorKind SensorKinds[MAX_SENSOR_COUNT]; inline size_t GetDeviceSizeAtIndex( _In_ ULONG Index) { - size_t result = 0; - switch (static_cast(Index)) + if (Index < SensorInstanceCount) { -#if ENABLE_ALS_SENSOR - case Device_Als: result = sizeof(AlsDevice); break; -#endif -#if ENABLE_ORIENTATION_SENSOR - case Device_SimpleDeviceOrientation:result = sizeof(SimpleDeviceOrientationDevice); break; -#endif -#if ENABLE_ACCEL_SENSOR - case Device_Accelerometer: result = sizeof(AccelerometerDevice); break; -#endif - default: break; // invalid + return SensorSizes[Index]; } - return result; + return 0; } void AllocateDeviceAtIndex( @@ -71,19 +53,17 @@ void AllocateDeviceAtIndex( _Inout_ PComboDevice* ppDevice ) { - switch (static_cast(Index)) + if (Index >= SensorInstanceCount) + { + return; + } + + switch (SensorKinds[Index]) { -#if ENABLE_ALS_SENSOR - case Device_Als: *ppDevice = new(*ppDevice) AlsDevice; break; -#endif -#if ENABLE_ORIENTATIONACCEL_SENSOR - case Device_SimpleDeviceOrientation:*ppDevice = new(*ppDevice) SimpleDeviceOrientationDevice; break; -#endif -#if ENABLE_ACCEL_SENSOR - case Device_Accelerometer: *ppDevice = new(*ppDevice) AccelerometerDevice; break; -#endif - - default: break; // invalid (let driver fail) + case SENSOR_KIND_ACCELEROMETER: *ppDevice = new(*ppDevice) AccelerometerDevice; break; + case SENSOR_KIND_HINGEANGLE: *ppDevice = new(*ppDevice) HingeAngleDevice; break; + case SENSOR_KIND_ALS: *ppDevice = new(*ppDevice) AlsDevice; break; + default: break; } } @@ -225,6 +205,86 @@ OnPrepareHardware( SENSOR_FunctionEnter(); + // + // Dynamic sensor detection + // + SensorInstanceCount = 0; + + // Detect accelerometer + hinge angle via motion sensor presence + { + UINT8 acc_status = 0; + CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_STATUS, &acc_status); + if (acc_status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT) + { + UINT8 base = 0, lid = 0; + if (NT_SUCCESS(CrosEcGetAccelIndeces(Handle, &base, &lid))) + { + TraceInformation("COMBO %!FUNC! Detected accelerometer (base=%d, lid=%d)", base, lid); + SensorSizes[SensorInstanceCount] = sizeof(AccelerometerDevice); + SensorKinds[SensorInstanceCount] = SENSOR_KIND_ACCELEROMETER; + SensorInstanceCount++; + + TraceInformation("COMBO %!FUNC! Detected hinge angle (base+lid accels present)"); + SensorSizes[SensorInstanceCount] = sizeof(HingeAngleDevice); + SensorKinds[SensorInstanceCount] = SENSOR_KIND_HINGEANGLE; + SensorInstanceCount++; + } + } + } + + // Detect ALS via motion sensor enumeration, then fallback to memmap + { + BOOLEAN alsFound = FALSE; + UINT8 sensorCount = CrosEcGetMotionSensorCount(Handle); + for (UINT8 idx = 0; idx < sensorCount && !alsFound; idx++) + { + EC_REQUEST_MOTION_SENSE_INFO infoReq{}; + EC_RESPONSE_MOTION_SENSE_INFO infoRes{}; + + infoReq.Cmd = 1; + infoReq.SensorNum = idx; + if (0 != CrosEcSendCommand( + Handle, + EC_CMD_MOTION_SENSE_CMD, + 1, + &infoReq, + sizeof(infoReq), + &infoRes, + sizeof(infoRes))) + { + if (infoRes.SensorType == MOTIONSENSE_TYPE_LIGHT || + infoRes.SensorType == MOTIONSENSE_TYPE_LIGHT_RGB) + { + TraceInformation("COMBO %!FUNC! Detected ALS via motion sensor index %d", idx); + alsFound = TRUE; + } + } + } + + // Fallback: check EC_MEMMAP_ALS for non-zero value + if (!alsFound) + { + UINT8 alsVal[2] = {0}; + CrosEcReadMemU8(Handle, EC_MEMMAP_ALS + 0, &alsVal[0]); + CrosEcReadMemU8(Handle, EC_MEMMAP_ALS + 1, &alsVal[1]); + UINT16 alsReading = alsVal[0] + (alsVal[1] << 8); + if (alsReading != 0) + { + TraceInformation("COMBO %!FUNC! Detected ALS via memmap (reading=%d)", alsReading); + alsFound = TRUE; + } + } + + if (alsFound && SensorInstanceCount < MAX_SENSOR_COUNT) + { + SensorSizes[SensorInstanceCount] = sizeof(AlsDevice); + SensorKinds[SensorInstanceCount] = SENSOR_KIND_ALS; + SensorInstanceCount++; + } + } + + TraceInformation("COMBO %!FUNC! Detected %d sensor(s) total", SensorInstanceCount); + for (ULONG Count = 0; Count < SensorInstanceCount; Count++) { PComboDevice pDevice = nullptr; diff --git a/FrameworkSensors/EcCommunication.h b/FrameworkSensors/EcCommunication.h index 67a4806..3f1bcbd 100644 --- a/FrameworkSensors/EcCommunication.h +++ b/FrameworkSensors/EcCommunication.h @@ -120,4 +120,9 @@ int CrosEcReadMemU8(HANDLE Handle, unsigned int offset, UINT8* dest); #ifdef __cplusplus } + +// Motion sensor helpers (defined in AccelerometerClient.cpp) +UINT8 CrosEcGetMotionSensorCount(HANDLE Handle); +NTSTATUS CrosEcGetAccelIndeces(HANDLE Handle, UINT8 *BaseSensor, UINT8 *LidSensor); + #endif diff --git a/FrameworkSensors/FrameworkSensors.vcxproj b/FrameworkSensors/FrameworkSensors.vcxproj index 5963940..94f196a 100644 --- a/FrameworkSensors/FrameworkSensors.vcxproj +++ b/FrameworkSensors/FrameworkSensors.vcxproj @@ -80,7 +80,7 @@ - + true true FrameworkSensors diff --git a/FrameworkSensors/HingeAngleClient.cpp b/FrameworkSensors/HingeAngleClient.cpp new file mode 100644 index 0000000..6d6a3f4 --- /dev/null +++ b/FrameworkSensors/HingeAngleClient.cpp @@ -0,0 +1,465 @@ +// SPDX-License-Identifier: MS-PL +// +// Copyright (C) Microsoft Corporation, All Rights Reserved. +// Copyright (C) Framework Computer Inc, All Rights Reserved. +// +// Abstract: +// +// This module contains the implementation of the hinge angle sensor client. +// +// Environment: +// +// Windows User-Mode Driver Framework (UMDF) + +#include "Clients.h" +#include "EcCommunication.h" + +#include "HingeAngleClient.tmh" + +#define FWK_SENSORS_POOL_TAG_HINGEANGLE 'hgAF' + +#define HingeAngleDevice_Default_MinDataInterval (100) +#define HingeAngleDevice_Default_Threshold (2.0f) +#define HingeAngleDevice_Resolution (1.0f) +#define HingeAngleDevice_Minimum (0.0f) +#define HingeAngleDevice_Maximum (360.0f) + +// Hinge Angle Sensor Unique ID +// {8412CCAB-F55E-4E8C-B3A0-7A5C2D3C8E41} +DEFINE_GUID(GUID_HingeAngleDevice_UniqueID, + 0x8412ccab, 0xf55e, 0x4e8c, 0xb3, 0xa0, 0x7a, 0x5c, 0x2d, 0x3c, 0x8e, 0x41); + +// Sensor data +typedef enum +{ + HINGEANGLE_DATA_TIMESTAMP = 0, + HINGEANGLE_DATA_ANGLE, + HINGEANGLE_DATA_COUNT +} HINGEANGLE_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 +HingeAngleDevice::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! HingeAngle 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! HingeAngle 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, + FWK_SENSORS_POOL_TAG_HINGEANGLE, + Size, + &MemoryHandle, + (PVOID*)&m_pEnumerationProperties); + if (!NT_SUCCESS(Status) || m_pEnumerationProperties == nullptr) + { + TraceError("COMBO %!FUNC! HingeAngle 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_HingeAngle, + &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); + + m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; + InitPropVariantFromString(L"Framework Computer Inc", + &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); + + m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; + InitPropVariantFromString(L"Hinge Angle", + &(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(SensorConnectionType::Integrated), + &(m_pEnumerationProperties->List[SENSOR_CONNECTION_TYPE].Value)); + + m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; + InitPropVariantFromCLSID(GUID_HingeAngleDevice_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)); + } + + // + // Supported Data-Fields + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_PROPERTY_LIST_SIZE(HINGEANGLE_DATA_COUNT); + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + FWK_SENSORS_POOL_TAG_HINGEANGLE, + Size, + &MemoryHandle, + (PVOID*)&m_pSupportedDataFields); + if (!NT_SUCCESS(Status) || m_pSupportedDataFields == nullptr) + { + TraceError("COMBO %!FUNC! HingeAngle WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); + m_pSupportedDataFields->Count = HINGEANGLE_DATA_COUNT; + + m_pSupportedDataFields->List[HINGEANGLE_DATA_TIMESTAMP] = PKEY_SensorData_Timestamp; + m_pSupportedDataFields->List[HINGEANGLE_DATA_ANGLE] = PKEY_SensorData_HingeAngle; + } + + // + // Data + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(HINGEANGLE_DATA_COUNT); + FILETIME Time = {0}; + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + FWK_SENSORS_POOL_TAG_HINGEANGLE, + Size, + &MemoryHandle, + (PVOID*)&m_pData); + if (!NT_SUCCESS(Status) || m_pData == nullptr) + { + TraceError("COMBO %!FUNC! HingeAngle WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pData, Size); + m_pData->Count = HINGEANGLE_DATA_COUNT; + + m_pData->List[HINGEANGLE_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; + GetSystemTimePreciseAsFileTime(&Time); + InitPropVariantFromFileTime(&Time, &(m_pData->List[HINGEANGLE_DATA_TIMESTAMP].Value)); + + m_pData->List[HINGEANGLE_DATA_ANGLE].Key = PKEY_SensorData_HingeAngle; + InitPropVariantFromFloat(0.0f, &(m_pData->List[HINGEANGLE_DATA_ANGLE].Value)); + + m_CachedData.Angle = 0.0f; + m_LastSample.Angle = 0.0f; + } + + // + // Sensor Properties + // + { + m_IntervalMs = HingeAngleDevice_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, + FWK_SENSORS_POOL_TAG_HINGEANGLE, + Size, + &MemoryHandle, + (PVOID*)&m_pProperties); + if (!NT_SUCCESS(Status) || m_pProperties == nullptr) + { + TraceError("COMBO %!FUNC! HingeAngle 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(HingeAngleDevice_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_HingeAngle, + &(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, + FWK_SENSORS_POOL_TAG_HINGEANGLE, + Size, + &MemoryHandle, + (PVOID*)&m_pDataFieldProperties); + if (!NT_SUCCESS(Status) || m_pDataFieldProperties == nullptr) + { + TraceError("COMBO %!FUNC! HingeAngle 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(HingeAngleDevice_Resolution, + &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); + + m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; + InitPropVariantFromFloat(HingeAngleDevice_Minimum, + &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); + + m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; + InitPropVariantFromFloat(HingeAngleDevice_Maximum, + &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); + } + + // + // Set default threshold + // + { + WDF_OBJECT_ATTRIBUTES MemoryAttributes; + WDFMEMORY MemoryHandle = NULL; + ULONG Size = SENSOR_COLLECTION_LIST_SIZE(1); // Single threshold: angle + + MemoryHandle = NULL; + WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); + MemoryAttributes.ParentObject = SensorInstance; + Status = WdfMemoryCreate(&MemoryAttributes, + PagedPool, + FWK_SENSORS_POOL_TAG_HINGEANGLE, + Size, + &MemoryHandle, + (PVOID*)&m_pThresholds); + if (!NT_SUCCESS(Status) || m_pThresholds == nullptr) + { + TraceError("COMBO %!FUNC! HingeAngle WdfMemoryCreate failed %!STATUS!", Status); + goto Exit; + } + + SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); + m_pThresholds->Count = 1; + + m_pThresholds->List[0].Key = PKEY_SensorData_HingeAngle; + InitPropVariantFromFloat(HingeAngleDevice_Default_Threshold, + &(m_pThresholds->List[0].Value)); + + m_CachedThresholds.Angle = HingeAngleDevice_Default_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 +HingeAngleDevice::GetData( + _In_ HANDLE Handle + ) +{ + BOOLEAN DataReady = FALSE; + FILETIME TimeStamp = {0}; + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + UINT8 lid_angle_bytes[2] = {0}; + CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_DATA + 0, &lid_angle_bytes[0]); + CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_DATA + 1, &lid_angle_bytes[1]); + UINT16 lid_angle = lid_angle_bytes[0] + (lid_angle_bytes[1] << 8); + TraceInformation("HingeAngle: %dDeg%s", lid_angle, lid_angle == LID_ANGLE_UNRELIABLE ? "(Unreliable)" : ""); + + if (lid_angle == LID_ANGLE_UNRELIABLE) + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! HingeAngle data unreliable, skipping"); + goto Exit; + } + + m_CachedData.Angle = (float)lid_angle; + + // new sample? + if (m_FirstSample != FALSE) + { + Status = GetPerformanceTime (&m_StartTime); + if (!NT_SUCCESS(Status)) + { + m_StartTime = 0; + TraceError("COMBO %!FUNC! HingeAngle GetPerformanceTime %!STATUS!", Status); + } + + m_SampleCount = 0; + + DataReady = TRUE; + } + else + { + if (abs(m_CachedData.Angle - m_LastSample.Angle) >= m_CachedThresholds.Angle) + { + DataReady = TRUE; + } + } + + if (DataReady != FALSE) + { + // update last sample + m_LastSample.Angle = m_CachedData.Angle; + + // push to clx + InitPropVariantFromFloat(m_LastSample.Angle, &(m_pData->List[HINGEANGLE_DATA_ANGLE].Value)); + + GetSystemTimePreciseAsFileTime(&TimeStamp); + InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[HINGEANGLE_DATA_TIMESTAMP].Value)); + + SensorsCxSensorDataReady(m_SensorInstance, m_pData); + m_FirstSample = FALSE; + } + else + { + Status = STATUS_DATA_NOT_ACCEPTED; + TraceInformation("COMBO %!FUNC! HingeAngle Data did NOT meet the threshold"); + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +} + + + +//------------------------------------------------------------------------------ +// Function: UpdateCachedThreshold +// +// This routine updates the cached threshold +// +// Arguments: +// None +// +// Return Value: +// NTSTATUS code +//------------------------------------------------------------------------------ +NTSTATUS +HingeAngleDevice::UpdateCachedThreshold( + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + SENSOR_FunctionEnter(); + + Status = PropKeyFindKeyGetFloat(m_pThresholds, + &PKEY_SensorData_HingeAngle, + &m_CachedThresholds.Angle); + if (!NT_SUCCESS(Status)) + { + TraceError("COMBO %!FUNC! HingeAngle PropKeyFindKeyGetFloat failed! %!STATUS!", Status); + goto Exit; + } + +Exit: + SENSOR_FunctionExit(Status); + return Status; +}