/// <summary> /// Restarts probing at the 0 timestamp. /// </summary> public void Restart() => _timer.Restart();
/// <summary> /// Reads the interrupt do work. /// </summary> private void ReadInterruptDoWork() { // Define some constants const long gapUsecs = 5000; const long maxElapsedMicroseconds = 250000; const long minElapsedMicroseconds = 50; const int idleCheckIntervalMilliSecs = 32; const int maxPulseCount = 128; // Setup the input pin InputPin.PinMode = GpioPinDriveMode.Input; InputPin.InputPullMode = GpioPinResistorPullMode.PullUp; // Get the timers started! var pulseTimer = new HighResolutionTimer(); var idleTimer = new HighResolutionTimer(); var pulseBuffer = new List <InfraredPulse>(maxPulseCount); var syncLock = new object(); _idleChecker = new Timer(s => { if (_isDisposed || _isInReadInterrupt) { return; } lock (syncLock) { if (idleTimer.ElapsedMicroseconds < gapUsecs || idleTimer.IsRunning == false || pulseBuffer.Count <= 0) { return; } OnInfraredSensorRawDataAvailable(pulseBuffer.ToArray(), ReceiverFlushReason.Idle); pulseBuffer.Clear(); idleTimer.Reset(); } }); InputPin.RegisterInterruptCallback(EdgeDetection.FallingAndRisingEdge, () => { if (_isDisposed) { return; } _isInReadInterrupt = true; lock (syncLock) { idleTimer.Restart(); _idleChecker.Change(idleCheckIntervalMilliSecs, idleCheckIntervalMilliSecs); var currentLength = pulseTimer.ElapsedMicroseconds; var pulse = new InfraredPulse( IsActiveLow ? !_currentValue : _currentValue, currentLength.Clamp(minElapsedMicroseconds, maxElapsedMicroseconds)); // Restart for the next bit coming in pulseTimer.Restart(); // For the next value _currentValue = InputPin.Read(); // Do not add an idling pulse if (pulse.DurationUsecs < maxElapsedMicroseconds) { pulseBuffer.Add(pulse); OnInfraredSensorPulseAvailable(pulse); } if (pulseBuffer.Count >= maxPulseCount) { OnInfraredSensorRawDataAvailable(pulseBuffer.ToArray(), ReceiverFlushReason.Overflow); pulseBuffer.Clear(); } } _isInReadInterrupt = false; }); // Get the timers started pulseTimer.Start(); idleTimer.Start(); _idleChecker.Change(0, idleCheckIntervalMilliSecs); }
/// <summary> /// Retrieves the sensor data. /// </summary> /// <returns>The event arguments that will be read from the sensor</returns> private AM2302DataReadEventArgs RetrieveSensorData() { // Wait for sensor response DataPin.PinMode = GpioPinDriveMode.Input; DataPin.InputPullMode = GpioPinResistorPullMode.PullUp; var changeElapsed = new HighResolutionTimer(); var lastValue = DataPin.Read(); var currentValue = lastValue; var lastElapsed = 0L; var pulses = new List <Tuple <bool, long> >(128); changeElapsed.Start(); while (true) { lastElapsed = changeElapsed.ElapsedMicroseconds; currentValue = DataPin.Read(); if (lastElapsed >= 5000) { break; } if (currentValue == lastValue) { continue; } else { changeElapsed.Restart(); } var pulse = new Tuple <bool, long>(lastValue, lastElapsed); pulses.Add(pulse); lastValue = currentValue; } var startPulseIndex = -1; for (var pulseIndex = 0; pulseIndex < pulses.Count - 80 - 1; pulseIndex++) { var p0 = pulses[pulseIndex + 0]; var p1 = pulses[pulseIndex + 1]; if (p0.Item1 == true && p0.Item2.IsBetween(70, 90) && p1.Item1 == false && p1.Item2.IsBetween(40, 60)) { startPulseIndex = pulseIndex + 1; break; } } if (startPulseIndex < 0 || pulses.Count - startPulseIndex < 80) { return(null); } var dataBits = new BitArray(5 * 8); // 40 bit is 8 bytes var dataBitIndex = 0; $"Start Pulse Index: {startPulseIndex}".Info(); for (var pulseIndex = startPulseIndex; pulseIndex < pulses.Count; pulseIndex += 2) { var p0 = pulses[pulseIndex + 0]; var p1 = pulses[pulseIndex + 1]; dataBits[dataBitIndex] = p1.Item2 >= 32; $"{(dataBits[dataBitIndex] ? "1" : "0")} = {(p0.Item1 ? "H" : "L")}: {p0.Item2,4} | {(p1.Item1 ? "H" : "L")}: {p1.Item2,4}".Warn(nameof(TemperatureSensorAM2302)); dataBitIndex++; if (dataBitIndex >= dataBits.Length) { break; } } // Compute the checksum var data = new byte[dataBits.Length / 8]; dataBits.CopyTo(data, 0); var checkSum = BitConverter.GetBytes(data[0] + data[1] + data[2] + data[3]); $"Checksum: {BitConverter.ToString(checkSum, 0)}; Data: {BitConverter.ToString(data)}".Warn(nameof(TemperatureSensorAM2302)); if (checkSum[0] != data[4]) { $"BAD CHECKSUM: Expected {checkSum[0]:X}; Was: {data[4]:X}".Error(nameof(TemperatureSensorAM2302)); // return null; } var sign = 0.1M; // Check negative temperature if ((data[2] & 0x80) != 0) { data[2] = (byte)(data[2] & 0x7F); sign *= -1; } return(new AM2302DataReadEventArgs( temperatureCelsius: sign *(BitConverter.IsLittleEndian ? BitConverter.ToUInt16(new byte[] { data[3], data[2] }, 0) : BitConverter.ToUInt16(new byte[] { data[2], data[3] }, 0)), humidityPercentage: 0.1M * (BitConverter.IsLittleEndian ? BitConverter.ToUInt16(new byte[] { data[1], data[0] }, 0) : BitConverter.ToUInt16(new byte[] { data[0], data[1] }, 0)))); }