//------------------------------------------------------------------------------ // 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; }
// This routine is called by worker thread to read a single sample and push it back // to CLX. NTSTATUS CustomSensorDevice::GetData() { PHardwareSimulator pSimulator = nullptr; FILETIME TimeStamp = {}; NTSTATUS Status = STATUS_SUCCESS; SENSOR_FunctionEnter(); if (FALSE != m_FirstSample) { Status = GetPerformanceTime(&m_StartTime); if (!NT_SUCCESS(Status)) { m_StartTime = 0; TraceError("CSTM %!FUNC! GetPerformanceTime %!STATUS!", Status); } } pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance); if (nullptr == pSimulator) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("CSTM %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); goto Exit; } // push to clx InitPropVariantFromFloat(pSimulator->GetSample(), &(m_pData->List[CSTM_DATA_CO2_LEVEL_PERCENT].Value)); GetSystemTimePreciseAsFileTime(&TimeStamp); InitPropVariantFromFileTime(&TimeStamp, &(m_pData->List[CSTM_DATA_TIMESTAMP].Value)); SensorsCxSensorDataReady(m_SensorInstance, m_pData); m_FirstSample = FALSE; Exit: SENSOR_FunctionExit(Status); return Status; }
// This callback is called when interval wait time has expired and driver is ready // to collect new sample. The callback reads current value, // pushes it up to CLX framework, and schedule next wake up time. VOID CustomSensorDevice::OnTimerExpire( _In_ WDFTIMER Timer // WDF timer object ) { PCustomSensorDevice pDevice = nullptr; NTSTATUS Status = STATUS_SUCCESS; SENSOR_FunctionEnter(); pDevice = GetCustomSensorContextFromSensorInstance(WdfTimerGetParentObject(Timer)); if (nullptr == pDevice) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("CSTM %!FUNC! GetCustomSensorContextFromSensorInstance failed %!STATUS!", Status); } if (NT_SUCCESS(Status)) { // Get data and push to clx WdfWaitLockAcquire(pDevice->m_Lock, NULL); Status = pDevice->GetData(); if (!NT_SUCCESS(Status) && Status != STATUS_DATA_NOT_ACCEPTED) { TraceError("CSTM %!FUNC! GetCstmData Failed %!STATUS!", Status); } WdfWaitLockRelease(pDevice->m_Lock); // Schedule next wake up time if (FALSE != pDevice->m_PoweredOn && FALSE != pDevice->m_Started) { LONGLONG WaitTimeHundredNanoseconds = 0; // in unit of 100ns if (0 == pDevice->m_StartTime) { // in case we fail to get sensor start time, use static wait time WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); } else { ULONG CurrentTimeMs = 0; // dynamically calculate wait time to avoid jitter Status = GetPerformanceTime(&CurrentTimeMs); if (!NT_SUCCESS(Status)) { TraceError("PED %!FUNC! GetPerformanceTime %!STATUS!", Status); WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); } else { WaitTimeHundredNanoseconds = pDevice->m_Interval - ((CurrentTimeMs - pDevice->m_StartTime) % pDevice->m_Interval); WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(WaitTimeHundredNanoseconds); } } WdfTimerStart(pDevice->m_Timer, WaitTimeHundredNanoseconds); } } SENSOR_FunctionExit(Status); }
// This routine is called by worker thread to read a single sample, compare threshold // and push it back to CLX. It simulates hardware thresholding by only generating data // when the change of data is greater than threshold. NTSTATUS PedometerDevice::GetData( ) { PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance); BOOLEAN DataReady = FALSE; NTSTATUS Status = STATUS_SUCCESS; ULONG CachedStepCountLimit = 0; ULONG LastStepCountLimit = 0; PedometerSample Sample = {}; SENSOR_FunctionEnter(); if (nullptr == pSimulator) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); goto Exit; } Status = pSimulator->GetSample(&Sample); if (!NT_SUCCESS(Status)) { TraceError("PED %!FUNC! GetSample failed %!STATUS!", Status); goto Exit; } if (FALSE != m_FirstSample) { Status = GetPerformanceTime(&m_StartTime); if (!NT_SUCCESS(Status)) { m_StartTime = 0; TraceError("PED %!FUNC! GetPerformanceTime failed %!STATUS!", Status); } m_SampleCount = 0; DataReady = TRUE; } else { if (0 == m_CachedThreshold || FALSE != Sample.IsFirstAfterReset) { // Streaming mode DataReady = TRUE; } else { if (FAILED(ULongAdd(Sample.UnknownStepCount, Sample.WalkingStepCount, &CachedStepCountLimit)) || FAILED(ULongAdd(Sample.RunningStepCount, CachedStepCountLimit, &CachedStepCountLimit))) { // If an overflow happened, we assume we reached the threshold // in other words, there is no threshold value that can be larger // than an overflowed value. DataReady = TRUE; } else if (FAILED(ULongAdd(m_LastSample.UnknownStepCount, m_LastSample.WalkingStepCount, &LastStepCountLimit)) || FAILED(ULongAdd(m_LastSample.RunningStepCount, LastStepCountLimit, &LastStepCountLimit))) { // If an overflow happened, we assume we reached the threshold // in other words, there is no threshold value that can be larger // than an overflowed value. DataReady = TRUE; } else if ((LastStepCountLimit < m_CachedThreshold && CachedStepCountLimit >= m_CachedThreshold) || (FALSE != Sample.IsFirstAfterReset)) { // Compare the change of data to threshold, and only push the data back to // clx if the change exceeds threshold or if this is the first sample after reset. This is usually done in HW. DataReady = TRUE; } } } if (FALSE != DataReady) { // update last sample m_LastSample = Sample; // push to clx InitPropVariantFromBoolean(m_LastSample.IsFirstAfterReset, &(m_pData->List[PEDOMETER_DATA_FIRST_AFTER_RESET].Value)); InitPropVariantFromUInt32(PedometerStepType_Unknown, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_TYPE].Value)); InitPropVariantFromInt64(m_LastSample.UnknownStepDurationMs, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_DURATION].Value)); InitPropVariantFromUInt32(m_LastSample.UnknownStepCount, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_COUNT].Value)); InitPropVariantFromUInt32(PedometerStepType_Walking, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_TYPE].Value)); InitPropVariantFromInt64(m_LastSample.WalkingStepDurationMs, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_DURATION].Value)); InitPropVariantFromUInt32(m_LastSample.WalkingStepCount, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_COUNT].Value)); InitPropVariantFromUInt32(PedometerStepType_Running, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_TYPE].Value)); InitPropVariantFromInt64(m_LastSample.RunningStepDurationMs, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_DURATION].Value)); InitPropVariantFromUInt32(m_LastSample.RunningStepCount, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_COUNT].Value)); // reset IsFirstAfterReset m_LastSample.IsFirstAfterReset = FALSE; InitPropVariantFromFileTime(&m_LastSample.Timestamp, &(m_pData->List[PEDOMETER_DATA_TIMESTAMP].Value)); SensorsCxSensorDataReady(m_SensorInstance, m_pData); m_FirstSample = FALSE; } else { Status = STATUS_DATA_NOT_ACCEPTED; TraceInformation("PED %!FUNC! Data did NOT meet the threshold"); } SENSOR_FunctionExit(Status); Exit: return Status; }
// This callback is called when interval wait time has expired and driver is ready // to collect new sample. The callback reads current value, compare value to threshold, // pushes it up to CLX framework, and schedule next wake up time. VOID PedometerDevice::OnTimerExpire( _In_ WDFTIMER Timer // WDF timer object ) { PPedometerDevice pDevice = nullptr; NTSTATUS Status = STATUS_SUCCESS; SENSOR_FunctionEnter(); pDevice = GetPedometerContextFromSensorInstance(WdfTimerGetParentObject(Timer)); if (nullptr == pDevice) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("PED %!FUNC! GetPedometerContextFromSensorInstance failed %!STATUS!", Status); goto Exit; } // Get data and push to clx WdfWaitLockAcquire(pDevice->m_Lock, NULL); Status = pDevice->GetData(); if (!NT_SUCCESS(Status) && Status != STATUS_DATA_NOT_ACCEPTED) { TraceError("PED %!FUNC! GetData Failed %!STATUS!", Status); } WdfWaitLockRelease(pDevice->m_Lock); // Schedule next wake up time if (FALSE != pDevice->m_PoweredOn && FALSE != pDevice->m_Started) { LONGLONG WaitTimeHundredNanoseconds = 0; // in unit of 100ns if (0 == pDevice->m_StartTime) { // in case we fail to get sensor start time, use static wait time WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); } else { ULONG CurrentTimeMs = 0; // dynamically calculate wait time to avoid jitter Status = GetPerformanceTime (&CurrentTimeMs); if (!NT_SUCCESS(Status)) { TraceError("PED %!FUNC! GetPerformanceTime %!STATUS!", Status); WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); } else { pDevice->m_SampleCount++; if (CurrentTimeMs > (pDevice->m_StartTime + (pDevice->m_Interval * (pDevice->m_SampleCount + 1)))) { // If we skipped two or more beats, reschedule the timer with a zero due time to catch up on missing samples WaitTimeHundredNanoseconds = 0; } else { WaitTimeHundredNanoseconds = (pDevice->m_StartTime + (pDevice->m_Interval * (pDevice->m_SampleCount + 1))) - CurrentTimeMs; } WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(WaitTimeHundredNanoseconds); } } WdfTimerStart(pDevice->m_Timer, WaitTimeHundredNanoseconds); } Exit: SENSOR_FunctionExit(Status); }