/PLATFORM/GumstixIII_BIN/VSProjects/GumstixManagedAPI/I2C.cs

# · C# · 462 lines · 343 code · 63 blank · 56 comment · 10 complexity · fc59e62eebb13c5b65dd0d4cd30b925f MD5 · raw file

  1. using System;
  2. using System.IO;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Runtime.InteropServices;
  6. using Gumstix;
  7. using OpenNETCF.IO;
  8. namespace Gumstix
  9. {
  10. public class I2C : StreamInterfaceDriver
  11. {
  12. #region I2C device IOCTL codes
  13. private enum RW : byte
  14. {
  15. WRITE = 1,
  16. READ
  17. }
  18. private const Int32 FILE_DEVICE_BUS_EXTENDER = 0x0000002a;
  19. private const Int32 FILE_ANY_ACCESS = 0x0;
  20. private const Int32 METHOD_BUFFERED = 0x0;
  21. private const Int32 CODE_IOCTL_SET_SLAVE_MODE = 3000; // Set I2C Bus to Slave Mode
  22. private const Int32 CODE_IOCTL_SET_MASTER_MODE = 3001; // Set I2C Bus to Master Mode
  23. private const Int32 CODE_IOCTL_IS_MASTER = 3002; // Is it in Master Mode?
  24. private const Int32 CODE_IOCTL_IS_SLAVE = 3003; // Is it in Slave Mode?
  25. private const Int32 CODE_IOCTL_SET_FAST_BUS = 3004; // Set Fast Bus Mode
  26. private const Int32 CODE_IOCTL_IS_FAST_BUS = 3005; // Is it in Fast Bus Mode?
  27. private const Int32 CODE_IOCTL_SET_SELF_ADDR = 3007; // Set My Address (Slave Mode)
  28. private const Int32 CODE_IOCTL_GET_SELF_ADDR = 3008; // Get My Address (Slave Mode)
  29. private const Int32 CODE_IOCTL_TRANSFER = 3009; // Transfer Data
  30. private const Int32 CODE_IOCTL_RESET = 3010; // Software Reset
  31. private const Int32 CODE_IOCTL_TRANSFER2 = 3015; // Transfer Data type 2
  32. private const Int32 IOCTL_SET_SLAVE_MODE =
  33. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  34. | ((CODE_IOCTL_SET_SLAVE_MODE) << 2) | (METHOD_BUFFERED);
  35. private const Int32 IOCTL_SET_MASTER_MODE =
  36. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  37. | ((CODE_IOCTL_SET_MASTER_MODE) << 2) | (METHOD_BUFFERED);
  38. private const Int32 IOCTL_IS_MASTER =
  39. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  40. | ((CODE_IOCTL_IS_MASTER) << 2) | (METHOD_BUFFERED);
  41. private const Int32 IOCTL_IS_SLAVE =
  42. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  43. | ((CODE_IOCTL_IS_SLAVE) << 2) | (METHOD_BUFFERED);
  44. private const Int32 IOCTL_SET_FAST_BUS =
  45. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  46. | ((CODE_IOCTL_SET_FAST_BUS) << 2) | (METHOD_BUFFERED);
  47. private const Int32 IOCTL_IS_FAST_BUS =
  48. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  49. | ((CODE_IOCTL_IS_FAST_BUS) << 2) | (METHOD_BUFFERED);
  50. private const Int32 IOCTL_SET_SELF_ADDR =
  51. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  52. | ((CODE_IOCTL_SET_SELF_ADDR) << 2) | (METHOD_BUFFERED);
  53. private const Int32 IOCTL_GET_SELF_ADDR =
  54. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  55. | ((CODE_IOCTL_GET_SELF_ADDR) << 2) | (METHOD_BUFFERED);
  56. private const Int32 IOCTL_TRANSFER =
  57. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  58. | ((CODE_IOCTL_TRANSFER) << 2) | (METHOD_BUFFERED);
  59. private const Int32 IOCTL_TRANSFER2 =
  60. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  61. | ((CODE_IOCTL_TRANSFER2) << 2) | (METHOD_BUFFERED);
  62. private const Int32 IOCTL_RESET =
  63. ((FILE_DEVICE_BUS_EXTENDER) << 16) | ((FILE_ANY_ACCESS) << 14)
  64. | ((CODE_IOCTL_RESET) << 2) | (METHOD_BUFFERED);
  65. #endregion
  66. #region Native interface structures
  67. [StructLayout(LayoutKind.Sequential)]
  68. private struct Packet
  69. {
  70. public byte slaveAddress; // I2C slave device address for this I2C operation
  71. public RW readWrite; // Read = I2C_READ or Write = I2C_WRITE
  72. public IntPtr buffer;
  73. public UInt16 length;
  74. public IntPtr result; // Contains the result of last operation
  75. public Packet(byte slaveAddress, RW readWrite, IntPtr data, int dataLength, IntPtr result)
  76. {
  77. this.slaveAddress = slaveAddress;
  78. this.readWrite = readWrite;
  79. this.buffer = data;
  80. this.length = (UInt16)dataLength;
  81. this.result = result;
  82. }
  83. }
  84. #endregion
  85. #region ctor / dtor
  86. /// <summary>
  87. /// Provides access to the I2C bus on the PXA270.
  88. /// </summary>
  89. public I2C() : base("I2C1:")
  90. {
  91. // open the driver
  92. Open(FileAccess.ReadWrite, FileShare.ReadWrite);
  93. }
  94. ~I2C()
  95. {
  96. // close the driver
  97. Close();
  98. }
  99. #endregion
  100. #region error handler
  101. private void BusError(Int32 result)
  102. {
  103. switch (result)
  104. {
  105. case -7:
  106. throw new Exception("No Acknowledge Issued:" + Marshal.GetLastWin32Error());
  107. case -8:
  108. throw new Exception("NULL Buffer:" + Marshal.GetLastWin32Error());
  109. case -9:
  110. throw new Exception("Invalid Buffer Size:" + Marshal.GetLastWin32Error());
  111. case -10:
  112. throw new Exception("NULL lpiResult field:" + Marshal.GetLastWin32Error());
  113. case -11:
  114. throw new Exception("CRM Operation Failure:" + Marshal.GetLastWin32Error());
  115. case -12:
  116. throw new Exception("I2C transmit timeout error:" + Marshal.GetLastWin32Error());
  117. case -13:
  118. throw new Exception("I2C arbitration lost error:" + Marshal.GetLastWin32Error());
  119. }
  120. }
  121. #endregion
  122. #region transfer
  123. /// <summary>
  124. /// Transfer one byte of data to the I2C bus
  125. /// </summary>
  126. /// <param name="address">Slave address</param>
  127. /// <param name="data">Data byte</param>
  128. public void Write(byte address, byte data)
  129. {
  130. Int32 result = 0;
  131. IntPtr pResult = Marshal.AllocHGlobal(Marshal.SizeOf(result));
  132. int rawsize = Marshal.SizeOf(data);
  133. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  134. Marshal.StructureToPtr(data, buffer, false);
  135. Packet packet = new Packet(address, RW.WRITE, buffer, rawsize, pResult);
  136. try
  137. {
  138. this.DeviceIoControl(IOCTL_TRANSFER2, SerializeToByteArray(packet), null);
  139. result = (Int32)Marshal.PtrToStructure(pResult, typeof(Int32));
  140. if (result < 0)
  141. BusError(result);
  142. }
  143. catch (Exception)
  144. {
  145. throw new Exception("Unable to complete I2C transaction:" + Marshal.GetLastWin32Error());
  146. }
  147. finally
  148. {
  149. Marshal.FreeHGlobal(buffer);
  150. Marshal.FreeHGlobal(pResult);
  151. }
  152. }
  153. /// <summary>
  154. /// Transfer two bytes (MSB first) to the I2C bus
  155. /// </summary>
  156. /// <param name="address">Slave address</param>
  157. /// <param name="data">MSB transfered first</param>
  158. public void Write(byte address, UInt16 data)
  159. {
  160. Int32 result = 0;
  161. IntPtr pResult = Marshal.AllocHGlobal(Marshal.SizeOf(result));
  162. int rawsize = Marshal.SizeOf(data);
  163. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  164. Marshal.StructureToPtr(data, buffer, false);
  165. Packet packet = new Packet(address, RW.WRITE, buffer, rawsize, pResult);
  166. try
  167. {
  168. this.DeviceIoControl(IOCTL_TRANSFER2, SerializeToByteArray(packet), null);
  169. result = (Int32)Marshal.PtrToStructure(pResult, typeof(Int32));
  170. if (result < 0)
  171. BusError(result);
  172. }
  173. catch (Exception)
  174. {
  175. throw new Exception("Unable to complete I2C transaction:" + Marshal.GetLastWin32Error());
  176. }
  177. finally
  178. {
  179. Marshal.FreeHGlobal(buffer);
  180. Marshal.FreeHGlobal(pResult);
  181. }
  182. }
  183. /// <summary>
  184. /// Transfer four bytes (MSB first) to the I2C bus
  185. /// </summary>
  186. /// <param name="address">Slave address</param>
  187. /// <param name="data">MSB transfered first</param>
  188. public void Write(byte address, UInt32 data)
  189. {
  190. Int32 result = 0;
  191. IntPtr pResult = Marshal.AllocHGlobal(Marshal.SizeOf(result));
  192. int rawsize = Marshal.SizeOf(data);
  193. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  194. Marshal.StructureToPtr(data, buffer, false);
  195. Packet packet = new Packet(address, RW.WRITE, buffer, rawsize, pResult);
  196. try
  197. {
  198. this.DeviceIoControl(IOCTL_TRANSFER2, SerializeToByteArray(packet), null);
  199. result = (Int32)Marshal.PtrToStructure(pResult, typeof(Int32));
  200. if (result < 0)
  201. BusError(result);
  202. }
  203. catch (Exception)
  204. {
  205. throw new Exception("Unable to complete I2C transaction:" + Marshal.GetLastWin32Error());
  206. }
  207. finally
  208. {
  209. Marshal.FreeHGlobal(buffer);
  210. Marshal.FreeHGlobal(pResult);
  211. }
  212. }
  213. /// <summary>
  214. /// Transfer eight bytes (MSB first) to the I2C bus
  215. /// </summary>
  216. /// <param name="address">Slave address</param>
  217. /// <param name="data">MSB transfered first</param>
  218. public void Write(byte address, UInt64 data)
  219. {
  220. Int32 result = 0;
  221. IntPtr pResult = Marshal.AllocHGlobal(Marshal.SizeOf(result));
  222. int rawsize = Marshal.SizeOf(data);
  223. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  224. Marshal.StructureToPtr(data, buffer, false);
  225. Packet packet = new Packet(address, RW.WRITE, buffer, rawsize, pResult);
  226. try
  227. {
  228. this.DeviceIoControl(IOCTL_TRANSFER2, SerializeToByteArray(packet), null);
  229. result = (Int32)Marshal.PtrToStructure(pResult, typeof(Int32));
  230. if (result < 0)
  231. BusError(result);
  232. }
  233. catch (Exception)
  234. {
  235. throw new Exception("Unable to complete I2C transaction:" + Marshal.GetLastWin32Error());
  236. }
  237. finally
  238. {
  239. Marshal.FreeHGlobal(buffer);
  240. Marshal.FreeHGlobal(pResult);
  241. }
  242. }
  243. /// <summary>
  244. /// Read one byte of data from the I2C bus
  245. /// </summary>
  246. /// <param name="address">Slave address</param>
  247. /// <param name="data">reference to data byte</param>
  248. public void Read(byte address, ref byte data)
  249. {
  250. Int32 result = 0;
  251. IntPtr pResult = Marshal.AllocHGlobal(Marshal.SizeOf(result));
  252. int rawsize = Marshal.SizeOf(data);
  253. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  254. Packet packet = new Packet(address, RW.READ, buffer, rawsize, pResult);
  255. try
  256. {
  257. this.DeviceIoControl(IOCTL_TRANSFER2, SerializeToByteArray(packet), null);
  258. data = (Byte)Marshal.PtrToStructure(buffer, typeof(Byte));
  259. result = (Int32)Marshal.PtrToStructure(pResult, typeof(Int32));
  260. if (result < 0)
  261. BusError(result);
  262. }
  263. catch (Exception)
  264. {
  265. throw new Exception("Unable to complete I2C transaction:" + Marshal.GetLastWin32Error());
  266. }
  267. finally
  268. {
  269. Marshal.FreeHGlobal(buffer);
  270. Marshal.FreeHGlobal(pResult);
  271. }
  272. }
  273. /// <summary>
  274. /// Read two bytes from the I2C bus
  275. /// </summary>
  276. /// <param name="address">Slave address</param>
  277. /// <param name="data">reference to data word MSB contains first read byte</param>
  278. public void Read(byte address, ref UInt16 data)
  279. {
  280. Int32 result = 0;
  281. IntPtr pResult = Marshal.AllocHGlobal(Marshal.SizeOf(result));
  282. int rawsize = Marshal.SizeOf(data);
  283. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  284. Packet packet = new Packet(address, RW.READ, buffer, rawsize, pResult);
  285. try
  286. {
  287. this.DeviceIoControl(IOCTL_TRANSFER2, SerializeToByteArray(packet), null);
  288. data = (UInt16)Marshal.PtrToStructure(buffer, typeof(UInt16));
  289. result = (Int32)Marshal.PtrToStructure(pResult, typeof(Int32));
  290. if (result < 0)
  291. BusError(result);
  292. }
  293. catch (Exception)
  294. {
  295. throw new Exception("Unable to complete I2C transaction:" + Marshal.GetLastWin32Error());
  296. }
  297. finally
  298. {
  299. Marshal.FreeHGlobal(buffer);
  300. Marshal.FreeHGlobal(pResult);
  301. }
  302. }
  303. /// <summary>
  304. /// Read four bytes from the I2C bus
  305. /// </summary>
  306. /// <param name="address">Slave address</param>
  307. /// <param name="data">reference to data dword MSB contains first read byte</param>
  308. public void Read(byte address, ref UInt32 data)
  309. {
  310. Int32 result = 0;
  311. IntPtr pResult = Marshal.AllocHGlobal(Marshal.SizeOf(result));
  312. int rawsize = Marshal.SizeOf(data);
  313. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  314. Packet packet = new Packet(address, RW.READ, buffer, rawsize, pResult);
  315. try
  316. {
  317. this.DeviceIoControl(IOCTL_TRANSFER2, SerializeToByteArray(packet), null);
  318. data = (UInt32)Marshal.PtrToStructure(buffer, typeof(UInt32));
  319. result = (Int32)Marshal.PtrToStructure(pResult, typeof(Int32));
  320. if (result < 0)
  321. BusError(result);
  322. }
  323. catch (Exception)
  324. {
  325. throw new Exception("Unable to complete I2C transaction:" + Marshal.GetLastWin32Error());
  326. }
  327. finally
  328. {
  329. Marshal.FreeHGlobal(buffer);
  330. Marshal.FreeHGlobal(pResult);
  331. }
  332. }
  333. /// <summary>
  334. /// Read eight bytes from the I2C bus
  335. /// </summary>
  336. /// <param name="address">Slave address</param>
  337. /// <param name="data">reference to data qword MSB contains first read byte</param>
  338. public void Read(byte address, ref UInt64 data)
  339. {
  340. Int32 result = 0;
  341. IntPtr pResult = Marshal.AllocHGlobal(Marshal.SizeOf(result));
  342. int rawsize = Marshal.SizeOf(data);
  343. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  344. Packet packet = new Packet(address, RW.READ, buffer, rawsize, pResult);
  345. try
  346. {
  347. this.DeviceIoControl(IOCTL_TRANSFER2, SerializeToByteArray(packet), null);
  348. data = (UInt64)Marshal.PtrToStructure(buffer, typeof(UInt64));
  349. result = (Int32)Marshal.PtrToStructure(pResult, typeof(Int32));
  350. if (result < 0)
  351. BusError(result);
  352. }
  353. catch (Exception)
  354. {
  355. throw new Exception("Unable to complete I2C transaction:" + Marshal.GetLastWin32Error());
  356. }
  357. finally
  358. {
  359. Marshal.FreeHGlobal(buffer);
  360. Marshal.FreeHGlobal(pResult);
  361. }
  362. }
  363. #endregion
  364. #region P/Invoke helpers
  365. /// <summary>
  366. /// Byte array serializer
  367. /// </summary>
  368. /// <param name="anything"></param>
  369. /// <returns></returns>
  370. private static byte[] SerializeToByteArray(object anything)
  371. {
  372. int rawsize = Marshal.SizeOf(anything);
  373. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  374. Marshal.StructureToPtr(anything, buffer, false);
  375. byte[] rawdatas = new byte[rawsize];
  376. Marshal.Copy(buffer, rawdatas, 0, rawsize);
  377. Marshal.FreeHGlobal(buffer);
  378. return rawdatas;
  379. }
  380. /// <summary>
  381. /// De-serializer from byte array
  382. /// </summary>
  383. /// <param name="rawdatas"></param>
  384. /// <param name="anytype"></param>
  385. /// <returns></returns>
  386. private static object DeserializeFromByteArray(byte[] rawdatas, Type anytype)
  387. {
  388. int rawsize = Marshal.SizeOf(anytype);
  389. if (rawsize > rawdatas.Length)
  390. return null;
  391. IntPtr buffer = Marshal.AllocHGlobal(rawsize);
  392. Marshal.Copy(rawdatas, 0, buffer, rawsize);
  393. object retobj = Marshal.PtrToStructure(buffer, anytype);
  394. Marshal.FreeHGlobal(buffer);
  395. return retobj;
  396. }
  397. #endregion
  398. }
  399. }