Example #1
0
        public void WaitForEventFallingEdgeTest()
        {
            TimeoutHelper.CompletesInTime(() =>
            {
                using (GpioController controller = new GpioController(GetTestNumberingScheme(), GetTestDriver()))
                {
                    CancellationTokenSource tokenSource = new CancellationTokenSource();
                    controller.OpenPin(InputPin, PinMode.Input);
                    controller.OpenPin(OutputPin, PinMode.Output);
                    controller.Write(OutputPin, PinValue.Low);

                    Task.Run(() =>
                    {
                        controller.Write(OutputPin, PinValue.High);
                        Thread.Sleep(WaitMilliseconds);
                        controller.Write(OutputPin, PinValue.Low);
                    });

                    WaitForEventResult result = controller.WaitForEvent(InputPin, PinEventTypes.Falling, tokenSource.Token);

                    Assert.False(result.TimedOut);
                    Assert.Equal(PinEventTypes.Falling, result.EventTypes);
                }
            }, TimeSpan.FromSeconds(30));
        }
Example #2
0
 public void ThrowsIfWaitingOnClosedPin()
 {
     using (GpioController controller = new GpioController(GetTestNumberingScheme(), GetTestDriver()))
     {
         Assert.Throws <InvalidOperationException>(() => controller.WaitForEvent(InputPin, PinEventTypes.Falling, CancellationToken.None));
     }
 }
        public HallEffectSensor()
        {
            var gpioController = new GpioController(PinNumberingScheme.Logical, new SysFsDriver());

            gpioController.RegisterCallbackForPinValueChangedEvent(4, PinEventTypes.Falling | PinEventTypes.Rising, this.PinValueChanged);
            gpioController.WaitForEvent(3, PinEventTypes.Falling, CancellationToken.None);
        }
Example #4
0
        /// <summary>
        /// Reads previous reading and prepares next reading for specified channel
        /// </summary>
        /// <param name="channelToCharge">Channel to prepare</param>
        /// <returns>10 bit value corresponding to relative voltage level on channel</returns>
        public int ReadPreviousAndChargeChannel(Channel channelToCharge)
        {
            if (!IsValidChannel(channelToCharge))
            {
                throw new ArgumentOutOfRangeException(nameof(channelToCharge));
            }

            Span <byte> readBuffer  = stackalloc byte[2];
            Span <byte> writeBuffer = stackalloc byte[2];

            writeBuffer[0] = (byte)((int)channelToCharge << 1);
            _spiDevice.TransferFullDuplex(writeBuffer, readBuffer);

            int previousReading = ((readBuffer[0] & 0b11111) << 5) | (readBuffer[1] & 0b11111);

            if (_endOfConversion != -1)
            {
                // Wait for ADC to report end of conversion or timeout at max conversion time
                _controller.WaitForEvent(_endOfConversion, PinEventTypes.Rising, _conversionTime);
            }
            else
            {
                // Max conversion time (21us) as seen in table on page 10 in TLC1543 documentation
                DelayHelper.Delay(_conversionTime, false);
            }

            return(previousReading);
        }
Example #5
0
        public void WaitForEventBothEdgesTest()
        {
            using (GpioController controller = new GpioController(GetTestNumberingScheme(), GetTestDriver()))
            {
                CancellationTokenSource tokenSource = new CancellationTokenSource();
                tokenSource.CancelAfter(2000);
                controller.OpenPin(InputPin, PinMode.Input);
                controller.OpenPin(OutputPin, PinMode.Output);
                controller.Write(OutputPin, PinValue.High);

                // Wait for any events that happen because of the initialization
                controller.WaitForEvent(InputPin, PinEventTypes.Falling | PinEventTypes.Rising, tokenSource.Token);
                tokenSource.Dispose();

                var task = Task.Run(() =>
                {
                    controller.Write(OutputPin, PinValue.High);
                    Thread.Sleep(WaitMilliseconds);
                    controller.Write(OutputPin, PinValue.Low);
                    Thread.Sleep(WaitMilliseconds);
                    controller.Write(OutputPin, PinValue.High);
                });

                tokenSource = new CancellationTokenSource();
                tokenSource.CancelAfter(WaitMilliseconds * 4);

                // First event is falling, second is rising
                WaitForEventResult result = controller.WaitForEvent(InputPin, PinEventTypes.Falling | PinEventTypes.Rising, tokenSource.Token);
                Assert.False(result.TimedOut);
                Assert.Equal(PinEventTypes.Falling, result.EventTypes);
                result = controller.WaitForEvent(InputPin, PinEventTypes.Falling | PinEventTypes.Rising, tokenSource.Token);
                Assert.False(result.TimedOut);
                Assert.Equal(PinEventTypes.Rising, result.EventTypes);
                Assert.True(task.Wait(TimeSpan.FromSeconds(30))); // Should end long before that
                tokenSource.Dispose();
            }
        }
Example #6
0
        [Trait("SkipOnTestRun", "Windows_NT")] // The windows driver is returning none as the event type.
        public void WaitForEventCancelAfter10MillisecondsTest()
        {
            using (GpioController controller = new GpioController(GetTestNumberingScheme(), GetTestDriver()))
            {
                CancellationTokenSource tokenSource = new CancellationTokenSource(WaitMilliseconds);
                controller.OpenPin(InputPin, PinMode.Input);
                controller.OpenPin(OutputPin, PinMode.Output);
                controller.Write(OutputPin, PinValue.Low);

                WaitForEventResult result = controller.WaitForEvent(InputPin, PinEventTypes.Falling, tokenSource.Token);

                Assert.True(result.TimedOut);
                Assert.Equal(PinEventTypes.Falling, result.EventTypes);
            }
        }
