PageRenderTime 38ms CodeModel.GetById 16ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Main/GadgeteerCore/Gadgeteer43/Socket.cs

#
C# | 571 lines | 315 code | 46 blank | 210 comment | 46 complexity | e899a164d1e2b0965b9263ec4acca02f MD5 | raw file
  1////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2// Copyright (c) Microsoft Corporation.  All rights reserved.
  3////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4namespace Gadgeteer
  5{
  6    using Microsoft.SPOT.Hardware;
  7    using System;
  8    using System.Collections;
  9    using Gadgeteer.Modules;
 10    using SI = Gadgeteer.SocketInterfaces;
 11
 12    /// <summary>
 13    /// A class representing a socket, which may be on a mainboard or on an expansion module such as an SPI multiplexer.  
 14    /// </summary>
 15    /// <remarks>
 16    /// This class is normally not directly used by application programs, who refer to sockets by their socket number. 
 17    /// Modules should normally use this class and the GT.Interfaces classes to access functionality required to implement their APIs.
 18    /// Mainboards and multiplexer modules providing sockets should use this class's SocketInterfaces subclass to declare functionalities provided on their sockets.
 19    /// </remarks>
 20    public partial class Socket
 21    {
 22        /// <summary>
 23        /// The <see cref="SI.AnalogInput" /> provider for this socket.
 24        /// </summary>
 25        public SI.AnalogInputIndirector AnalogInputIndirector;
 26        /// <summary>
 27        /// The <see cref="SI.AnalogOutput" /> provider for this socket.
 28        /// </summary>
 29        public SI.AnalogOutputIndirector AnalogOutputIndirector;
 30        /// <summary>
 31        /// The <see cref="SI.DigitalInput" /> provider for this socket.
 32        /// </summary>
 33        public SI.DigitalInputIndirector DigitalInputIndirector;
 34        /// <summary>
 35        /// The <see cref="SI.DigitalIO" /> provider for this socket.
 36        /// </summary>
 37        public SI.DigitalOIndirector DigitalIOIndirector;
 38        /// <summary>
 39        /// The <see cref="SI.DigitalOutput" /> provider for this socket.
 40        /// </summary>
 41        public SI.DigitalOutputIndirector DigitalOutputIndirector;
 42        /// <summary>
 43        /// The <see cref="SI.I2CBus" /> provider for this socket.
 44        /// </summary>
 45        public SI.I2CBusIndirector I2CBusIndirector;
 46        /// <summary>
 47        /// The <see cref="SI.InterruptInput" /> provider for this socket.
 48        /// </summary>
 49        public SI.InterruptInputIndirector InterruptIndirector;
 50        /// <summary>
 51        /// The <see cref="SI.PwmOutput" /> provider for this socket.
 52        /// </summary>
 53        public SI.PwmOutputIndirector PwmOutputIndirector;
 54        /// <summary>
 55        /// The <see cref="SI.Serial" /> provider for this socket.
 56        /// </summary>
 57        public SI.SerialIndirector SerialIndirector;
 58        /// <summary>
 59        /// The <see cref="SI.Spi" /> provider for this socket.
 60        /// </summary>
 61        public SI.SpiIndirector SpiIndirector;
 62
 63        /// <summary>
 64        /// The socket number corresponding to this socket.  On mainboards, this is a positive number and is printed on the board itself. 
 65        /// For module-provided sockets (i.e. sockets you plug other modules into) this is an automatically generated negative number.
 66        /// </summary>
 67        public int SocketNumber { get; private set; }
 68
 69        /// <summary>
 70        /// The name of the socket.  This is shown to users in any socket-related error messages generated by Gadgeteer Core.
 71        /// </summary>
 72        public string Name { get; private set; }
 73
 74        /// <summary>
 75        /// 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.
 76        /// Index 0 is unused.
 77        /// </summary>
 78        public Cpu.Pin[] CpuPins { get; private set; }
 79
 80        /// <summary>
 81        /// The supported types of this socket.  
 82        /// </summary>
 83        public char[] SupportedTypes
 84        {
 85            get
 86            {
 87                return _SupportedTypes;
 88            }
 89            set
 90            {
 91                if (_registered) throw new SocketImmutableAfterRegistrationException();
 92                _SupportedTypes = value;
 93            }
 94        }
 95        private char[] _SupportedTypes = new char[] { };
 96
 97        /// <summary>
 98        /// The SPI_module corresponding to this socket.  This is Socket.SPIMissing if there is no SPI module on this socket.
 99        /// </summary>
100        public SPI.SPI_module SPIModule
101        {
102            get
103            {
104                return _SPIModule;
105            }
106            set
107            {
108                if (_registered) throw new SocketImmutableAfterRegistrationException();
109                _SPIModule = value;
110            }
111        }
112        private SPI.SPI_module _SPIModule = Socket.SocketInterfaces.SPIMissing;
113
114        /// <summary>
115        /// Returns the serial port name (e.g. "COM1") associated with a particular socket. 
116        /// </summary>
117        /// <returns>The serial port name</returns>
118        public string SerialPortName
119        {
120            get
121            {
122                return _serialPortName;
123            }
124            set
125            {
126                if (_registered) throw new SocketImmutableAfterRegistrationException();
127                _serialPortName = value;
128            }
129        }
130        private string _serialPortName = null;
131
132        /// <summary>
133        /// Provides access to pulse width modulation (PWM) functionality on a socket pin 7. 
134        /// </summary>
135        /// <returns>An instance of the Cpu.PWMChannel enumeration, which should be PWM_NONE if there is no PWM support.</returns>
136        public Cpu.PWMChannel PWM7
137        {
138            get
139            {
140                return _PWM7;
141            }
142            set
143            {
144                if (_registered) throw new SocketImmutableAfterRegistrationException();
145                _PWM7 = value;
146            }
147        }
148        private Cpu.PWMChannel _PWM7 = Cpu.PWMChannel.PWM_NONE;
149
150        /// <summary>
151        /// Provides access to pulse width modulation (PWM) functionality on a socket pin 8. 
152        /// </summary>
153        /// <returns>An instance of the Cpu.PWMChannel enumeration, which should be PWM_NONE if there is no PWM support on this socket pin.</returns>
154        public Cpu.PWMChannel PWM8
155        {
156            get
157            {
158                return _PWM8;
159            }
160            set
161            {
162                if (_registered) throw new SocketImmutableAfterRegistrationException();
163                _PWM8 = value;
164            }
165        }
166        private Cpu.PWMChannel _PWM8 = Cpu.PWMChannel.PWM_NONE;
167
168        /// <summary>
169        /// Provides access to pulse width modulation (PWM) functionality on a socket pin 9. 
170        /// </summary>
171        /// <returns>An instance of the Cpu.PWMChannel enumeration, which should be PWM_NONE if there is no PWM support on this socket pin.</returns>
172        public Cpu.PWMChannel PWM9
173        {
174            get
175            {
176                return _PWM9;
177            }
178            set
179            {
180                if (_registered) throw new SocketImmutableAfterRegistrationException();
181                _PWM9 = value;
182            }
183        }
184        private Cpu.PWMChannel _PWM9 = Cpu.PWMChannel.PWM_NONE;
185
186        internal double AnalogInputScale = double.MinValue;
187        internal double AnalogInputOffset = double.MinValue;
188        internal int AnalogInputPrecisionInBits = int.MinValue;
189
190        internal double AnalogOutputScale = double.MinValue;
191        internal double AnalogOutputOffset = double.MinValue;
192        internal int AnalogOutputPrecisionInBits = int.MinValue;
193
194        /// <summary>
195        /// Provides access to analog input functionality on a socket's pin 3.
196        /// </summary>
197        /// <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>
198        public Cpu.AnalogChannel AnalogInput3
199        {
200            get
201            {
202                return _AnalogInput3;
203            }
204            set
205            {
206                if (_registered) throw new SocketImmutableAfterRegistrationException();
207                _AnalogInput3 = value;
208            }
209        }
210        private Cpu.AnalogChannel _AnalogInput3 = Cpu.AnalogChannel.ANALOG_NONE;
211
212        /// <summary>
213        /// Provides access to analog input functionality on a socket's pin 4.
214        /// </summary>
215        /// <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>
216        public Cpu.AnalogChannel AnalogInput4
217        {
218            get
219            {
220                return _AnalogInput4;
221            }
222            set
223            {
224                if (_registered) throw new SocketImmutableAfterRegistrationException();
225                _AnalogInput4 = value;
226            }
227        }
228        private Cpu.AnalogChannel _AnalogInput4 = Cpu.AnalogChannel.ANALOG_NONE;
229
230        /// <summary>
231        /// Provides access to analog input functionality on a socket's pin 5.
232        /// </summary>
233        /// <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>
234        public Cpu.AnalogChannel AnalogInput5
235        {
236            get
237            {
238                return _AnalogInput5;
239            }
240            set
241            {
242                if (_registered) throw new SocketImmutableAfterRegistrationException();
243                _AnalogInput5 = value;
244            }
245        }
246        private Cpu.AnalogChannel _AnalogInput5 = Cpu.AnalogChannel.ANALOG_NONE;
247
248        /// <summary>
249        /// Provides access to analog output functionality on a socket's pin 5.
250        /// </summary>
251        /// <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>
252        public Cpu.AnalogOutputChannel AnalogOutput5
253        {
254            get
255            {
256                return _AnalogOutput5;
257            }
258            set
259            {
260                if (_registered) throw new SocketImmutableAfterRegistrationException();
261                _AnalogOutput5 = value;
262            }
263        }
264        private Cpu.AnalogOutputChannel _AnalogOutput5 = Cpu.AnalogOutputChannel.ANALOG_OUTPUT_NONE;
265       
266        internal static ArrayList _sockets = new ArrayList();
267
268        /// <summary>
269        /// A special socket number indicating that a module socket is not used.
270        /// </summary>
271        public static int Unused { get { return int.MinValue; } }
272
273
274        /// <summary>
275        /// Get the <see cref="Socket"/> corresponding to a socket number.
276        /// </summary>
277        /// <param name="socketNumber">The socket number</param>
278        /// <param name="throwExceptionIfSocketNumberInvalid">Whether to throw an <see cref="InvalidSocketException"/> if the socket does not exist.</param>
279        /// <param name="module">The module using this socket.</param>
280        /// <param name="socketLabel">The label on the socket, if there is more than one socket on the module (can be null).</param>
281        /// <returns>The socket corresponding to the provided socket number.</returns>
282        public static Socket GetSocket(int socketNumber, bool throwExceptionIfSocketNumberInvalid, Module module, string socketLabel)
283        {
284            if (socketLabel == "") socketLabel = null;
285
286            if (socketNumber == Socket.Unused)
287            {
288                if (throwExceptionIfSocketNumberInvalid)
289                {
290                    if (module == null)
291                    {
292                        throw new InvalidSocketException("Cannot get Socket for socket number Socket.NotConnected");
293                    }
294                    else
295                    {
296                        String errormessage = "Module " + module;
297                        if (socketLabel != null) errormessage += " socket " + socketLabel;
298                        errormessage += " must have a valid socket number specified (it does not support Socket.Unused)";
299                        throw new InvalidSocketException(errormessage);
300                    }
301                }
302                else
303                {
304                    return null;
305                }
306            }
307
308            lock (_sockets)
309            {
310                for (int i = 0; i < _sockets.Count; i++)
311                {
312                    Socket socket = (Socket)_sockets[i];
313                    if (socket.SocketNumber == socketNumber) return socket;
314                }
315            }
316            if (throwExceptionIfSocketNumberInvalid)
317            {
318                if (module == null)
319                {
320                    throw new InvalidSocketException("Invalid socket number " + socketNumber + " specified.");
321                }
322                else
323                {
324                    String errormessage = "Module " + module;
325                    if (socketLabel != null) errormessage += " socket " + socketLabel;
326                    errormessage += " cannot be used with invalid socket number " + socketNumber;
327                    throw new InvalidSocketException(errormessage);
328                }
329            }
330            return null;
331        }
332
333        internal bool _registered = false;
334
335        internal Socket(int socketNumber, string name)
336        {
337            this.Name = name;
338            this.SocketNumber = socketNumber;
339            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 };
340        }
341
342        /// <summary>
343        /// Returns the Name of this socket.
344        /// </summary>
345        /// <returns></returns>
346        public override string ToString()
347        {
348            return Name;
349        }
350
351
352        /// <summary>
353        /// Determines whether the specified socket supports the given socket type
354        /// </summary>
355        /// <param name="type">The socket type</param>
356        /// <returns></returns>
357        public bool SupportsType(char type)
358        {
359            return Array.IndexOf(_SupportedTypes, type) >= 0;
360        }
361
362        /// <summary>
363        /// 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.
364        /// </summary>
365        /// <param name="type">The socket type required.</param>
366        /// <param name="module">The module requiring this socket type (can be null).</param>
367        public void EnsureTypeIsSupported(char type, Module module)
368        {
369            if (!SupportsType(type))
370            {
371                throw new InvalidSocketException("Socket " + Name + " does not support type '" + type + "'" + (module != null ? "  required by " + module + " module." : "."));
372            }
373        }
374
375        /// <summary>
376        /// 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.
377        /// </summary>
378        /// <param name="types">The array of socket types required (any one of these is sufficient).</param>
379        /// <param name="module">The module requiring this socket type (can be null).</param>
380        public void EnsureTypeIsSupported(char[] types, Module module)
381        {
382            for (int i = 0; i < types.Length; i++)
383            {
384                if (SupportsType(types[i])) return;
385            }
386            throw new InvalidSocketException("Socket " + Name + " does not support one of the types '" + new String(types) + "'" + (module != null ? "  required by " + module + " module." : "."));
387        }
388
389        /// <summary>
390        /// An enumeration of socket pins.
391        /// </summary>
392        public enum Pin
393        {
394            /// <summary>
395            /// Not applicable
396            /// </summary>
397            None = 0,
398            /// <summary>
399            /// Socket pin 1
400            /// </summary>
401            One = 1,
402            /// <summary>
403            /// Socket pin 2
404            /// </summary>
405            Two = 2,
406            /// <summary>
407            /// Socket pin 3
408            /// </summary>
409            Three = 3,
410            /// <summary>
411            /// Socket pin 4
412            /// </summary>
413            Four = 4,
414            /// <summary>
415            /// Socket pin 5
416            /// </summary>
417            Five = 5,
418            /// <summary>
419            /// Socket pin 6
420            /// </summary>
421            Six = 6,
422            /// <summary>
423            /// Socket pin 7
424            /// </summary>
425            Seven = 7,
426            /// <summary>
427            /// Socket pin 8
428            /// </summary>
429            Eight = 8,
430            /// <summary>
431            /// Socket pin 9
432            /// </summary>
433            Nine = 9,
434            /// <summary>
435            /// Socket pin 10
436            /// </summary>
437            Ten = 10
438        }
439
440        /// <summary>
441        /// Tells GadgeteerCore that a pin is being used on this socket.
442        /// 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.
443        /// </summary>
444        /// <param name="pin">The socket pin being used</param>
445        /// <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>
446        /// <returns></returns>
447        public Cpu.Pin ReservePin(Socket.Pin pin, Module module)
448        {
449            if (pin == Pin.None)
450            {
451                return UnspecifiedPin;
452            }
453
454            Cpu.Pin cpuPin = CpuPins[(int)pin];
455            if (cpuPin == UnspecifiedPin)
456            {
457                throw new PinMissingException(this, pin);
458            }
459
460            if (cpuPin == UnnumberedPin)
461            {
462                // bypass checks, return no pin
463                return Cpu.Pin.GPIO_NONE;
464            }
465
466            // see if this is a display socket and reboot if we need to disable the LCD controller
467            if (!(module is Module.DisplayModule) && (SupportsType('R') || SupportsType('G') || SupportsType('B')))
468            {
469                Program.Mainboard.EnsureRgbSocketPinsAvailable();
470            }
471
472            return cpuPin;
473        }
474
475        /// <summary>
476        /// An exception raised when a socket pin which is unspecified by the socket provider is used.
477        /// </summary>
478        public class PinMissingException : ApplicationException
479        {
480            internal PinMissingException(Socket socket, Socket.Pin pin)
481                : base("\nPin " + (int)pin + " on socket " + socket + " is not connected to a valid CPU pin.")
482            { }
483        }
484
485        /// <summary>
486        /// An exception raised when an invalid socket is specified, e.g. a socket incompatible with the functionality required. 
487        /// </summary>
488        public class InvalidSocketException : ArgumentException
489        {
490            /// <summary>
491            /// Generates a new invalid socket exception
492            /// </summary>
493            /// <param name="message">The exception cause</param>
494            public InvalidSocketException(String message)
495                : base(message)
496            {
497            }
498
499            /// <summary>
500            /// Throws an <see cref="InvalidSocketException" /> if a pin number is not in the specified range.
501            /// </summary>
502            /// <param name="pin">The pin number to test.</param>
503            /// <param name="from">The lowest valid pin number.</param>
504            /// <param name="to">The highest valid pin number.</param>
505            /// <param name="iface">The requesting interface.</param>
506            /// <param name="module">The requesting module.</param>
507            /// <exception cref="InvalidSocketException">The <paramref name="pin" /> is out of the range specified by <paramref name="from" /> and <paramref name="to" />.</exception>
508            /// <remarks>
509            /// This method helps lowering the footprint and should be called when implementing a socket interface.
510            /// </remarks>
511            [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
512            public static void ThrowIfOutOfRange(Socket.Pin pin, Socket.Pin from, Socket.Pin to, string iface, Module module)
513            {
514                if (pin >= from && pin <= to)
515                    return;
516
517                string message = "Cannot use " + iface + " interface on pin " + pin + " - pin must be in range " + from + " to " + to + ".";
518                if (module != null)
519                    message = "Module " + module + ": ";
520
521                throw new InvalidSocketException(message);
522            }
523
524            /// <summary>
525            /// Returns an <see cref="InvalidSocketException" /> with functionality error message.
526            /// </summary>
527            /// <param name="socket">The socket that has the error.</param>
528            /// <param name="iface">The interface that is causing the error.</param>
529            /// <returns>An <see cref="InvalidSocketException" /> with functionality error message.</returns>
530            /// <remarks>
531            /// This method helps lowering the footprint and should be called when implementing a socket interface.
532            /// </remarks>
533            [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
534            public static InvalidSocketException FunctionalityException(Socket socket, string iface)
535            {
536                return new InvalidSocketException("Socket " + socket + " has an error with its " + iface + " functionality. Please try a different socket.");
537            }
538
539            /// <summary>
540            /// Generates a new invalid socket exception
541            /// </summary>
542            /// <param name="message">The exception cause</param>
543            /// <param name="e">The underlying exception</param>
544            public InvalidSocketException(String message, Exception e)
545                : base(message, e)
546            {
547            }
548        }
549
550        /// <summary>
551        /// This exception is thrown when a socket which is already registered with GadgeteerCore is then modified.
552        /// </summary>
553        public class SocketImmutableAfterRegistrationException : InvalidOperationException
554        {
555            internal SocketImmutableAfterRegistrationException()
556                : base("Socket data is immutable after socket is registered.")
557            { }
558        }
559
560        /// <summary>
561        /// A CPU pin which has no number, and for which reservation does not need to be tracked.
562        /// </summary>
563        public static readonly Cpu.Pin UnnumberedPin = (Cpu.Pin)int.MinValue;
564
565        /// <summary>
566        /// An unspecified CPU pin (e.g. for a socket which does not use this pin).
567        /// </summary>
568        public static readonly Cpu.Pin UnspecifiedPin = Cpu.Pin.GPIO_NONE;
569    }
570
571}