/// <summary>
        /// Creates and initializes an instance.
        /// </summary>
        public NavioRCInputDevice()
        {
            // Initialize buffers and events
            _valueBuffer = new ConcurrentQueue<PwmValue>();
            _valueTrigger = new AutoResetEvent(false);
            _frameBuffer = new ConcurrentQueue<PwmFrame>();
            _frameTrigger = new AutoResetEvent(false);

            // Configure GPIO
            _inputPin = GpioController.GetDefault().OpenPin(InputPinNumber);
            if (_inputPin.GetDriveMode() != GpioPinDriveMode.Input)
                _inputPin.SetDriveMode(GpioPinDriveMode.Input);
            _inputPin.DebounceTimeout = TimeSpan.Zero;
            _inputPin.ValueChanged += OnInputPinValueChanged;

            // Create decoder thread (CPPM only to start with, SBus desired)
            _decoder = new CppmDecoder();
            _stop = new CancellationTokenSource();
            _channels = new int[_decoder.MaximumChannels];
            Channels = new ReadOnlyCollection<int>(_channels);
            _decoderTask = Task.Factory.StartNew(() => { _decoder.Decode(_valueBuffer, _valueTrigger, _frameBuffer, _frameTrigger, _stop.Token); });

            // Create receiver thread
            _receiverTask = Task.Factory.StartNew(() => { Receiver(); });
        }
        /// <summary>
        /// Creates an instance with required mode bits set, but the device state and PWM values unchanged (supporting recovery).
        /// </summary>
        /// <remarks>
        /// <para>
        /// Initializing without restart allows the caller decide whether to recover or reset the device. 
        /// Before starting any output be sure to check the <see cref="NxpPca9685Device.Frequency"/>.
        /// </para>
        /// <para>
        /// To start with new settings, call <see cref="NxpPca9685Device.Clear"/>, <seealso cref="Restart"/> then set <see cref="OutputEnabled"/>.
        /// To resume, call <see cref="NxpPca9685Device.Wake"/> then set <see cref="OutputEnabled"/>.
        /// </para>
        /// </remarks>
        public NavioPca9685Device()
            : base(GetDeviceId(), I2cAddress, ExternalClockSpeed, true, true)
        {
            // Add PWM channel shortcuts
            Pwm = new ObservableCollection<NxpPca9685Channel>();
            for (var index = PwmChannelIndex; index < ChannelCount; index++)
                Pwm.Add(Channels[index]);

            // Initialize output pin and ensure in correct mode (but leave current state)
            _outputEnablePin = GpioController.GetDefault().OpenPin(OutputEnableGpioPin);
            if (_outputEnablePin.GetDriveMode() != GpioPinDriveMode.Output)
                _outputEnablePin.SetDriveMode(GpioPinDriveMode.Output);

            // Enable auto-increment and "all call"
            Hardware.WriteBit((byte)NxpPca9685Register.Mode1, (byte)(NxpPca9685Mode1Bits.AutoIncrement | NxpPca9685Mode1Bits.AllCall), true);

            // Set "all call" address
            Hardware.WriteByte((byte)NxpPca9685Register.AllCall, (byte)I2cAllCallAddress);

            // Update property
            ReadMode1();

            // Setup LED channels

            var redChannel = Channels[LedRedChannelIndex];
            redChannel.ValueChanged += OnLedRedChannelChanged;
            _ledRed = ~redChannel.Value.Length & 0xfff;

            var greenChannel = Channels[LedGreenChannelIndex];
            greenChannel.ValueChanged += OnLedGreenChannelChanged;
            _ledGreen = ~greenChannel.Value.Length & 0xfff;

            var blueChannel = Channels[LedBlueChannelIndex];
            blueChannel.ValueChanged += OnLedBlueChannelChanged;
            _ledBlue = ~blueChannel.Value.Length & 0xfff;
        }
        /// <summary>
        /// Creates and initializes an instance.
        /// </summary>
        public NavioRCInputDevice()
        {
            // Initialize
            _timer = new Stopwatch();
            _inputPin = GpioController.GetDefault().OpenPin(InputGpioPin);
            _ppmFrame = new double[8];
            _channels = new Collection<NavioRCInputChannel>();
            Channels = new ReadOnlyCollection<NavioRCInputChannel>(_channels);

            // PPM only in current implementation
            Mode = NavioRCInputMode.PPM;
            for (var index = 0; index < PpmChannelCount; index++)
                _channels.Add(new NavioRCInputChannel(index));

            // Configure GPIO
            if (_inputPin.GetDriveMode() != GpioPinDriveMode.Input)
                _inputPin.SetDriveMode(GpioPinDriveMode.Input);
            _inputPin.ValueChanged += OnInputPinValueChanged;
        }