Example #7
0
        public void WaitForEventSuccess()
        {
            var ctrl = new GpioController(PinNumberingScheme.Logical, _mockedGpioDriver.Object);

            _mockedGpioDriver.Setup(x => x.OpenPinEx(1));
            _mockedGpioDriver.Setup(x => x.IsPinModeSupportedEx(1, PinMode.Input)).Returns(true);
            _mockedGpioDriver.Setup(x => x.WaitForEventEx(1, PinEventTypes.Rising | PinEventTypes.Falling, It.IsAny <CancellationToken>()))
            .Returns(new WaitForEventResult()
            {
                EventTypes = PinEventTypes.Falling,
                TimedOut   = false
            });
            Assert.NotNull(ctrl);
            ctrl.OpenPin(1, PinMode.Input);

            var result = ctrl.WaitForEvent(1, PinEventTypes.Falling | PinEventTypes.Rising, TimeSpan.FromSeconds(0.01));

            Assert.False(result.TimedOut);
            Assert.Equal(PinEventTypes.Falling, result.EventTypes);
        }
Example #8
0
 public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout)
 {
     return(_controller.WaitForEvent(pinNumber, eventTypes, timeout));
 }
Example #9
0
        /// <summary>
        /// The CCS811 sensor constructor
        /// </summary>
        /// <param name="i2cDevice">A valid I2C device</param>
        /// <param name="gpioController">An optional controller, either the default one will be used, either none will be created if any pin is used</param>
        /// <param name="pinWake">An awake pin, it is optional, this pin can be set to the ground if the sensor is always on</param>
        /// <param name="pinInterruption">An interruption pin when a measurement is ready, best use when you specify a threshold</param>
        /// <param name="pinReset">An optional hard reset pin</param>
        /// <param name="shouldDispose">Should the GPIO controller be disposed at the end</param>
        public Ccs811Sensor(I2cDevice i2cDevice, GpioController gpioController = null, int pinWake = -1, int pinInterruption = -1, int pinReset = -1, bool shouldDispose = true)
        {
            _i2cDevice       = i2cDevice;
            _pinWake         = pinWake;
            _pinInterruption = pinInterruption;
            _pinReset        = pinReset;
            _shouldDispose   = shouldDispose;
            // We need a GPIO controller only if we are using any of the pin
            if ((_pinInterruption >= 0) || (_pinReset >= 0) || (_pinWake >= 0))
            {
                _shouldDispose = _shouldDispose || gpioController == null;
                _controller    = gpioController ?? new GpioController();
            }

            if (_pinWake >= 0)
            {
                _controller.OpenPin(_pinWake, PinMode.Output);
                _controller.Write(_pinWake, PinValue.High);
            }

            if (_pinReset >= 0)
            {
                _controller.OpenPin(_pinReset, PinMode.Output);
                _controller.Write(_pinReset, PinValue.Low);
                // Delays from documentation CCS811-Datasheet.pdf page 8
                // 15 micro second
                DelayHelper.DelayMicroseconds(15, true);
                _controller.Write(_pinReset, PinValue.High);
                // Need to wait at least 2 milliseconds before executing anything I2C
                Thread.Sleep(2);
            }

            // Initialization flow page 29
            // https://www.sciosense.com/wp-content/uploads/2020/01/CCS811-Application-Note-Programming-and-interfacing-guide.pdf
            // do a soft reset
            Span <byte> toReset = stackalloc byte[4]
            {
                0x11,
                0xE5,
                0x72,
                0x8A
            };

            WriteRegister(Register.SW_RESET, toReset);
            // Wait 2 milliseconds as per documentation
            Thread.Sleep(2);
            if (HardwareIdentification != 0x81)
            {
                throw new IOException($"CCS811 does not have a valid ID: {HardwareIdentification}. ID must be 0x81.");
            }

            if ((HardwareVersion & 0xF0) != 0x10)
            {
                throw new IOException($"CCS811 does not have a valid version: {HardwareVersion}, should be 0x1X where any X is valid.");
            }

            // Read status
            if (!Status.HasFlag(Status.APP_VALID))
            {
                throw new IOException($"CCS811 has no application firmware loaded.");
            }

            // Switch to app mode and wait 1 millisecond according to doc
            WriteRegister(Register.APP_START);
            Thread.Sleep(1);

            if (!Status.HasFlag(Status.FW_MODE))
            {
                throw new IOException($"CCS811 is not in application mode.");
            }

            // Set interrupt if the interruption pin is valid
            if (_pinInterruption >= 0)
            {
                _controller.OpenPin(_pinInterruption, PinMode.Input);
                byte mode = 0b0000_1000;
                WriteRegister(Register.MEAS_MODE, mode);
                _controller.RegisterCallbackForPinValueChangedEvent(_pinInterruption, PinEventTypes.Falling, InterruptReady);
                _running = true;
                // Start a new thread to monitor the events
                new Thread(() =>
                {
                    _isRunning = true;
                    while (_running)
                    {
                        var res = _controller.WaitForEvent(_pinInterruption, PinEventTypes.Falling, new TimeSpan(0, 0, 0, 0, 50));
                        if ((!res.TimedOut) && (res.EventTypes != PinEventTypes.None))
                        {
                            InterruptReady(_controller, new PinValueChangedEventArgs(res.EventTypes, _pinInterruption));
                            // We know we won't get any new measurement in next 250 milliseconds at least
                            // Waiting to make sure the sensor will have time to remove the interrupt pin
                            Thread.Sleep(50);
                        }
                    }

                    _isRunning = false;
                }).Start();
            }
        }