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