Ejemplo n.º 1
0
 /// <summary>
 /// Restarts probing at the 0 timestamp.
 /// </summary>
 public void Restart() => _timer.Restart();
Ejemplo n.º 2
0
        /// <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);
        }
Ejemplo n.º 3
0
        /// <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))));
        }