/Main/GadgeteerCore/Gadgeteer43/Socket.cs
C# | 571 lines | 315 code | 46 blank | 210 comment | 46 complexity | e899a164d1e2b0965b9263ec4acca02f MD5 | raw file
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Copyright (c) Microsoft Corporation. All rights reserved.
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- namespace Gadgeteer
- {
- using Microsoft.SPOT.Hardware;
- using System;
- using System.Collections;
- using Gadgeteer.Modules;
- using SI = Gadgeteer.SocketInterfaces;
-
- /// <summary>
- /// A class representing a socket, which may be on a mainboard or on an expansion module such as an SPI multiplexer.
- /// </summary>
- /// <remarks>
- /// This class is normally not directly used by application programs, who refer to sockets by their socket number.
- /// Modules should normally use this class and the GT.Interfaces classes to access functionality required to implement their APIs.
- /// Mainboards and multiplexer modules providing sockets should use this class's SocketInterfaces subclass to declare functionalities provided on their sockets.
- /// </remarks>
- public partial class Socket
- {
- /// <summary>
- /// The <see cref="SI.AnalogInput" /> provider for this socket.
- /// </summary>
- public SI.AnalogInputIndirector AnalogInputIndirector;
- /// <summary>
- /// The <see cref="SI.AnalogOutput" /> provider for this socket.
- /// </summary>
- public SI.AnalogOutputIndirector AnalogOutputIndirector;
- /// <summary>
- /// The <see cref="SI.DigitalInput" /> provider for this socket.
- /// </summary>
- public SI.DigitalInputIndirector DigitalInputIndirector;
- /// <summary>
- /// The <see cref="SI.DigitalIO" /> provider for this socket.
- /// </summary>
- public SI.DigitalOIndirector DigitalIOIndirector;
- /// <summary>
- /// The <see cref="SI.DigitalOutput" /> provider for this socket.
- /// </summary>
- public SI.DigitalOutputIndirector DigitalOutputIndirector;
- /// <summary>
- /// The <see cref="SI.I2CBus" /> provider for this socket.
- /// </summary>
- public SI.I2CBusIndirector I2CBusIndirector;
- /// <summary>
- /// The <see cref="SI.InterruptInput" /> provider for this socket.
- /// </summary>
- public SI.InterruptInputIndirector InterruptIndirector;
- /// <summary>
- /// The <see cref="SI.PwmOutput" /> provider for this socket.
- /// </summary>
- public SI.PwmOutputIndirector PwmOutputIndirector;
- /// <summary>
- /// The <see cref="SI.Serial" /> provider for this socket.
- /// </summary>
- public SI.SerialIndirector SerialIndirector;
- /// <summary>
- /// The <see cref="SI.Spi" /> provider for this socket.
- /// </summary>
- public SI.SpiIndirector SpiIndirector;
-
- /// <summary>
- /// The socket number corresponding to this socket. On mainboards, this is a positive number and is printed on the board itself.
- /// For module-provided sockets (i.e. sockets you plug other modules into) this is an automatically generated negative number.
- /// </summary>
- public int SocketNumber { get; private set; }
-
- /// <summary>
- /// The name of the socket. This is shown to users in any socket-related error messages generated by Gadgeteer Core.
- /// </summary>
- public string Name { get; private set; }
-
- /// <summary>
- /// Array of pins used by the socket. This is always of size 11, with index [1] to [10] being the relevant Cpu.Pin for the Socket.Pin.
- /// Index 0 is unused.
- /// </summary>
- public Cpu.Pin[] CpuPins { get; private set; }
-
- /// <summary>
- /// The supported types of this socket.
- /// </summary>
- public char[] SupportedTypes
- {
- get
- {
- return _SupportedTypes;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _SupportedTypes = value;
- }
- }
- private char[] _SupportedTypes = new char[] { };
-
- /// <summary>
- /// The SPI_module corresponding to this socket. This is Socket.SPIMissing if there is no SPI module on this socket.
- /// </summary>
- public SPI.SPI_module SPIModule
- {
- get
- {
- return _SPIModule;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _SPIModule = value;
- }
- }
- private SPI.SPI_module _SPIModule = Socket.SocketInterfaces.SPIMissing;
-
- /// <summary>
- /// Returns the serial port name (e.g. "COM1") associated with a particular socket.
- /// </summary>
- /// <returns>The serial port name</returns>
- public string SerialPortName
- {
- get
- {
- return _serialPortName;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _serialPortName = value;
- }
- }
- private string _serialPortName = null;
-
- /// <summary>
- /// Provides access to pulse width modulation (PWM) functionality on a socket pin 7.
- /// </summary>
- /// <returns>An instance of the Cpu.PWMChannel enumeration, which should be PWM_NONE if there is no PWM support.</returns>
- public Cpu.PWMChannel PWM7
- {
- get
- {
- return _PWM7;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _PWM7 = value;
- }
- }
- private Cpu.PWMChannel _PWM7 = Cpu.PWMChannel.PWM_NONE;
-
- /// <summary>
- /// Provides access to pulse width modulation (PWM) functionality on a socket pin 8.
- /// </summary>
- /// <returns>An instance of the Cpu.PWMChannel enumeration, which should be PWM_NONE if there is no PWM support on this socket pin.</returns>
- public Cpu.PWMChannel PWM8
- {
- get
- {
- return _PWM8;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _PWM8 = value;
- }
- }
- private Cpu.PWMChannel _PWM8 = Cpu.PWMChannel.PWM_NONE;
-
- /// <summary>
- /// Provides access to pulse width modulation (PWM) functionality on a socket pin 9.
- /// </summary>
- /// <returns>An instance of the Cpu.PWMChannel enumeration, which should be PWM_NONE if there is no PWM support on this socket pin.</returns>
- public Cpu.PWMChannel PWM9
- {
- get
- {
- return _PWM9;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _PWM9 = value;
- }
- }
- private Cpu.PWMChannel _PWM9 = Cpu.PWMChannel.PWM_NONE;
-
- internal double AnalogInputScale = double.MinValue;
- internal double AnalogInputOffset = double.MinValue;
- internal int AnalogInputPrecisionInBits = int.MinValue;
-
- internal double AnalogOutputScale = double.MinValue;
- internal double AnalogOutputOffset = double.MinValue;
- internal int AnalogOutputPrecisionInBits = int.MinValue;
-
- /// <summary>
- /// Provides access to analog input functionality on a socket's pin 3.
- /// </summary>
- /// <returns>An instance of the Cpu.AnalogChannel enumeration, which should be ANALOG_NONE if there is no Analog input support on this socket pin.</returns>
- public Cpu.AnalogChannel AnalogInput3
- {
- get
- {
- return _AnalogInput3;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _AnalogInput3 = value;
- }
- }
- private Cpu.AnalogChannel _AnalogInput3 = Cpu.AnalogChannel.ANALOG_NONE;
-
- /// <summary>
- /// Provides access to analog input functionality on a socket's pin 4.
- /// </summary>
- /// <returns>An instance of the Cpu.AnalogChannel enumeration, which should be ANALOG_NONE if there is no Analog input support on this socket pin.</returns>
- public Cpu.AnalogChannel AnalogInput4
- {
- get
- {
- return _AnalogInput4;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _AnalogInput4 = value;
- }
- }
- private Cpu.AnalogChannel _AnalogInput4 = Cpu.AnalogChannel.ANALOG_NONE;
-
- /// <summary>
- /// Provides access to analog input functionality on a socket's pin 5.
- /// </summary>
- /// <returns>An instance of the Cpu.AnalogChannel enumeration, which should be ANALOG_NONE if there is no Analog input support on this socket pin.</returns>
- public Cpu.AnalogChannel AnalogInput5
- {
- get
- {
- return _AnalogInput5;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _AnalogInput5 = value;
- }
- }
- private Cpu.AnalogChannel _AnalogInput5 = Cpu.AnalogChannel.ANALOG_NONE;
-
- /// <summary>
- /// Provides access to analog output functionality on a socket's pin 5.
- /// </summary>
- /// <returns>An instance of the Cpu.AnalogChannel enumeration, which should be ANALOG_NONE if there is no Analog input support on this socket pin.</returns>
- public Cpu.AnalogOutputChannel AnalogOutput5
- {
- get
- {
- return _AnalogOutput5;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _AnalogOutput5 = value;
- }
- }
- private Cpu.AnalogOutputChannel _AnalogOutput5 = Cpu.AnalogOutputChannel.ANALOG_OUTPUT_NONE;
-
- internal static ArrayList _sockets = new ArrayList();
-
- /// <summary>
- /// A special socket number indicating that a module socket is not used.
- /// </summary>
- public static int Unused { get { return int.MinValue; } }
-
-
- /// <summary>
- /// Get the <see cref="Socket"/> corresponding to a socket number.
- /// </summary>
- /// <param name="socketNumber">The socket number</param>
- /// <param name="throwExceptionIfSocketNumberInvalid">Whether to throw an <see cref="InvalidSocketException"/> if the socket does not exist.</param>
- /// <param name="module">The module using this socket.</param>
- /// <param name="socketLabel">The label on the socket, if there is more than one socket on the module (can be null).</param>
- /// <returns>The socket corresponding to the provided socket number.</returns>
- public static Socket GetSocket(int socketNumber, bool throwExceptionIfSocketNumberInvalid, Module module, string socketLabel)
- {
- if (socketLabel == "") socketLabel = null;
-
- if (socketNumber == Socket.Unused)
- {
- if (throwExceptionIfSocketNumberInvalid)
- {
- if (module == null)
- {
- throw new InvalidSocketException("Cannot get Socket for socket number Socket.NotConnected");
- }
- else
- {
- String errormessage = "Module " + module;
- if (socketLabel != null) errormessage += " socket " + socketLabel;
- errormessage += " must have a valid socket number specified (it does not support Socket.Unused)";
- throw new InvalidSocketException(errormessage);
- }
- }
- else
- {
- return null;
- }
- }
-
- lock (_sockets)
- {
- for (int i = 0; i < _sockets.Count; i++)
- {
- Socket socket = (Socket)_sockets[i];
- if (socket.SocketNumber == socketNumber) return socket;
- }
- }
- if (throwExceptionIfSocketNumberInvalid)
- {
- if (module == null)
- {
- throw new InvalidSocketException("Invalid socket number " + socketNumber + " specified.");
- }
- else
- {
- String errormessage = "Module " + module;
- if (socketLabel != null) errormessage += " socket " + socketLabel;
- errormessage += " cannot be used with invalid socket number " + socketNumber;
- throw new InvalidSocketException(errormessage);
- }
- }
- return null;
- }
-
- internal bool _registered = false;
-
- internal Socket(int socketNumber, string name)
- {
- this.Name = name;
- this.SocketNumber = socketNumber;
- this.CpuPins = new Cpu.Pin[11] { Socket.UnspecifiedPin, Socket.UnspecifiedPin, Socket.UnspecifiedPin, Socket.UnspecifiedPin, Socket.UnspecifiedPin, Socket.UnspecifiedPin, Socket.UnspecifiedPin, Socket.UnspecifiedPin, Socket.UnspecifiedPin, Socket.UnspecifiedPin, Socket.UnspecifiedPin };
- }
-
- /// <summary>
- /// Returns the Name of this socket.
- /// </summary>
- /// <returns></returns>
- public override string ToString()
- {
- return Name;
- }
-
-
- /// <summary>
- /// Determines whether the specified socket supports the given socket type
- /// </summary>
- /// <param name="type">The socket type</param>
- /// <returns></returns>
- public bool SupportsType(char type)
- {
- return Array.IndexOf(_SupportedTypes, type) >= 0;
- }
-
- /// <summary>
- /// Checks that a given socket type is supported, and throws an <see cref="InvalidSocketException"/> if not. Optionally specifies the module which requires this type, resulting in a better error message.
- /// </summary>
- /// <param name="type">The socket type required.</param>
- /// <param name="module">The module requiring this socket type (can be null).</param>
- public void EnsureTypeIsSupported(char type, Module module)
- {
- if (!SupportsType(type))
- {
- throw new InvalidSocketException("Socket " + Name + " does not support type '" + type + "'" + (module != null ? " required by " + module + " module." : "."));
- }
- }
-
- /// <summary>
- /// Checks that one of a given set of socket types is supported, and throws an <see cref="InvalidSocketException"/> if not. Optionally specifies the module which requires this type, resulting in a better error message.
- /// </summary>
- /// <param name="types">The array of socket types required (any one of these is sufficient).</param>
- /// <param name="module">The module requiring this socket type (can be null).</param>
- public void EnsureTypeIsSupported(char[] types, Module module)
- {
- for (int i = 0; i < types.Length; i++)
- {
- if (SupportsType(types[i])) return;
- }
- throw new InvalidSocketException("Socket " + Name + " does not support one of the types '" + new String(types) + "'" + (module != null ? " required by " + module + " module." : "."));
- }
-
- /// <summary>
- /// An enumeration of socket pins.
- /// </summary>
- public enum Pin
- {
- /// <summary>
- /// Not applicable
- /// </summary>
- None = 0,
- /// <summary>
- /// Socket pin 1
- /// </summary>
- One = 1,
- /// <summary>
- /// Socket pin 2
- /// </summary>
- Two = 2,
- /// <summary>
- /// Socket pin 3
- /// </summary>
- Three = 3,
- /// <summary>
- /// Socket pin 4
- /// </summary>
- Four = 4,
- /// <summary>
- /// Socket pin 5
- /// </summary>
- Five = 5,
- /// <summary>
- /// Socket pin 6
- /// </summary>
- Six = 6,
- /// <summary>
- /// Socket pin 7
- /// </summary>
- Seven = 7,
- /// <summary>
- /// Socket pin 8
- /// </summary>
- Eight = 8,
- /// <summary>
- /// Socket pin 9
- /// </summary>
- Nine = 9,
- /// <summary>
- /// Socket pin 10
- /// </summary>
- Ten = 10
- }
-
- /// <summary>
- /// Tells GadgeteerCore that a pin is being used on this socket.
- /// This is called by Gadgteeer.Interface classes automatically. Gadgeteer.Modules which do not use a Gadgeteer.Interface helper class in using a pin should call this directly.
- /// </summary>
- /// <param name="pin">The socket pin being used</param>
- /// <param name="module">The module using the socket pin (can be null, but if it is not null a more useful error message will be generated).</param>
- /// <returns></returns>
- public Cpu.Pin ReservePin(Socket.Pin pin, Module module)
- {
- if (pin == Pin.None)
- {
- return UnspecifiedPin;
- }
-
- Cpu.Pin cpuPin = CpuPins[(int)pin];
- if (cpuPin == UnspecifiedPin)
- {
- throw new PinMissingException(this, pin);
- }
-
- if (cpuPin == UnnumberedPin)
- {
- // bypass checks, return no pin
- return Cpu.Pin.GPIO_NONE;
- }
-
- // see if this is a display socket and reboot if we need to disable the LCD controller
- if (!(module is Module.DisplayModule) && (SupportsType('R') || SupportsType('G') || SupportsType('B')))
- {
- Program.Mainboard.EnsureRgbSocketPinsAvailable();
- }
-
- return cpuPin;
- }
-
- /// <summary>
- /// An exception raised when a socket pin which is unspecified by the socket provider is used.
- /// </summary>
- public class PinMissingException : ApplicationException
- {
- internal PinMissingException(Socket socket, Socket.Pin pin)
- : base("\nPin " + (int)pin + " on socket " + socket + " is not connected to a valid CPU pin.")
- { }
- }
-
- /// <summary>
- /// An exception raised when an invalid socket is specified, e.g. a socket incompatible with the functionality required.
- /// </summary>
- public class InvalidSocketException : ArgumentException
- {
- /// <summary>
- /// Generates a new invalid socket exception
- /// </summary>
- /// <param name="message">The exception cause</param>
- public InvalidSocketException(String message)
- : base(message)
- {
- }
-
- /// <summary>
- /// Throws an <see cref="InvalidSocketException" /> if a pin number is not in the specified range.
- /// </summary>
- /// <param name="pin">The pin number to test.</param>
- /// <param name="from">The lowest valid pin number.</param>
- /// <param name="to">The highest valid pin number.</param>
- /// <param name="iface">The requesting interface.</param>
- /// <param name="module">The requesting module.</param>
- /// <exception cref="InvalidSocketException">The <paramref name="pin" /> is out of the range specified by <paramref name="from" /> and <paramref name="to" />.</exception>
- /// <remarks>
- /// This method helps lowering the footprint and should be called when implementing a socket interface.
- /// </remarks>
- [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
- public static void ThrowIfOutOfRange(Socket.Pin pin, Socket.Pin from, Socket.Pin to, string iface, Module module)
- {
- if (pin >= from && pin <= to)
- return;
-
- string message = "Cannot use " + iface + " interface on pin " + pin + " - pin must be in range " + from + " to " + to + ".";
- if (module != null)
- message = "Module " + module + ": ";
-
- throw new InvalidSocketException(message);
- }
-
- /// <summary>
- /// Returns an <see cref="InvalidSocketException" /> with functionality error message.
- /// </summary>
- /// <param name="socket">The socket that has the error.</param>
- /// <param name="iface">The interface that is causing the error.</param>
- /// <returns>An <see cref="InvalidSocketException" /> with functionality error message.</returns>
- /// <remarks>
- /// This method helps lowering the footprint and should be called when implementing a socket interface.
- /// </remarks>
- [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
- public static InvalidSocketException FunctionalityException(Socket socket, string iface)
- {
- return new InvalidSocketException("Socket " + socket + " has an error with its " + iface + " functionality. Please try a different socket.");
- }
-
- /// <summary>
- /// Generates a new invalid socket exception
- /// </summary>
- /// <param name="message">The exception cause</param>
- /// <param name="e">The underlying exception</param>
- public InvalidSocketException(String message, Exception e)
- : base(message, e)
- {
- }
- }
-
- /// <summary>
- /// This exception is thrown when a socket which is already registered with GadgeteerCore is then modified.
- /// </summary>
- public class SocketImmutableAfterRegistrationException : InvalidOperationException
- {
- internal SocketImmutableAfterRegistrationException()
- : base("Socket data is immutable after socket is registered.")
- { }
- }
-
- /// <summary>
- /// A CPU pin which has no number, and for which reservation does not need to be tracked.
- /// </summary>
- public static readonly Cpu.Pin UnnumberedPin = (Cpu.Pin)int.MinValue;
-
- /// <summary>
- /// An unspecified CPU pin (e.g. for a socket which does not use this pin).
- /// </summary>
- public static readonly Cpu.Pin UnspecifiedPin = Cpu.Pin.GPIO_NONE;
- }
-
- }