Ejemplo n.º 1
0
        private bool UsageCanSharePins(PinUsage usage)
        {
            switch (usage)
            {
            // Several SPI devices can share the same Pins (because we're allocating devices, not buses)
            case PinUsage.Spi:
                return(true);

            default:
                return(false);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets the current alternate pin mode. (ALTn mode)
        /// </summary>
        /// <param name="pinNumber">Pin number, in the logical scheme</param>
        /// <returns>The current pin usage</returns>
        /// <remarks>This also works for closed pins, but then uses a bit of heuristics to get the correct mode</remarks>
        public override PinUsage DetermineCurrentPinUsage(int pinNumber)
        {
            if (_managedGpioController == null)
            {
                throw new InvalidOperationException("Board not initialized");
            }

            PinUsage cached = base.DetermineCurrentPinUsage(pinNumber);

            if (cached != PinUsage.Unknown)
            {
                return(cached);
            }

            if (_raspberryPi3Driver == null || !_raspberryPi3Driver.AlternatePinModeSettingSupported)
            {
                throw new NotSupportedException("Alternate pin mode setting not supported by driver");
            }

            var pinMode = _raspberryPi3Driver.GetAlternatePinMode(pinNumber);

            if (pinMode == RaspberryPi3Driver.AltMode.Input || pinMode == RaspberryPi3Driver.AltMode.Output)
            {
                return(PinUsage.Gpio);
            }

            // Do some heuristics: If the given pin number can be used for I2C with the same Alt mode, we can assume that's what it
            // it set to.
            var possibleAltMode = GetHardwareModeForPinUsage(pinNumber, PinUsage.I2c, DefaultPinNumberingScheme);

            if (possibleAltMode == pinMode)
            {
                return(PinUsage.I2c);
            }

            possibleAltMode = GetHardwareModeForPinUsage(pinNumber, PinUsage.Spi, DefaultPinNumberingScheme);
            if (possibleAltMode == pinMode)
            {
                return(PinUsage.Spi);
            }

            possibleAltMode = GetHardwareModeForPinUsage(pinNumber, PinUsage.Pwm, DefaultPinNumberingScheme);
            if (possibleAltMode == pinMode)
            {
                return(PinUsage.Pwm);
            }

            return(PinUsage.Unknown);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Removes the reservation for a pin.
        /// See <see cref="ReservePin"/> for details.
        /// </summary>
        /// <param name="pinNumber">The pin number to free, in the numbering scheme of the board</param>
        /// <param name="usage">The current pin usage</param>
        /// <param name="owner">The current pin owner</param>
        /// <exception cref="InvalidOperationException">The pin is not reserved, or the owner is not correct</exception>
        public virtual void ReleasePin(int pinNumber, PinUsage usage, object owner)
        {
            if (!_initialized)
            {
                throw new InvalidOperationException("Cannot release a pin if board is not initialized.");
            }

            lock (_pinReservationsLock)
            {
                if (_pinReservations.TryGetValue(pinNumber, out List <PinReservation>?reservations))
                {
                    if (!UsageCanSharePins(usage))
                    {
                        PinReservation reservation = reservations.Single();
                        if (reservation.Owner != owner || reservation.Usage != usage)
                        {
                            throw new InvalidOperationException($"Cannot release Pin {pinNumber}, because you are not the owner or the usage is wrong. Class {reservation.Owner} has reserved the Pin for {reservation.Usage}");
                        }

                        _pinReservations.Remove(pinNumber);
                    }
                    else
                    {
                        PinReservation?reservation = reservations.FirstOrDefault(x => x.Owner == owner);
                        if (reservation == null)
                        {
                            throw new InvalidOperationException($"Cannot release Pin {pinNumber}, because you are not a valid owner.");
                        }

                        if (reservation.Usage != usage)
                        {
                            throw new InvalidOperationException($"Cannot release Pin {pinNumber}, because you are not the owner or the usage is wrong. Class {reservation.Owner} has reserved the Pin for {reservation.Usage}");
                        }

                        reservations.Remove(reservation);
                        if (reservations.Count == 0)
                        {
                            _pinReservations.Remove(pinNumber);
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException($"Cannot release Pin {pinNumber}, because it is not reserved.");
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Reserves a pin for a specific usage. This is done automatically if a known interface (i.e. GpioController) is
        /// used to open the pin, but may be used to block a pin explicitly, i.e. for UART.
        /// </summary>
        /// <param name="pinNumber">The pin number, in the boards default numbering scheme</param>
        /// <param name="usage">Intended usage of the pin</param>
        /// <param name="owner">Class that owns the pin (use "this")</param>
        /// <exception cref="InvalidOperationException">The pin is already reserved</exception>
        public virtual void ReservePin(int pinNumber, PinUsage usage, object owner)
        {
            if (!_initialized)
            {
                Initialize();
            }

            lock (_pinReservationsLock)
            {
                if (!UsageCanSharePins(usage))
                {
                    if (_pinReservations.TryGetValue(pinNumber, out List <PinReservation>?reservations))
                    {
                        PinReservation reservation = reservations.First();
                        throw new InvalidOperationException($"Pin {pinNumber} has already been reserved for {reservation.Usage} by class {reservation.Owner}.");
                    }

                    PinReservation rsv = new PinReservation(pinNumber, usage, owner);
                    _pinReservations.Add(pinNumber, new List <PinReservation>()
                    {
                        rsv
                    });
                }
                else
                {
                    if (_pinReservations.TryGetValue(pinNumber, out List <PinReservation>?reservations))
                    {
                        PinReservation reservation = reservations.First();
                        if (reservation.Usage != usage)
                        {
                            throw new InvalidOperationException($"Pin {pinNumber} has already been reserved for {reservation.Usage} by class {reservation.Owner}.");
                        }
                    }
                    else
                    {
                        reservations = new List <PinReservation>();
                        _pinReservations.Add(pinNumber, reservations);
                    }

                    PinReservation rsv = new PinReservation(pinNumber, usage, owner);
                    reservations.Add(rsv);
                }
            }

            ActivatePinMode(pinNumber, usage);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Switches a pin to a certain alternate mode. (ALTn mode)
        /// </summary>
        /// <param name="pinNumber">The pin number in the logical scheme</param>
        /// <param name="usage">The desired usage</param>
        protected override void ActivatePinMode(int pinNumber, PinUsage usage)
        {
            if (_managedGpioController == null)
            {
                throw new InvalidOperationException("Board not initialized");
            }

            if (_raspberryPi3Driver == null || !_raspberryPi3Driver.AlternatePinModeSettingSupported)
            {
                throw new NotSupportedException("Alternate pin mode setting not supported by driver");
            }

            var modeToSet = GetHardwareModeForPinUsage(pinNumber, usage, PinNumberingScheme.Logical);

            if (modeToSet != RaspberryPi3Driver.AltMode.Unknown)
            {
                _raspberryPi3Driver.SetAlternatePinMode(pinNumber, modeToSet);
            }

            base.ActivatePinMode(pinNumber, usage);
        }
Ejemplo n.º 6
0
 public PinReservation(int pin, PinUsage usage, object owner)
 {
     Pin   = pin;
     Usage = usage;
     Owner = owner;
 }
Ejemplo n.º 7
0
 /// <summary>
 /// Override this method if something special needs to be done to use the pin for the given device.
 /// Many devices support multiple functions per Pin, but not at the same time, so that some kind of
 /// multiplexer needs to be set accordingly.
 /// </summary>
 /// <param name="pinNumber">The logical pin number to use.</param>
 /// <param name="usage">The intended usage</param>
 protected virtual void ActivatePinMode(int pinNumber, PinUsage usage)
 {
     _knownUsages[pinNumber] = usage;
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Gets the board-specific hardware mode for a particular pin and pin usage (i.e. the different ALTn modes on the raspberry pi)
        /// </summary>
        /// <param name="pinNumber">Pin number to use</param>
        /// <param name="usage">Requested usage</param>
        /// <param name="pinNumberingScheme">Pin numbering scheme for the pin provided (logical or physical)</param>
        /// <param name="bus">Optional bus argument, for SPI and I2C pins</param>
        /// <returns>
        /// A member of <see cref="RaspberryPi3Driver.AltMode"/> describing the mode the pin is in.</returns>
        private RaspberryPi3Driver.AltMode GetHardwareModeForPinUsage(int pinNumber, PinUsage usage, PinNumberingScheme pinNumberingScheme = PinNumberingScheme.Logical, int bus = 0)
        {
            if (pinNumber >= PinCount)
            {
                throw new InvalidOperationException($"Invalid pin number {pinNumber}");
            }

            if (usage == PinUsage.Gpio)
            {
                // all pins support GPIO
                return(RaspberryPi3Driver.AltMode.Input);
            }

            if (usage == PinUsage.I2c)
            {
                // The Pi4 has a big number of pins that can become I2C pins
                switch (pinNumber)
                {
                // Busses 0 and 1 run on Alt0
                case 0:
                case 1:
                case 2:
                case 3:
                    return(RaspberryPi3Driver.AltMode.Alt0);

                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                case 10:
                case 11:
                case 12:
                case 13:
                case 14:
                    return(RaspberryPi3Driver.AltMode.Alt5);

                case 22:
                case 23:
                    return(RaspberryPi3Driver.AltMode.Alt5);
                }

                throw new NotSupportedException($"No I2C support on Pin {pinNumber}.");
            }

            if (usage == PinUsage.Pwm)
            {
                if (pinNumber == 12 || pinNumber == 13)
                {
                    return(RaspberryPi3Driver.AltMode.Alt0);
                }

                if (pinNumber == 18 || pinNumber == 19)
                {
                    return(RaspberryPi3Driver.AltMode.Alt5);
                }

                throw new NotSupportedException($"No Pwm support on Pin {pinNumber}.");
            }

            if (usage == PinUsage.Spi)
            {
                switch (pinNumber)
                {
                case 7:     // Pin 7 can be assigned to either SPI0 or SPI4
                    return(bus == 0 ? RaspberryPi3Driver.AltMode.Alt0 : RaspberryPi3Driver.AltMode.Alt3);

                case 8:
                case 9:
                case 10:
                case 11:
                    return(RaspberryPi3Driver.AltMode.Alt0);

                case 0:
                case 1:
                case 2:
                case 3:
                    return(RaspberryPi3Driver.AltMode.Alt3);

                case 4:
                case 5:
                case 6:
                    return(RaspberryPi3Driver.AltMode.Alt3);

                case 12:
                case 13:
                case 14:
                case 15:
                    return(RaspberryPi3Driver.AltMode.Alt3);

                case 16:
                case 17:
                    return(RaspberryPi3Driver.AltMode.Alt4);

                case 18:
                case 19:
                case 20:
                case 21:
                    return(bus == 6 ? RaspberryPi3Driver.AltMode.Alt3 : RaspberryPi3Driver.AltMode.Alt4);

                case 24:
                case 25:
                case 26:
                case 27:
                    return(RaspberryPi3Driver.AltMode.Alt5);
                }

                throw new NotSupportedException($"No SPI support on Pin {pinNumber}.");
            }

            if (usage == PinUsage.Uart)
            {
                switch (pinNumber)
                {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                case 10:
                case 11:
                case 12:
                case 13:
                    return(RaspberryPi3Driver.AltMode.Alt4);

                case 14:
                case 15:
                    if (bus == 0)
                    {
                        return(RaspberryPi3Driver.AltMode.Alt0);
                    }
                    else if (bus == 5)
                    {
                        return(RaspberryPi3Driver.AltMode.Alt4);
                    }
                    else if (bus == 1)
                    {
                        return(RaspberryPi3Driver.AltMode.Alt5);
                    }

                    break;

                case 16:
                case 17:
                    return((bus == 0) ? RaspberryPi3Driver.AltMode.Alt3 : RaspberryPi3Driver.AltMode.Alt5);
                }

                throw new NotSupportedException($"No Uart support on Pin {pinNumber}.");
            }

            throw new NotSupportedException($"There are no known pins for {usage}.");
        }