/Main/GadgeteerCore/Gadgeteer42/Socket.cs
C# | 656 lines | 333 code | 48 blank | 275 comment | 45 complexity | 3eb558bb829e5f64f92802f98b658d31 MD5 | raw file
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Copyright (c) Microsoft Corporation. All rights reserved.
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- namespace Gadgeteer
- {
- using Microsoft.SPOT;
- using Microsoft.SPOT.Hardware;
- using System;
- using System.Collections;
- using System.ComponentModel;
- using Gadgeteer.Modules;
-
- /// <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="SocketInterfaces.AnalogInput" /> provider for this socket.
- /// </summary>
- public SocketInterfaces.AnalogInputIndirector AnalogInputIndirector;
- /// <summary>
- /// The <see cref="SocketInterfaces.DigitalInput" /> provider for this socket.
- /// </summary>
- public SocketInterfaces.DigitalInputIndirector DigitalInputIndirector;
- /// <summary>
- /// The <see cref="SocketInterfaces.DigitalIO" /> provider for this socket.
- /// </summary>
- public SocketInterfaces.DigitalIOIndirector DigitalIOIndirector;
- /// <summary>
- /// The <see cref="SocketInterfaces.DigitalOutput" /> provider for this socket.
- /// </summary>
- public SocketInterfaces.DigitalOutputIndirector DigitalOutputIndirector;
- /// <summary>
- /// The <see cref="SocketInterfaces.I2CBus" /> provider for this socket.
- /// </summary>
- public SocketInterfaces.I2CBusIndirector I2CBusIndirector;
- /// <summary>
- /// The <see cref="SocketInterfaces.InterruptInput" /> provider for this socket.
- /// </summary>
- public SocketInterfaces.InterruptInputIndirector InterruptIndirector;
- /// <summary>
- /// The <see cref="SocketInterfaces.PwmOutput" /> provider for this socket.
- /// </summary>
- public SocketInterfaces.PwmOutputIndirector PwmOutputIndirector;
- /// <summary>
- /// The <see cref="SocketInterfaces.Serial" /> provider for this socket.
- /// </summary>
- public SocketInterfaces.SerialIndirector SerialIndirector;
- /// <summary>
- /// The <see cref="SocketInterfaces.Spi" /> provider for this socket.
- /// </summary>
- public SocketInterfaces.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;
-
- /// <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.
- /// </summary>
- /// <remarks>
- /// Relies on native or hardware support for analog output provided by the mainboard manufacturer.
- /// </remarks>
- /// <returns>An instance of the SocketInterfaces.AnalogOutput class, which provides access to underlying analog output functionality.</returns>
- public SocketInterfaces.AnalogOutput AnalogOutput
- {
- get
- {
- return _AnalogOutput;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _AnalogOutput = value;
- }
- }
- private SocketInterfaces.AnalogOutput _AnalogOutput = null;
-
- /// <summary>
- /// NativeI2C functionality provided by the socket. Null if not available on this socket.
- /// </summary>
- public SocketInterfaces.NativeI2CWriteReadDelegate NativeI2CWriteRead
- {
- get
- {
- return _NativeI2CWriteRead;
- }
- set
- {
- if (_registered) throw new SocketImmutableAfterRegistrationException();
- _NativeI2CWriteRead = value;
- }
- }
- private SocketInterfaces.NativeI2CWriteReadDelegate _NativeI2CWriteRead = null;
-
- 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)
- {
- foreach (Socket socket in _sockets)
- {
- 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)
- {
- foreach (char supportedType in SupportedTypes)
- {
- if (type == supportedType) return true;
- }
-
- return false;
- }
-
- /// <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)
- {
- foreach (char type in types)
- {
- if (SupportsType(type)) 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>
- /// 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
- }
- /*
- private static ArrayList _reservedPins = new ArrayList();
-
- internal class PinReservation
- {
- public Socket ReservingSocket { get; private set; }
- public Socket.Pin ReservingPin { get; private set; }
- public Cpu.Pin CpuPin { get; private set; }
- public Module ReservingModule { get; private set; }
-
- public PinReservation(Socket socket, Socket.Pin pin, Cpu.Pin cpuPin, Module module)
- {
- ReservingSocket = socket;
- ReservingModule = module;
- ReservingPin = pin;
- CpuPin = cpuPin;
- }
- }
- */
- /// <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.
- /// Note that Gadgeteer allows mainboard pins to be reused across multiple sockets, so the reservation check also checks if the pin is used on a different socket where the pin is shared.
- /// </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)
- {
- 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;
- }
-
- /*
- // Check to see if pin is already reserved
- foreach (PinReservation reservation in _reservedPins)
- {
- if (cpuPin == reservation.CpuPin)
- {
- throw new PinConflictException(this, pin, module, reservation);
- }
- }
- */
-
- // 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')))
- {
- Module.DisplayModule.LCDControllerPinReuse();
- }
-
- //_reservedPins.Add(new PinReservation(this, pin, cpuPin, module));
- 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 there is a pin conflict.
- /// </summary>
- public class PinConflictException : ApplicationException
- {
- internal PinConflictException(Socket socket, Socket.Pin pin, Module module, PinReservation priorReservation)
- : base("\nUnable to configure the " + (module != null ? module + " " : "") + "module using socket " + socket + " (pin " + (int)pin + "). " +
- "There is a conflict with the " + (priorReservation.ReservingModule != null ? priorReservation.ReservingModule + " " : "") + "module using socket " +
- priorReservation.ReservingSocket + " (pin " + priorReservation.ReservingPin + "). Please try using a different combination of sockets.")
- { }
- }
- */
- /// <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;
-
- /// <summary>
- /// This static class contains interfaces used by mainboards to provide functionalities on sockets to Gadgeteer.
- /// End users do not need to use this class directly and should normally use GTM.Modules to access functionality.
- /// Module developers do not need to use this class directly and should normally use GT.Socket and GT.Interfaces to access the required functionality.
- /// </summary>
- public static partial class SocketInterfaces
- {
- /// <summary>
- /// Provides access to a socket's analog output functionality.
- /// </summary>
- public interface AnalogOutput
- {
- /// <summary>
- /// Specifies the minimum voltage that this analog output supports.
- /// </summary>
- double MinOutputVoltage { get; }
-
- /// <summary>
- /// Specifies the maximum voltage that this analog output supports.
- /// </summary>
- double MaxOutputVoltage { get; }
-
- /// <summary>
- /// Sets the voltage output by this analog output.
- /// </summary>
- /// <param name="value">The voltage to output</param>
- void SetVoltage(double value);
-
- /// <summary>
- /// A property to control whether the analog output functionality on this socket is active or not.
- /// </summary>
- bool Active { get; set; }
- }
- }
- }
- }