repo time
Dependencies: mbed MAX14720 MAX30205 USBDevice
HspGuiSourceV301/GuiDLLs/RPCSupport/HidSupport/HID.cs@20:6d2af70c92ab, 2021-04-06 (annotated)
- Committer:
- darienf
- Date:
- Tue Apr 06 06:41:40 2021 +0000
- Revision:
- 20:6d2af70c92ab
another repo
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
darienf | 20:6d2af70c92ab | 1 | /******************************************************************************* |
darienf | 20:6d2af70c92ab | 2 | * Copyright (C) 2016 Maxim Integrated Products, Inc., All rights Reserved. |
darienf | 20:6d2af70c92ab | 3 | * |
darienf | 20:6d2af70c92ab | 4 | * This software is protected by copyright laws of the United States and |
darienf | 20:6d2af70c92ab | 5 | * of foreign countries. This material may also be protected by patent laws |
darienf | 20:6d2af70c92ab | 6 | * and technology transfer regulations of the United States and of foreign |
darienf | 20:6d2af70c92ab | 7 | * countries. This software is furnished under a license agreement and/or a |
darienf | 20:6d2af70c92ab | 8 | * nondisclosure agreement and may only be used or reproduced in accordance |
darienf | 20:6d2af70c92ab | 9 | * with the terms of those agreements. Dissemination of this information to |
darienf | 20:6d2af70c92ab | 10 | * any party or parties not specified in the license agreement and/or |
darienf | 20:6d2af70c92ab | 11 | * nondisclosure agreement is expressly prohibited. |
darienf | 20:6d2af70c92ab | 12 | * |
darienf | 20:6d2af70c92ab | 13 | * The above copyright notice and this permission notice shall be included |
darienf | 20:6d2af70c92ab | 14 | * in all copies or substantial portions of the Software. |
darienf | 20:6d2af70c92ab | 15 | * |
darienf | 20:6d2af70c92ab | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
darienf | 20:6d2af70c92ab | 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
darienf | 20:6d2af70c92ab | 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
darienf | 20:6d2af70c92ab | 19 | * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES |
darienf | 20:6d2af70c92ab | 20 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
darienf | 20:6d2af70c92ab | 21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
darienf | 20:6d2af70c92ab | 22 | * OTHER DEALINGS IN THE SOFTWARE. |
darienf | 20:6d2af70c92ab | 23 | * |
darienf | 20:6d2af70c92ab | 24 | * Except as contained in this notice, the name of Maxim Integrated |
darienf | 20:6d2af70c92ab | 25 | * Products, Inc. shall not be used except as stated in the Maxim Integrated |
darienf | 20:6d2af70c92ab | 26 | * Products, Inc. Branding Policy. |
darienf | 20:6d2af70c92ab | 27 | * |
darienf | 20:6d2af70c92ab | 28 | * The mere transfer of this software does not imply any licenses |
darienf | 20:6d2af70c92ab | 29 | * of trade secrets, proprietary technology, copyrights, patents, |
darienf | 20:6d2af70c92ab | 30 | * trademarks, maskwork rights, or any other form of intellectual |
darienf | 20:6d2af70c92ab | 31 | * property whatsoever. Maxim Integrated Products, Inc. retains all |
darienf | 20:6d2af70c92ab | 32 | * ownership rights. |
darienf | 20:6d2af70c92ab | 33 | ******************************************************************************* |
darienf | 20:6d2af70c92ab | 34 | */ |
darienf | 20:6d2af70c92ab | 35 | |
darienf | 20:6d2af70c92ab | 36 | using System; |
darienf | 20:6d2af70c92ab | 37 | using System.Collections; |
darienf | 20:6d2af70c92ab | 38 | using System.Threading; |
darienf | 20:6d2af70c92ab | 39 | using System.IO; |
darienf | 20:6d2af70c92ab | 40 | using System.Windows.Forms; |
darienf | 20:6d2af70c92ab | 41 | using System.Runtime.InteropServices; |
darienf | 20:6d2af70c92ab | 42 | using Microsoft.Win32.SafeHandles; |
darienf | 20:6d2af70c92ab | 43 | using System.Text; |
darienf | 20:6d2af70c92ab | 44 | |
darienf | 20:6d2af70c92ab | 45 | //------------------------------------------------------------------------------------------ |
darienf | 20:6d2af70c92ab | 46 | // OS24EVK-59 split into HeartRateApp EXE and MAX30101 DLL. |
darienf | 20:6d2af70c92ab | 47 | // Moved all MAX30101 DLL classes into namespace Maxim.MAX30101GUI |
darienf | 20:6d2af70c92ab | 48 | // Moved all HeartRateApp GUI classes into namespace Maxim.MAX30101 |
darienf | 20:6d2af70c92ab | 49 | // OS24EVK-59 Create separate project that builds Maxim.MAX30101GUI DLL library |
darienf | 20:6d2af70c92ab | 50 | |
darienf | 20:6d2af70c92ab | 51 | // OS24EVK-59 moved class HID into namespace Maxim.MAX30101 instead of namespace HeartRateApp |
darienf | 20:6d2af70c92ab | 52 | namespace RPCSupport |
darienf | 20:6d2af70c92ab | 53 | { |
darienf | 20:6d2af70c92ab | 54 | #pragma warning disable 1574 |
darienf | 20:6d2af70c92ab | 55 | /// <summary> |
darienf | 20:6d2af70c92ab | 56 | /// USB Human Interface Device functions to connect to EV kit without requiring a custom device driver |
darienf | 20:6d2af70c92ab | 57 | /// </summary> |
darienf | 20:6d2af70c92ab | 58 | #pragma warning restore 1574 |
darienf | 20:6d2af70c92ab | 59 | internal class HID |
darienf | 20:6d2af70c92ab | 60 | { |
darienf | 20:6d2af70c92ab | 61 | |
darienf | 20:6d2af70c92ab | 62 | #region Globals |
darienf | 20:6d2af70c92ab | 63 | private IntPtr EventObject; |
darienf | 20:6d2af70c92ab | 64 | private System.Threading.NativeOverlapped managedOverlapped; |
darienf | 20:6d2af70c92ab | 65 | private IntPtr nonManagedOverlapped; |
darienf | 20:6d2af70c92ab | 66 | private IntPtr nonManagedBuffer; |
darienf | 20:6d2af70c92ab | 67 | public SafeFileHandle writeHandle; |
darienf | 20:6d2af70c92ab | 68 | public ArrayList writeHandleArray = new ArrayList(); |
darienf | 20:6d2af70c92ab | 69 | public SafeFileHandle readHandle; |
darienf | 20:6d2af70c92ab | 70 | public ArrayList readHandleArray = new ArrayList(); |
darienf | 20:6d2af70c92ab | 71 | public ArrayList desiredHIDPathNameArray = new ArrayList(); |
darienf | 20:6d2af70c92ab | 72 | |
darienf | 20:6d2af70c92ab | 73 | public const int DEFAULT_VENDOR_ID = 0x0B6A; // update USB VID PID from default Vid_16C0&Pid_0830 |
darienf | 20:6d2af70c92ab | 74 | public const int DEFAULT_PRODUCT_ID = 0x1366; // MAX30100EVKit USB Vid_0B6A&Pid_1364; MAX30101EVKit USB Vid_0B6A&Pid_1365 |
darienf | 20:6d2af70c92ab | 75 | public const byte DEFAULT_I2C_ADDRESS = 0xAE; // 8-bit address (write address) |
darienf | 20:6d2af70c92ab | 76 | |
darienf | 20:6d2af70c92ab | 77 | public String deviceID = System.String.Format("Vid_{0:x4}&Pid_{1:x4}", DEFAULT_VENDOR_ID, DEFAULT_PRODUCT_ID); |
darienf | 20:6d2af70c92ab | 78 | |
darienf | 20:6d2af70c92ab | 79 | private bool explicit_report_id = false; |
darienf | 20:6d2af70c92ab | 80 | private const byte DEFAULT_REPORT_ID = 0; |
darienf | 20:6d2af70c92ab | 81 | private const byte SHORT_REPORT_ID = 1; |
darienf | 20:6d2af70c92ab | 82 | public const byte HID_REPORT_ID_1 = 1; // MAX30101 optical data, 3 bytes per channel, up to 3 channels per sample |
darienf | 20:6d2af70c92ab | 83 | public const byte HID_REPORT_ID_2 = 2; // LIS2DH accelerometer data, 2 bytes per channel, 3 channels per sample |
darienf | 20:6d2af70c92ab | 84 | public const byte HID_REPORT_ID_3 = 3; // reserved |
darienf | 20:6d2af70c92ab | 85 | private const byte USB_OVERFLOW = 8; |
darienf | 20:6d2af70c92ab | 86 | private const byte USB_WRITE_ERROR = 4; |
darienf | 20:6d2af70c92ab | 87 | private const byte USB_READ_ERROR = 2; |
darienf | 20:6d2af70c92ab | 88 | public const byte I2C_NACK_ERROR = 1; |
darienf | 20:6d2af70c92ab | 89 | private const byte API_FAIL = 0; //API functions return non-0 upon success, to easily denote 'true' for C programs |
darienf | 20:6d2af70c92ab | 90 | private const byte I2C_SUCCESS = 3; //we'll also use a non-0 value to denote success, since returning a '0' would lead to trouble when mixed with API's returns. |
darienf | 20:6d2af70c92ab | 91 | private const byte GP_SUCCESS = 3; |
darienf | 20:6d2af70c92ab | 92 | private const byte GP_FAIL = 0; |
darienf | 20:6d2af70c92ab | 93 | private const byte REPORT_SIZE = 65; |
darienf | 20:6d2af70c92ab | 94 | |
darienf | 20:6d2af70c92ab | 95 | #region I2C clock speeds |
darienf | 20:6d2af70c92ab | 96 | public const byte I2C_ClOCK_100KHz = 0; |
darienf | 20:6d2af70c92ab | 97 | public const byte I2C_ClOCK_400KHz = 1; |
darienf | 20:6d2af70c92ab | 98 | public const byte I2C_ClOCK_1MHz = 2; |
darienf | 20:6d2af70c92ab | 99 | |
darienf | 20:6d2af70c92ab | 100 | #endregion |
darienf | 20:6d2af70c92ab | 101 | |
darienf | 20:6d2af70c92ab | 102 | #region Command Codes |
darienf | 20:6d2af70c92ab | 103 | private const byte COMMAND_SUCCESS = 0xEE; |
darienf | 20:6d2af70c92ab | 104 | private const byte COMMAND_FAILED = 0xFF; |
darienf | 20:6d2af70c92ab | 105 | |
darienf | 20:6d2af70c92ab | 106 | private const byte GET_FIRMWARE_VERSION = 0x00; |
darienf | 20:6d2af70c92ab | 107 | private const byte SET_LED = 0x01; |
darienf | 20:6d2af70c92ab | 108 | private const byte I2C_INIT = 0x03; |
darienf | 20:6d2af70c92ab | 109 | private const byte I2C_CONFIG = 0x04; |
darienf | 20:6d2af70c92ab | 110 | private const byte I2C_TRANSACTION = 0x06; |
darienf | 20:6d2af70c92ab | 111 | #endregion |
darienf | 20:6d2af70c92ab | 112 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] before FlushQueue() |
darienf | 20:6d2af70c92ab | 113 | // mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 114 | // mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 115 | public static Mutex mutexGuardIOBuf = new Mutex(); |
darienf | 20:6d2af70c92ab | 116 | // TODO1: OS24EVK-57 2015-04-01 myHID.readHID2() needs to return result into IOBuf. But IOBuf = new byte[64], do we replace with IOBuf = new byte[128]? Does this affect readHID()? |
darienf | 20:6d2af70c92ab | 117 | public byte[] IOBuf = new byte[REPORT_SIZE]; |
darienf | 20:6d2af70c92ab | 118 | |
darienf | 20:6d2af70c92ab | 119 | private const int IOtimeout = 10000; |
darienf | 20:6d2af70c92ab | 120 | |
darienf | 20:6d2af70c92ab | 121 | // API declarations relating to device management (SetupDixxx and |
darienf | 20:6d2af70c92ab | 122 | // RegisterDeviceNotification functions). |
darienf | 20:6d2af70c92ab | 123 | |
darienf | 20:6d2af70c92ab | 124 | // from dbt.h |
darienf | 20:6d2af70c92ab | 125 | |
darienf | 20:6d2af70c92ab | 126 | internal const Int32 DBT_DEVNODES_CHANGED = 7; |
darienf | 20:6d2af70c92ab | 127 | internal const Int32 DBT_DEVICEARRIVAL = 0X8000; |
darienf | 20:6d2af70c92ab | 128 | internal const Int32 DBT_DEVICEREMOVECOMPLETE = 0X8004; |
darienf | 20:6d2af70c92ab | 129 | internal const Int32 DBT_DEVTYP_DEVICEINTERFACE = 5; |
darienf | 20:6d2af70c92ab | 130 | internal const Int32 DBT_DEVTYP_HANDLE = 6; |
darienf | 20:6d2af70c92ab | 131 | internal const Int32 DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 4; |
darienf | 20:6d2af70c92ab | 132 | internal const Int32 DEVICE_NOTIFY_SERVICE_HANDLE = 1; |
darienf | 20:6d2af70c92ab | 133 | internal const Int32 DEVICE_NOTIFY_WINDOW_HANDLE = 0; |
darienf | 20:6d2af70c92ab | 134 | internal const Int32 WM_DEVICECHANGE = 0X219; |
darienf | 20:6d2af70c92ab | 135 | internal const Int32 SPDRP_HARDWAREID = 1; |
darienf | 20:6d2af70c92ab | 136 | |
darienf | 20:6d2af70c92ab | 137 | // from setupapi.h |
darienf | 20:6d2af70c92ab | 138 | |
darienf | 20:6d2af70c92ab | 139 | internal const Int32 DIGCF_PRESENT = 2; |
darienf | 20:6d2af70c92ab | 140 | internal const Int32 DIGCF_DEVICEINTERFACE = 0X10; |
darienf | 20:6d2af70c92ab | 141 | #endregion |
darienf | 20:6d2af70c92ab | 142 | |
darienf | 20:6d2af70c92ab | 143 | #region Variable Stuctures |
darienf | 20:6d2af70c92ab | 144 | // Two declarations for the DEV_BROADCAST_DEVICEINTERFACE structure. |
darienf | 20:6d2af70c92ab | 145 | |
darienf | 20:6d2af70c92ab | 146 | // Use this one in the call to RegisterDeviceNotification() and |
darienf | 20:6d2af70c92ab | 147 | // in checking dbch_devicetype in a DEV_BROADCAST_HDR structure: |
darienf | 20:6d2af70c92ab | 148 | |
darienf | 20:6d2af70c92ab | 149 | [StructLayout(LayoutKind.Sequential)] |
darienf | 20:6d2af70c92ab | 150 | internal class DEV_BROADCAST_DEVICEINTERFACE |
darienf | 20:6d2af70c92ab | 151 | { |
darienf | 20:6d2af70c92ab | 152 | internal Int32 dbcc_size; |
darienf | 20:6d2af70c92ab | 153 | internal Int32 dbcc_devicetype; |
darienf | 20:6d2af70c92ab | 154 | internal Int32 dbcc_reserved; |
darienf | 20:6d2af70c92ab | 155 | internal Guid dbcc_classguid; |
darienf | 20:6d2af70c92ab | 156 | internal Int16 dbcc_name; |
darienf | 20:6d2af70c92ab | 157 | } |
darienf | 20:6d2af70c92ab | 158 | |
darienf | 20:6d2af70c92ab | 159 | // Use this to read the dbcc_name String and classguid: |
darienf | 20:6d2af70c92ab | 160 | |
darienf | 20:6d2af70c92ab | 161 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] |
darienf | 20:6d2af70c92ab | 162 | internal class DEV_BROADCAST_DEVICEINTERFACE_1 |
darienf | 20:6d2af70c92ab | 163 | { |
darienf | 20:6d2af70c92ab | 164 | internal Int32 dbcc_size; |
darienf | 20:6d2af70c92ab | 165 | internal Int32 dbcc_devicetype; |
darienf | 20:6d2af70c92ab | 166 | internal Int32 dbcc_reserved; |
darienf | 20:6d2af70c92ab | 167 | [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)] |
darienf | 20:6d2af70c92ab | 168 | internal Byte[] dbcc_classguid; |
darienf | 20:6d2af70c92ab | 169 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)] |
darienf | 20:6d2af70c92ab | 170 | internal Char[] dbcc_name; |
darienf | 20:6d2af70c92ab | 171 | } |
darienf | 20:6d2af70c92ab | 172 | |
darienf | 20:6d2af70c92ab | 173 | [StructLayout(LayoutKind.Sequential)] |
darienf | 20:6d2af70c92ab | 174 | internal class DEV_BROADCAST_HDR |
darienf | 20:6d2af70c92ab | 175 | { |
darienf | 20:6d2af70c92ab | 176 | internal Int32 dbch_size; |
darienf | 20:6d2af70c92ab | 177 | internal Int32 dbch_devicetype; |
darienf | 20:6d2af70c92ab | 178 | internal Int32 dbch_reserved; |
darienf | 20:6d2af70c92ab | 179 | } |
darienf | 20:6d2af70c92ab | 180 | |
darienf | 20:6d2af70c92ab | 181 | internal struct SP_DEVICE_INTERFACE_DATA |
darienf | 20:6d2af70c92ab | 182 | { |
darienf | 20:6d2af70c92ab | 183 | internal Int32 cbSize; |
darienf | 20:6d2af70c92ab | 184 | internal System.Guid InterfaceClassGuid; |
darienf | 20:6d2af70c92ab | 185 | internal Int32 Flags; |
darienf | 20:6d2af70c92ab | 186 | internal IntPtr Reserved; |
darienf | 20:6d2af70c92ab | 187 | } |
darienf | 20:6d2af70c92ab | 188 | |
darienf | 20:6d2af70c92ab | 189 | //[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] |
darienf | 20:6d2af70c92ab | 190 | //internal struct SP_DEVICE_INTERFACE_DETAIL_DATA |
darienf | 20:6d2af70c92ab | 191 | //{ |
darienf | 20:6d2af70c92ab | 192 | // internal Int32 cbSize; |
darienf | 20:6d2af70c92ab | 193 | // //internal String DevicePath; |
darienf | 20:6d2af70c92ab | 194 | // internal Char[] DevicePath; |
darienf | 20:6d2af70c92ab | 195 | //} |
darienf | 20:6d2af70c92ab | 196 | |
darienf | 20:6d2af70c92ab | 197 | // warning CS0649: Field 'Maxim.MAX30101.HID.SP_DEVINFO_DATA.cbSize' is never assigned to, and will always have its default value 0 |
darienf | 20:6d2af70c92ab | 198 | #pragma warning disable 0649 |
darienf | 20:6d2af70c92ab | 199 | internal struct SP_DEVINFO_DATA |
darienf | 20:6d2af70c92ab | 200 | { |
darienf | 20:6d2af70c92ab | 201 | internal Int32 cbSize; |
darienf | 20:6d2af70c92ab | 202 | internal System.Guid ClassGuid; |
darienf | 20:6d2af70c92ab | 203 | internal Int32 DevInst; |
darienf | 20:6d2af70c92ab | 204 | internal Int32 Reserved; |
darienf | 20:6d2af70c92ab | 205 | } |
darienf | 20:6d2af70c92ab | 206 | #pragma warning restore 0649 |
darienf | 20:6d2af70c92ab | 207 | #endregion |
darienf | 20:6d2af70c92ab | 208 | |
darienf | 20:6d2af70c92ab | 209 | #region External Functions from dll |
darienf | 20:6d2af70c92ab | 210 | //HDEVINFO SetupDiGetClassDevs(const GUID *ClassGuid, PCTSTR Enumerator, HWND hwndParent, DWORD Flags); |
darienf | 20:6d2af70c92ab | 211 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] |
darienf | 20:6d2af70c92ab | 212 | internal static extern IntPtr SetupDiGetClassDevs(ref System.Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, Int32 Flags); |
darienf | 20:6d2af70c92ab | 213 | |
darienf | 20:6d2af70c92ab | 214 | //BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet); |
darienf | 20:6d2af70c92ab | 215 | [DllImport("setupapi.dll", SetLastError = true)] |
darienf | 20:6d2af70c92ab | 216 | internal static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); |
darienf | 20:6d2af70c92ab | 217 | |
darienf | 20:6d2af70c92ab | 218 | //BOOL SetupDiEnumDeviceInterfaces(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const GUID *InterfaceClassGuid, DWORD MemberIndex, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); |
darienf | 20:6d2af70c92ab | 219 | [DllImport("setupapi.dll", SetLastError = true)] |
darienf | 20:6d2af70c92ab | 220 | internal static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, ref System.Guid InterfaceClassGuid, Int32 MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); |
darienf | 20:6d2af70c92ab | 221 | [DllImport("setupapi.dll", SetLastError = true)] |
darienf | 20:6d2af70c92ab | 222 | // required to pass DeviceInfoData=null |
darienf | 20:6d2af70c92ab | 223 | internal static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref System.Guid InterfaceClassGuid, Int32 MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); |
darienf | 20:6d2af70c92ab | 224 | |
darienf | 20:6d2af70c92ab | 225 | //BOOL SetupDiGetDeviceInterfaceDetail(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, DWORD DeviceInterfaceDetailDataSize, PDWORD RequiredSize, PSP_DEVINFO_DATA DeviceInfoData); |
darienf | 20:6d2af70c92ab | 226 | //[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] |
darienf | 20:6d2af70c92ab | 227 | //internal extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, ref SP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, ref SP_DEVINFO_DATA DeviceInfoData); |
darienf | 20:6d2af70c92ab | 228 | //[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] |
darienf | 20:6d2af70c92ab | 229 | //// required to pass DeviceInfoData=null |
darienf | 20:6d2af70c92ab | 230 | //internal extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, ref SP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, IntPtr DeviceInfoData); |
darienf | 20:6d2af70c92ab | 231 | // cannot get SP_DEVICE_INTERFACE_DETAIL_DATA's DevicePath field to work properly, so use IntPtr instead of ref SP_DEVICE_INTERFACE_DATA |
darienf | 20:6d2af70c92ab | 232 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] |
darienf | 20:6d2af70c92ab | 233 | // required to pass DeviceInterfaceDetailData=null |
darienf | 20:6d2af70c92ab | 234 | internal static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, ref SP_DEVINFO_DATA DeviceInfoData); |
darienf | 20:6d2af70c92ab | 235 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] |
darienf | 20:6d2af70c92ab | 236 | // required to pass DeviceInterfaceDetailData=null, DeviceInfoData=null |
darienf | 20:6d2af70c92ab | 237 | internal static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, IntPtr DeviceInfoData); |
darienf | 20:6d2af70c92ab | 238 | |
darienf | 20:6d2af70c92ab | 239 | //BOOL SetupDiEnumDeviceInfo(HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData); |
darienf | 20:6d2af70c92ab | 240 | [DllImport("setupapi.dll", SetLastError = true)] |
darienf | 20:6d2af70c92ab | 241 | internal static extern Boolean SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, Int32 MemberIndex, ref SP_DEVINFO_DATA DevInfoData); |
darienf | 20:6d2af70c92ab | 242 | |
darienf | 20:6d2af70c92ab | 243 | //BOOL SetupDiGetDeviceRegistryProperty(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize); |
darienf | 20:6d2af70c92ab | 244 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] |
darienf | 20:6d2af70c92ab | 245 | internal static extern Boolean SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DevInfoData, Int32 Property, IntPtr PropertyRegDataType, IntPtr PropertyBuffer, Int32 PropertyBufferSize, ref Int32 RequiredSize); |
darienf | 20:6d2af70c92ab | 246 | |
darienf | 20:6d2af70c92ab | 247 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] |
darienf | 20:6d2af70c92ab | 248 | internal static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, Int32 Flags); |
darienf | 20:6d2af70c92ab | 249 | |
darienf | 20:6d2af70c92ab | 250 | [DllImport("user32.dll", SetLastError = true)] |
darienf | 20:6d2af70c92ab | 251 | internal static extern Boolean UnregisterDeviceNotification(IntPtr Handle); |
darienf | 20:6d2af70c92ab | 252 | |
darienf | 20:6d2af70c92ab | 253 | // API declarations for HID communications. |
darienf | 20:6d2af70c92ab | 254 | |
darienf | 20:6d2af70c92ab | 255 | // from hidpi.h |
darienf | 20:6d2af70c92ab | 256 | // Typedef enum defines a set of integer constants for HidP_Report_Type |
darienf | 20:6d2af70c92ab | 257 | |
darienf | 20:6d2af70c92ab | 258 | internal const Int16 HidP_Input = 0; |
darienf | 20:6d2af70c92ab | 259 | internal const Int16 HidP_Output = 1; |
darienf | 20:6d2af70c92ab | 260 | internal const Int16 HidP_Feature = 2; |
darienf | 20:6d2af70c92ab | 261 | |
darienf | 20:6d2af70c92ab | 262 | [StructLayout(LayoutKind.Sequential)] |
darienf | 20:6d2af70c92ab | 263 | internal struct HIDD_ATTRIBUTES |
darienf | 20:6d2af70c92ab | 264 | { |
darienf | 20:6d2af70c92ab | 265 | internal Int32 Size; |
darienf | 20:6d2af70c92ab | 266 | internal UInt16 VendorID; |
darienf | 20:6d2af70c92ab | 267 | internal UInt16 ProductID; |
darienf | 20:6d2af70c92ab | 268 | internal UInt16 VersionNumber; |
darienf | 20:6d2af70c92ab | 269 | } |
darienf | 20:6d2af70c92ab | 270 | |
darienf | 20:6d2af70c92ab | 271 | [DllImport("hid.dll", SetLastError = true)] |
darienf | 20:6d2af70c92ab | 272 | internal static extern Boolean HidD_FlushQueue(SafeFileHandle HidDeviceObject); |
darienf | 20:6d2af70c92ab | 273 | |
darienf | 20:6d2af70c92ab | 274 | [DllImport("hid.dll", SetLastError = true)] |
darienf | 20:6d2af70c92ab | 275 | internal static extern Boolean HidD_GetAttributes(SafeFileHandle HidDeviceObject, ref HIDD_ATTRIBUTES Attributes); |
darienf | 20:6d2af70c92ab | 276 | |
darienf | 20:6d2af70c92ab | 277 | [DllImport("hid.dll", SetLastError = true)] |
darienf | 20:6d2af70c92ab | 278 | internal static extern void HidD_GetHidGuid(ref System.Guid HidGuid); |
darienf | 20:6d2af70c92ab | 279 | #endregion |
darienf | 20:6d2af70c92ab | 280 | |
darienf | 20:6d2af70c92ab | 281 | #region Setup HID |
darienf | 20:6d2af70c92ab | 282 | public void getHidGuid(ref System.Guid hidGuid) |
darienf | 20:6d2af70c92ab | 283 | { |
darienf | 20:6d2af70c92ab | 284 | DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 285 | #if DEBUG |
darienf | 20:6d2af70c92ab | 286 | HidD_GetHidGuid(ref hidGuid); |
darienf | 20:6d2af70c92ab | 287 | #else |
darienf | 20:6d2af70c92ab | 288 | try |
darienf | 20:6d2af70c92ab | 289 | { |
darienf | 20:6d2af70c92ab | 290 | HidD_GetHidGuid(ref hidGuid); |
darienf | 20:6d2af70c92ab | 291 | } |
darienf | 20:6d2af70c92ab | 292 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 293 | { |
darienf | 20:6d2af70c92ab | 294 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 295 | } |
darienf | 20:6d2af70c92ab | 296 | #endif |
darienf | 20:6d2af70c92ab | 297 | DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 298 | } |
darienf | 20:6d2af70c92ab | 299 | |
darienf | 20:6d2af70c92ab | 300 | public string DebugMessage; |
darienf | 20:6d2af70c92ab | 301 | //public void TraceMessage(string message, |
darienf | 20:6d2af70c92ab | 302 | //[System.Runtime.CompilerServices.CallerMemberName] string memberName = "", |
darienf | 20:6d2af70c92ab | 303 | //[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", |
darienf | 20:6d2af70c92ab | 304 | //[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) |
darienf | 20:6d2af70c92ab | 305 | //{ |
darienf | 20:6d2af70c92ab | 306 | // Console.WriteLine("message: " + message); |
darienf | 20:6d2af70c92ab | 307 | // Console.WriteLine("member name: " + memberName); |
darienf | 20:6d2af70c92ab | 308 | // Console.WriteLine("source file path: " + sourceFilePath); |
darienf | 20:6d2af70c92ab | 309 | // Console.WriteLine("source line number: " + sourceLineNumber); |
darienf | 20:6d2af70c92ab | 310 | //} |
darienf | 20:6d2af70c92ab | 311 | |
darienf | 20:6d2af70c92ab | 312 | /// <summary> |
darienf | 20:6d2af70c92ab | 313 | /// FindDesiredHIDPathNamesFromGuid() only appends to desiredHIDPathNameArray. |
darienf | 20:6d2af70c92ab | 314 | /// Desired HIDs that have been removed from the system are removed from desiredHIDPathNameArray in openHIDhandles |
darienf | 20:6d2af70c92ab | 315 | /// </summary> |
darienf | 20:6d2af70c92ab | 316 | /// <param name="myGuid"></param> |
darienf | 20:6d2af70c92ab | 317 | private void FindDesiredHIDPathNamesFromGuid(System.Guid myGuid) |
darienf | 20:6d2af70c92ab | 318 | { |
darienf | 20:6d2af70c92ab | 319 | DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 320 | // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. |
darienf | 20:6d2af70c92ab | 321 | // But I never see this kind of exception thrown from within the C# GUI. |
darienf | 20:6d2af70c92ab | 322 | // HID.findHIDs() still raises the exception in Matlab, |
darienf | 20:6d2af70c92ab | 323 | // Message: Arithmetic operation resulted in an overflow. |
darienf | 20:6d2af70c92ab | 324 | // |
darienf | 20:6d2af70c92ab | 325 | // % Required: connect to MAX30101EVKIT hardware |
darienf | 20:6d2af70c92ab | 326 | // fprintf('Connecting to MAX30101EVKIT hardware...\n'); |
darienf | 20:6d2af70c92ab | 327 | // for trial=0:2000 |
darienf | 20:6d2af70c92ab | 328 | // try |
darienf | 20:6d2af70c92ab | 329 | // %pause(1) % delay at least 1 second |
darienf | 20:6d2af70c92ab | 330 | // myMAX30101.myHID.findHIDs(); |
darienf | 20:6d2af70c92ab | 331 | // % Sometimes we get Error using MAX30101Example |
darienf | 20:6d2af70c92ab | 332 | // % If this happens, try clearing the workspace and run again. |
darienf | 20:6d2af70c92ab | 333 | // % Message: Arithmetic operation resulted in an overflow. |
darienf | 20:6d2af70c92ab | 334 | // % FindDesiredHIDPathNamesFromGuid |
darienf | 20:6d2af70c92ab | 335 | // % findHIDs |
darienf | 20:6d2af70c92ab | 336 | // % Source: MAX30101 |
darienf | 20:6d2af70c92ab | 337 | // % HelpLink: |
darienf | 20:6d2af70c92ab | 338 | // if (myMAX30101.myHID.isConnected()) |
darienf | 20:6d2af70c92ab | 339 | // break |
darienf | 20:6d2af70c92ab | 340 | // end |
darienf | 20:6d2af70c92ab | 341 | // catch me |
darienf | 20:6d2af70c92ab | 342 | // % disp(me) |
darienf | 20:6d2af70c92ab | 343 | // end |
darienf | 20:6d2af70c92ab | 344 | // end |
darienf | 20:6d2af70c92ab | 345 | // |
darienf | 20:6d2af70c92ab | 346 | // If matlab does successfully connect to USB, it is able to get |
darienf | 20:6d2af70c92ab | 347 | // streaming data through the PartialArrayIntAvailable event |
darienf | 20:6d2af70c92ab | 348 | // handler -- even though it can't understand |
darienf | 20:6d2af70c92ab | 349 | // System.Collections.ArrayList data, it does at least understand |
darienf | 20:6d2af70c92ab | 350 | // Array<System.Int32> or int[] data. |
darienf | 20:6d2af70c92ab | 351 | // |
darienf | 20:6d2af70c92ab | 352 | Int32 memberIndex = 0; |
darienf | 20:6d2af70c92ab | 353 | Int32 bufferSize = 0; |
darienf | 20:6d2af70c92ab | 354 | IntPtr deviceInfoSet = new System.IntPtr(); |
darienf | 20:6d2af70c92ab | 355 | SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(); |
darienf | 20:6d2af70c92ab | 356 | IntPtr deviceInterfaceDetailDataBuffer = IntPtr.Zero; |
darienf | 20:6d2af70c92ab | 357 | |
darienf | 20:6d2af70c92ab | 358 | // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. |
darienf | 20:6d2af70c92ab | 359 | // diagnostic: trying to avoid "Arithmetic overflow" from matlab. Limit the number of HID devices to be checked. |
darienf | 20:6d2af70c92ab | 360 | const int memberIndexLimit = 100; |
darienf | 20:6d2af70c92ab | 361 | |
darienf | 20:6d2af70c92ab | 362 | #if DEBUG |
darienf | 20:6d2af70c92ab | 363 | #else |
darienf | 20:6d2af70c92ab | 364 | try |
darienf | 20:6d2af70c92ab | 365 | { |
darienf | 20:6d2af70c92ab | 366 | #endif |
darienf | 20:6d2af70c92ab | 367 | DebugMessage = string.Format("{0} first deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 368 | deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); |
darienf | 20:6d2af70c92ab | 369 | |
darienf | 20:6d2af70c92ab | 370 | memberIndex = 0; |
darienf | 20:6d2af70c92ab | 371 | |
darienf | 20:6d2af70c92ab | 372 | // The cbSize element of the DeviceInterfaceData structure must be set to the structure's size in bytes. |
darienf | 20:6d2af70c92ab | 373 | // The size is 28 bytes for 32-bit code and 32 bits for 64-bit code. |
darienf | 20:6d2af70c92ab | 374 | DeviceInterfaceData.cbSize = Marshal.SizeOf(DeviceInterfaceData); |
darienf | 20:6d2af70c92ab | 375 | |
darienf | 20:6d2af70c92ab | 376 | while (memberIndex < memberIndexLimit) |
darienf | 20:6d2af70c92ab | 377 | { |
darienf | 20:6d2af70c92ab | 378 | // Begin with memberIndex = 0 and increment through the device information set until no more devices are available. |
darienf | 20:6d2af70c92ab | 379 | DebugMessage = string.Format("{0} memberIndex={1} first SetupDiEnumDeviceInterfaces ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 380 | if (!SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref myGuid, memberIndex, ref DeviceInterfaceData)) |
darienf | 20:6d2af70c92ab | 381 | { |
darienf | 20:6d2af70c92ab | 382 | break; |
darienf | 20:6d2af70c92ab | 383 | } |
darienf | 20:6d2af70c92ab | 384 | |
darienf | 20:6d2af70c92ab | 385 | DebugMessage = string.Format("{0} memberIndex={1} first SetupDiGetDeviceInterfaceDetail ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 386 | SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); |
darienf | 20:6d2af70c92ab | 387 | //tempLastError = GetLastError(); |
darienf | 20:6d2af70c92ab | 388 | //if (tempLastError != ERROR_INSUFFICIENT_BUFFER) // ERROR_INSUFFICIENT_BUFFER is expected on this first call |
darienf | 20:6d2af70c92ab | 389 | // break; |
darienf | 20:6d2af70c92ab | 390 | //FIXME add error check |
darienf | 20:6d2af70c92ab | 391 | |
darienf | 20:6d2af70c92ab | 392 | // Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size. |
darienf | 20:6d2af70c92ab | 393 | DebugMessage = string.Format("{0} memberIndex={1} Marshal.AllocHGlobal(bufferSize) ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 394 | deviceInterfaceDetailDataBuffer = Marshal.AllocHGlobal(bufferSize); |
darienf | 20:6d2af70c92ab | 395 | // Returns a System.IntPtr pointer to the newly allocated global heap memory. |
darienf | 20:6d2af70c92ab | 396 | // This memory must be released using the Marshal.FreeHGlobal method. |
darienf | 20:6d2af70c92ab | 397 | // Marshal.AllocHGlobal(numBytes) could throw OutOfMemoryException ? |
darienf | 20:6d2af70c92ab | 398 | |
darienf | 20:6d2af70c92ab | 399 | // Store cbSize in the first bytes of the array. The number of bytes varies with 32- and 64-bit systems. |
darienf | 20:6d2af70c92ab | 400 | DebugMessage = string.Format("{0} memberIndex={1} Marshal.WriteInt32 ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 401 | Marshal.WriteInt32(deviceInterfaceDetailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); |
darienf | 20:6d2af70c92ab | 402 | |
darienf | 20:6d2af70c92ab | 403 | // Call SetupDiGetDeviceInterfaceDetail again. |
darienf | 20:6d2af70c92ab | 404 | // This time, pass a pointer to DetailDataBuffer and the returned required buffer size. |
darienf | 20:6d2af70c92ab | 405 | DebugMessage = string.Format("{0} memberIndex={1} second SetupDiGetDeviceInterfaceDetail ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 406 | if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, deviceInterfaceDetailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero)) |
darienf | 20:6d2af70c92ab | 407 | break; |
darienf | 20:6d2af70c92ab | 408 | |
darienf | 20:6d2af70c92ab | 409 | // Skip over cbsize (4 bytes) to get the address of the devicePathName. |
darienf | 20:6d2af70c92ab | 410 | // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message |
darienf | 20:6d2af70c92ab | 411 | DebugMessage = string.Format("{0} memberIndex={1} IntPtr pDevicePathName = IntPtr.Add(deviceInterfaceDetailDataBuffer, 4); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 412 | IntPtr pDevicePathName = IntPtr.Add(deviceInterfaceDetailDataBuffer, 4); |
darienf | 20:6d2af70c92ab | 413 | // DebugMessage = string.Format("{0} memberIndex={1} new IntPtr(deviceInterfaceDetailDataBuffer.ToInt32() + 4); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 414 | // BAD CODE. IntPtr pDevicePathName = new IntPtr(deviceInterfaceDetailDataBuffer.ToInt32() + 4); |
darienf | 20:6d2af70c92ab | 415 | // BAD CODE. assumes the pointer is a 32-bit address, intermittently fails from 64-bit matlab client. |
darienf | 20:6d2af70c92ab | 416 | |
darienf | 20:6d2af70c92ab | 417 | // Get the String containing the devicePathName. |
darienf | 20:6d2af70c92ab | 418 | DebugMessage = string.Format("{0} memberIndex={1} Marshal.PtrToStringAuto(pDevicePathName); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 419 | string tempPathName = Marshal.PtrToStringAuto(pDevicePathName); |
darienf | 20:6d2af70c92ab | 420 | |
darienf | 20:6d2af70c92ab | 421 | // match any device pathname that contains deviceID (case-insensitive match) "Vid_{0:x4}&Pid_{1:x4}" |
darienf | 20:6d2af70c92ab | 422 | DebugMessage = string.Format("{0} memberIndex={1} if (tempPathName.ToLower().IndexOf(deviceID.ToLower()) != -1) ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 423 | if (tempPathName.ToLower().IndexOf(deviceID.ToLower()) != -1) |
darienf | 20:6d2af70c92ab | 424 | { |
darienf | 20:6d2af70c92ab | 425 | DebugMessage = string.Format("{0} memberIndex={1} desiredHIDPathNameArray.Add(tempPathName); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 426 | desiredHIDPathNameArray.Add(tempPathName); |
darienf | 20:6d2af70c92ab | 427 | } |
darienf | 20:6d2af70c92ab | 428 | |
darienf | 20:6d2af70c92ab | 429 | DebugMessage = string.Format("{0} memberIndex={1} memberIndex = memberIndex + 1; ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 430 | |
darienf | 20:6d2af70c92ab | 431 | // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message |
darienf | 20:6d2af70c92ab | 432 | // why didn't they call Marshal.FreeHGlobal here, inside the while loop? Isn't this a memory leak? |
darienf | 20:6d2af70c92ab | 433 | // Free the memory allocated previously by AllocHGlobal. |
darienf | 20:6d2af70c92ab | 434 | if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 435 | { |
darienf | 20:6d2af70c92ab | 436 | Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); |
darienf | 20:6d2af70c92ab | 437 | deviceInterfaceDetailDataBuffer = IntPtr.Zero; |
darienf | 20:6d2af70c92ab | 438 | } |
darienf | 20:6d2af70c92ab | 439 | |
darienf | 20:6d2af70c92ab | 440 | memberIndex = memberIndex + 1; |
darienf | 20:6d2af70c92ab | 441 | } |
darienf | 20:6d2af70c92ab | 442 | #if DEBUG |
darienf | 20:6d2af70c92ab | 443 | // Free the memory allocated previously by AllocHGlobal. |
darienf | 20:6d2af70c92ab | 444 | if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 445 | Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); |
darienf | 20:6d2af70c92ab | 446 | |
darienf | 20:6d2af70c92ab | 447 | if (deviceInfoSet != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 448 | SetupDiDestroyDeviceInfoList(deviceInfoSet); |
darienf | 20:6d2af70c92ab | 449 | #else |
darienf | 20:6d2af70c92ab | 450 | } |
darienf | 20:6d2af70c92ab | 451 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 452 | { |
darienf | 20:6d2af70c92ab | 453 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 454 | } |
darienf | 20:6d2af70c92ab | 455 | finally |
darienf | 20:6d2af70c92ab | 456 | { |
darienf | 20:6d2af70c92ab | 457 | // Free the memory allocated previously by AllocHGlobal. |
darienf | 20:6d2af70c92ab | 458 | if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 459 | Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); |
darienf | 20:6d2af70c92ab | 460 | |
darienf | 20:6d2af70c92ab | 461 | if (deviceInfoSet != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 462 | SetupDiDestroyDeviceInfoList(deviceInfoSet); |
darienf | 20:6d2af70c92ab | 463 | } |
darienf | 20:6d2af70c92ab | 464 | #endif |
darienf | 20:6d2af70c92ab | 465 | DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 466 | } |
darienf | 20:6d2af70c92ab | 467 | |
darienf | 20:6d2af70c92ab | 468 | private void FindAllHIDPathNamesFromGuid(System.Guid myGuid, ArrayList allHIDPathNameArray) |
darienf | 20:6d2af70c92ab | 469 | { |
darienf | 20:6d2af70c92ab | 470 | DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 471 | // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. |
darienf | 20:6d2af70c92ab | 472 | // But I never see this kind of exception thrown from within the C# GUI. |
darienf | 20:6d2af70c92ab | 473 | // HID.findHIDs() still raises the exception in Matlab, |
darienf | 20:6d2af70c92ab | 474 | // Message: Arithmetic operation resulted in an overflow. |
darienf | 20:6d2af70c92ab | 475 | Int32 memberIndex = 0; |
darienf | 20:6d2af70c92ab | 476 | Int32 bufferSize = 0; |
darienf | 20:6d2af70c92ab | 477 | IntPtr deviceInfoSet = new System.IntPtr(); |
darienf | 20:6d2af70c92ab | 478 | SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(); |
darienf | 20:6d2af70c92ab | 479 | IntPtr deviceInterfaceDetailDataBuffer = IntPtr.Zero; |
darienf | 20:6d2af70c92ab | 480 | |
darienf | 20:6d2af70c92ab | 481 | // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. |
darienf | 20:6d2af70c92ab | 482 | // diagnostic: trying to avoid "Arithmetic overflow" from matlab. Limit the number of HID devices to be checked. |
darienf | 20:6d2af70c92ab | 483 | const int memberIndexLimit = 100; |
darienf | 20:6d2af70c92ab | 484 | |
darienf | 20:6d2af70c92ab | 485 | |
darienf | 20:6d2af70c92ab | 486 | #if DEBUG |
darienf | 20:6d2af70c92ab | 487 | #else |
darienf | 20:6d2af70c92ab | 488 | try |
darienf | 20:6d2af70c92ab | 489 | { |
darienf | 20:6d2af70c92ab | 490 | #endif |
darienf | 20:6d2af70c92ab | 491 | DebugMessage = string.Format("{0} first deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 492 | deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); |
darienf | 20:6d2af70c92ab | 493 | |
darienf | 20:6d2af70c92ab | 494 | memberIndex = 0; |
darienf | 20:6d2af70c92ab | 495 | |
darienf | 20:6d2af70c92ab | 496 | // The cbSize element of the DeviceInterfaceData structure must be set to the structure's size in bytes. |
darienf | 20:6d2af70c92ab | 497 | // The size is 28 bytes for 32-bit code and 32 bits for 64-bit code. |
darienf | 20:6d2af70c92ab | 498 | DeviceInterfaceData.cbSize = Marshal.SizeOf(DeviceInterfaceData); |
darienf | 20:6d2af70c92ab | 499 | |
darienf | 20:6d2af70c92ab | 500 | // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. |
darienf | 20:6d2af70c92ab | 501 | while (memberIndex < memberIndexLimit) |
darienf | 20:6d2af70c92ab | 502 | { |
darienf | 20:6d2af70c92ab | 503 | DebugMessage = string.Format("{0} memberIndex={1} first SetupDiEnumDeviceInterfaces ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 504 | if (!SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref myGuid, memberIndex, ref DeviceInterfaceData)) |
darienf | 20:6d2af70c92ab | 505 | { |
darienf | 20:6d2af70c92ab | 506 | break; |
darienf | 20:6d2af70c92ab | 507 | } |
darienf | 20:6d2af70c92ab | 508 | |
darienf | 20:6d2af70c92ab | 509 | DebugMessage = string.Format("{0} memberIndex={1} first SetupDiGetDeviceInterfaceDetail ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 510 | SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); |
darienf | 20:6d2af70c92ab | 511 | |
darienf | 20:6d2af70c92ab | 512 | // Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size. |
darienf | 20:6d2af70c92ab | 513 | DebugMessage = string.Format("{0} memberIndex={1} Marshal.AllocHGlobal(bufferSize) ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 514 | deviceInterfaceDetailDataBuffer = Marshal.AllocHGlobal(bufferSize); |
darienf | 20:6d2af70c92ab | 515 | |
darienf | 20:6d2af70c92ab | 516 | // Store cbSize in the first bytes of the array. The number of bytes varies with 32- and 64-bit systems. |
darienf | 20:6d2af70c92ab | 517 | DebugMessage = string.Format("{0} memberIndex={1} Marshal.WriteInt32 ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 518 | Marshal.WriteInt32(deviceInterfaceDetailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); |
darienf | 20:6d2af70c92ab | 519 | |
darienf | 20:6d2af70c92ab | 520 | // Call SetupDiGetDeviceInterfaceDetail again. |
darienf | 20:6d2af70c92ab | 521 | // This time, pass a pointer to deviceInterfaceDetailDataBuffer and the returned required buffer size. |
darienf | 20:6d2af70c92ab | 522 | DebugMessage = string.Format("{0} memberIndex={1} second SetupDiGetDeviceInterfaceDetail ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 523 | if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, deviceInterfaceDetailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero)) |
darienf | 20:6d2af70c92ab | 524 | break; |
darienf | 20:6d2af70c92ab | 525 | |
darienf | 20:6d2af70c92ab | 526 | // Skip over cbsize (4 bytes) to get the address of the devicePathName. |
darienf | 20:6d2af70c92ab | 527 | // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message |
darienf | 20:6d2af70c92ab | 528 | DebugMessage = string.Format("{0} memberIndex={1} IntPtr pDevicePathName = IntPtr.Add(deviceInterfaceDetailDataBuffer, 4); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 529 | // example: IntPtr right way to add an offset (portable to 64-bit clients) |
darienf | 20:6d2af70c92ab | 530 | IntPtr pDevicePathName = IntPtr.Add(deviceInterfaceDetailDataBuffer, 4); |
darienf | 20:6d2af70c92ab | 531 | // DebugMessage = string.Format("{0} memberIndex={1} IntPtr pDevicePathName = new IntPtr(deviceInterfaceDetailDataBuffer.ToInt32() + 4); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 532 | // BAD CODE. IntPtr pDevicePathName = new IntPtr(deviceInterfaceDetailDataBuffer.ToInt32() + 4); |
darienf | 20:6d2af70c92ab | 533 | // BAD CODE. assumes the pointer is a 32-bit address, intermittently fails from 64-bit matlab client. |
darienf | 20:6d2af70c92ab | 534 | |
darienf | 20:6d2af70c92ab | 535 | // Get the String containing the devicePathName. |
darienf | 20:6d2af70c92ab | 536 | DebugMessage = string.Format("{0} memberIndex={1} Marshal.PtrToStringAuto(pDevicePathName); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); |
darienf | 20:6d2af70c92ab | 537 | allHIDPathNameArray.Add(Marshal.PtrToStringAuto(pDevicePathName)); |
darienf | 20:6d2af70c92ab | 538 | |
darienf | 20:6d2af70c92ab | 539 | // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message |
darienf | 20:6d2af70c92ab | 540 | // why didn't they call Marshal.FreeHGlobal here, inside the while loop? Isn't this a memory leak? |
darienf | 20:6d2af70c92ab | 541 | // Free the memory allocated previously by AllocHGlobal. |
darienf | 20:6d2af70c92ab | 542 | if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 543 | { |
darienf | 20:6d2af70c92ab | 544 | Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); |
darienf | 20:6d2af70c92ab | 545 | deviceInterfaceDetailDataBuffer = IntPtr.Zero; |
darienf | 20:6d2af70c92ab | 546 | } |
darienf | 20:6d2af70c92ab | 547 | |
darienf | 20:6d2af70c92ab | 548 | memberIndex = memberIndex + 1; |
darienf | 20:6d2af70c92ab | 549 | } |
darienf | 20:6d2af70c92ab | 550 | #if DEBUG |
darienf | 20:6d2af70c92ab | 551 | // Free the memory allocated previously by AllocHGlobal. |
darienf | 20:6d2af70c92ab | 552 | if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 553 | Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); |
darienf | 20:6d2af70c92ab | 554 | |
darienf | 20:6d2af70c92ab | 555 | if (deviceInfoSet != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 556 | SetupDiDestroyDeviceInfoList(deviceInfoSet); |
darienf | 20:6d2af70c92ab | 557 | #else |
darienf | 20:6d2af70c92ab | 558 | } |
darienf | 20:6d2af70c92ab | 559 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 560 | { |
darienf | 20:6d2af70c92ab | 561 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 562 | } |
darienf | 20:6d2af70c92ab | 563 | finally |
darienf | 20:6d2af70c92ab | 564 | { |
darienf | 20:6d2af70c92ab | 565 | // Free the memory allocated previously by AllocHGlobal. |
darienf | 20:6d2af70c92ab | 566 | if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 567 | Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); |
darienf | 20:6d2af70c92ab | 568 | |
darienf | 20:6d2af70c92ab | 569 | if (deviceInfoSet != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 570 | SetupDiDestroyDeviceInfoList(deviceInfoSet); |
darienf | 20:6d2af70c92ab | 571 | } |
darienf | 20:6d2af70c92ab | 572 | #endif |
darienf | 20:6d2af70c92ab | 573 | DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 574 | } |
darienf | 20:6d2af70c92ab | 575 | |
darienf | 20:6d2af70c92ab | 576 | public bool isConnected() |
darienf | 20:6d2af70c92ab | 577 | { |
darienf | 20:6d2af70c92ab | 578 | try |
darienf | 20:6d2af70c92ab | 579 | { |
darienf | 20:6d2af70c92ab | 580 | return desiredHIDPathNameArray.Count != 0 ? true : false; |
darienf | 20:6d2af70c92ab | 581 | } |
darienf | 20:6d2af70c92ab | 582 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 583 | { |
darienf | 20:6d2af70c92ab | 584 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 585 | } |
darienf | 20:6d2af70c92ab | 586 | } |
darienf | 20:6d2af70c92ab | 587 | |
darienf | 20:6d2af70c92ab | 588 | |
darienf | 20:6d2af70c92ab | 589 | /// <summary> |
darienf | 20:6d2af70c92ab | 590 | /// Called when a WM_DEVICECHANGE message has arrived, |
darienf | 20:6d2af70c92ab | 591 | /// indicating that a device has been attached or removed. |
darienf | 20:6d2af70c92ab | 592 | /// |
darienf | 20:6d2af70c92ab | 593 | /// </summary> |
darienf | 20:6d2af70c92ab | 594 | /// <param name="m"> a message with information about the device </param> |
darienf | 20:6d2af70c92ab | 595 | /// <returns>true on HID device arrival or remove complete</returns> |
darienf | 20:6d2af70c92ab | 596 | public bool HandleWMDeviceChangeMessage(Message m) |
darienf | 20:6d2af70c92ab | 597 | { |
darienf | 20:6d2af70c92ab | 598 | // Example code: |
darienf | 20:6d2af70c92ab | 599 | // |
darienf | 20:6d2af70c92ab | 600 | // <code> |
darienf | 20:6d2af70c92ab | 601 | // protected override void WndProc(ref Message m) |
darienf | 20:6d2af70c92ab | 602 | // { |
darienf | 20:6d2af70c92ab | 603 | // if (myHID != null) |
darienf | 20:6d2af70c92ab | 604 | // { |
darienf | 20:6d2af70c92ab | 605 | // if (myHID.HandleWMDeviceChangeMessage(m) /* m.Msg == HID.WM_DEVICECHANGE */ ) |
darienf | 20:6d2af70c92ab | 606 | // { |
darienf | 20:6d2af70c92ab | 607 | // // optional: handle newly arrived connection or surprise disconnect |
darienf | 20:6d2af70c92ab | 608 | // } |
darienf | 20:6d2af70c92ab | 609 | // } |
darienf | 20:6d2af70c92ab | 610 | // // Let the base form process the message. |
darienf | 20:6d2af70c92ab | 611 | // base.WndProc(ref m); |
darienf | 20:6d2af70c92ab | 612 | // } |
darienf | 20:6d2af70c92ab | 613 | // </code> |
darienf | 20:6d2af70c92ab | 614 | // |
darienf | 20:6d2af70c92ab | 615 | // https://jira.maxim-ic.com/browse/OS24EVK-59 WndProc if HID.WM_DEVICECHANGE do HID.OnDeviceChange(Message m) |
darienf | 20:6d2af70c92ab | 616 | try |
darienf | 20:6d2af70c92ab | 617 | { |
darienf | 20:6d2af70c92ab | 618 | if (m.Msg == HID.WM_DEVICECHANGE) |
darienf | 20:6d2af70c92ab | 619 | { |
darienf | 20:6d2af70c92ab | 620 | //if ((int)m.WParam == HID.DBT_DEVNODES_CHANGED) //this always occurs when any USB device is attached/detached. Use this if not registering for device notifications. |
darienf | 20:6d2af70c92ab | 621 | if ( |
darienf | 20:6d2af70c92ab | 622 | ( m.WParam.ToInt32() == HID.DBT_DEVICEARRIVAL |
darienf | 20:6d2af70c92ab | 623 | || m.WParam.ToInt32() == HID.DBT_DEVICEREMOVECOMPLETE |
darienf | 20:6d2af70c92ab | 624 | ) |
darienf | 20:6d2af70c92ab | 625 | && |
darienf | 20:6d2af70c92ab | 626 | (m.LParam.ToInt32() != 0) |
darienf | 20:6d2af70c92ab | 627 | && |
darienf | 20:6d2af70c92ab | 628 | DeviceIDMatch(m) |
darienf | 20:6d2af70c92ab | 629 | ) |
darienf | 20:6d2af70c92ab | 630 | { |
darienf | 20:6d2af70c92ab | 631 | closeHIDhandles(); |
darienf | 20:6d2af70c92ab | 632 | findHIDs(); |
darienf | 20:6d2af70c92ab | 633 | // cboEVB_init(); |
darienf | 20:6d2af70c92ab | 634 | return true; |
darienf | 20:6d2af70c92ab | 635 | } |
darienf | 20:6d2af70c92ab | 636 | } |
darienf | 20:6d2af70c92ab | 637 | return false; |
darienf | 20:6d2af70c92ab | 638 | } |
darienf | 20:6d2af70c92ab | 639 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 640 | { |
darienf | 20:6d2af70c92ab | 641 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 642 | } |
darienf | 20:6d2af70c92ab | 643 | } |
darienf | 20:6d2af70c92ab | 644 | |
darienf | 20:6d2af70c92ab | 645 | /// <summary> |
darienf | 20:6d2af70c92ab | 646 | /// findHIDs() called upon startup or if a desired HID has been inserted or removed |
darienf | 20:6d2af70c92ab | 647 | /// </summary> |
darienf | 20:6d2af70c92ab | 648 | public void findHIDs() |
darienf | 20:6d2af70c92ab | 649 | { |
darienf | 20:6d2af70c92ab | 650 | DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 651 | ArrayList allHIDPathNameArray = new ArrayList(); |
darienf | 20:6d2af70c92ab | 652 | System.Guid hidGuid = new System.Guid(); |
darienf | 20:6d2af70c92ab | 653 | |
darienf | 20:6d2af70c92ab | 654 | // https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. |
darienf | 20:6d2af70c92ab | 655 | #if DEBUG |
darienf | 20:6d2af70c92ab | 656 | #else |
darienf | 20:6d2af70c92ab | 657 | try |
darienf | 20:6d2af70c92ab | 658 | { |
darienf | 20:6d2af70c92ab | 659 | #endif |
darienf | 20:6d2af70c92ab | 660 | HidD_GetHidGuid(ref hidGuid); |
darienf | 20:6d2af70c92ab | 661 | // FindDesiredHIDPathNamesFromGuid() builds desiredHIDPathNameArray which is a list of all desired HIDs in the system |
darienf | 20:6d2af70c92ab | 662 | // desiredHIDPathNameArray is a global list and is used to maintain the order of desired HIDs in the selection list. |
darienf | 20:6d2af70c92ab | 663 | // USB ports have different priorities, and the user could have attached the first desired HID to a lower priority port. |
darienf | 20:6d2af70c92ab | 664 | // Hence, when another desired HID is attached to a higher priority port, it will come earlier in allHIDPathNameArray, but it will be maintained in the same attachment order in desiredHIDPathNameArray. |
darienf | 20:6d2af70c92ab | 665 | // Note that desiredHIDPathNameArray is only appended to or deleted from; it is never recreated in whole. |
darienf | 20:6d2af70c92ab | 666 | // FIXME desiredHIDPathNameArray will get duplicate pathnames for desired HIDs that were already attached, but these will be removed by openHIDhandles() since they're in allHIDPathNameArray only once. |
darienf | 20:6d2af70c92ab | 667 | // These duplicates pathnames are appended after the initial list, so they won't affect order. |
darienf | 20:6d2af70c92ab | 668 | FindDesiredHIDPathNamesFromGuid(hidGuid); |
darienf | 20:6d2af70c92ab | 669 | // FindAllHIDPathNamesFromGuid() builds allHIDPathNameArray which is a list of all HIDs in the system. It is recreated every time a desired HID is attached or removed. |
darienf | 20:6d2af70c92ab | 670 | FindAllHIDPathNamesFromGuid(hidGuid, allHIDPathNameArray); |
darienf | 20:6d2af70c92ab | 671 | // openHIDhandles() gets handles for all desired HIDs |
darienf | 20:6d2af70c92ab | 672 | // openHIDhandles() loops through all attached HIDs and checks for a match of each item in desiredHIDPathNameArray. This maintains the attachement order. |
darienf | 20:6d2af70c92ab | 673 | // If a previously attached HID has been removed, it won't be found in allHIDPathNameArray and it will be removed from desiredHIDPathNameArray. |
darienf | 20:6d2af70c92ab | 674 | openHIDhandles(allHIDPathNameArray); |
darienf | 20:6d2af70c92ab | 675 | if (desiredHIDPathNameArray.Count != 0) |
darienf | 20:6d2af70c92ab | 676 | { |
darienf | 20:6d2af70c92ab | 677 | prepareForOverlappedTransfer(); |
darienf | 20:6d2af70c92ab | 678 | } |
darienf | 20:6d2af70c92ab | 679 | #if DEBUG |
darienf | 20:6d2af70c92ab | 680 | #else |
darienf | 20:6d2af70c92ab | 681 | } |
darienf | 20:6d2af70c92ab | 682 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 683 | { |
darienf | 20:6d2af70c92ab | 684 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 685 | } |
darienf | 20:6d2af70c92ab | 686 | #endif |
darienf | 20:6d2af70c92ab | 687 | DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 688 | } |
darienf | 20:6d2af70c92ab | 689 | |
darienf | 20:6d2af70c92ab | 690 | private void openHIDhandles(ArrayList allHIDPathNameArray) |
darienf | 20:6d2af70c92ab | 691 | { |
darienf | 20:6d2af70c92ab | 692 | DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 693 | int desiredHIDPathNameArrayCounter; |
darienf | 20:6d2af70c92ab | 694 | int allHIDPathNameArrayCounter; |
darienf | 20:6d2af70c92ab | 695 | bool found_installed_device; |
darienf | 20:6d2af70c92ab | 696 | try |
darienf | 20:6d2af70c92ab | 697 | { |
darienf | 20:6d2af70c92ab | 698 | desiredHIDPathNameArrayCounter = 0; |
darienf | 20:6d2af70c92ab | 699 | while (desiredHIDPathNameArrayCounter < desiredHIDPathNameArray.Count) // count will change if a previously installed device has been removed, so don't use a for loop |
darienf | 20:6d2af70c92ab | 700 | { |
darienf | 20:6d2af70c92ab | 701 | found_installed_device = false; |
darienf | 20:6d2af70c92ab | 702 | allHIDPathNameArrayCounter = 0; |
darienf | 20:6d2af70c92ab | 703 | while (allHIDPathNameArrayCounter < allHIDPathNameArray.Count) |
darienf | 20:6d2af70c92ab | 704 | { |
darienf | 20:6d2af70c92ab | 705 | if ((string)allHIDPathNameArray[allHIDPathNameArrayCounter] == (string)desiredHIDPathNameArray[desiredHIDPathNameArrayCounter]) |
darienf | 20:6d2af70c92ab | 706 | { |
darienf | 20:6d2af70c92ab | 707 | writeHandle = FileIO.CreateFile((string)desiredHIDPathNameArray[desiredHIDPathNameArrayCounter], FileIO.GENERIC_READ | FileIO.GENERIC_WRITE, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0); |
darienf | 20:6d2af70c92ab | 708 | if (!(writeHandle.IsInvalid)) |
darienf | 20:6d2af70c92ab | 709 | { |
darienf | 20:6d2af70c92ab | 710 | readHandle = FileIO.CreateFile((string)desiredHIDPathNameArray[desiredHIDPathNameArrayCounter], FileIO.GENERIC_READ | FileIO.GENERIC_WRITE, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, FileIO.FILE_FLAG_OVERLAPPED, 0); |
darienf | 20:6d2af70c92ab | 711 | if (!(readHandle.IsInvalid)) |
darienf | 20:6d2af70c92ab | 712 | { |
darienf | 20:6d2af70c92ab | 713 | writeHandleArray.Add(writeHandle); |
darienf | 20:6d2af70c92ab | 714 | readHandleArray.Add(readHandle); |
darienf | 20:6d2af70c92ab | 715 | allHIDPathNameArray.RemoveAt(allHIDPathNameArrayCounter); // remove it so we don't repeatedly add it when we check for new devices (after we finish checking for previously installed devices) |
darienf | 20:6d2af70c92ab | 716 | found_installed_device = true; |
darienf | 20:6d2af70c92ab | 717 | } |
darienf | 20:6d2af70c92ab | 718 | else |
darienf | 20:6d2af70c92ab | 719 | { |
darienf | 20:6d2af70c92ab | 720 | writeHandle.Close(); |
darienf | 20:6d2af70c92ab | 721 | writeHandle = null; |
darienf | 20:6d2af70c92ab | 722 | readHandle = null; |
darienf | 20:6d2af70c92ab | 723 | } |
darienf | 20:6d2af70c92ab | 724 | } |
darienf | 20:6d2af70c92ab | 725 | else |
darienf | 20:6d2af70c92ab | 726 | { |
darienf | 20:6d2af70c92ab | 727 | writeHandle = null; |
darienf | 20:6d2af70c92ab | 728 | readHandle = null; |
darienf | 20:6d2af70c92ab | 729 | } |
darienf | 20:6d2af70c92ab | 730 | break; |
darienf | 20:6d2af70c92ab | 731 | } |
darienf | 20:6d2af70c92ab | 732 | allHIDPathNameArrayCounter++; |
darienf | 20:6d2af70c92ab | 733 | } |
darienf | 20:6d2af70c92ab | 734 | if (found_installed_device == false) // no match in all allHIDPathNameArray elements; the device has been removed so remove its pathname from desiredHIDPathNameArray. Don't use counter at max count to check if not found, since max count can change. |
darienf | 20:6d2af70c92ab | 735 | desiredHIDPathNameArray.RemoveAt(desiredHIDPathNameArrayCounter); // decrements count by 1; don't increment desiredHIDPathNameArrayCounter |
darienf | 20:6d2af70c92ab | 736 | else |
darienf | 20:6d2af70c92ab | 737 | desiredHIDPathNameArrayCounter++; |
darienf | 20:6d2af70c92ab | 738 | } |
darienf | 20:6d2af70c92ab | 739 | } |
darienf | 20:6d2af70c92ab | 740 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 741 | { |
darienf | 20:6d2af70c92ab | 742 | DebugMessage = string.Format("{0} exception {1}", System.Reflection.MethodInfo.GetCurrentMethod().Name, ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 743 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 744 | } |
darienf | 20:6d2af70c92ab | 745 | DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); |
darienf | 20:6d2af70c92ab | 746 | } |
darienf | 20:6d2af70c92ab | 747 | |
darienf | 20:6d2af70c92ab | 748 | |
darienf | 20:6d2af70c92ab | 749 | |
darienf | 20:6d2af70c92ab | 750 | private void prepareForOverlappedTransfer() |
darienf | 20:6d2af70c92ab | 751 | { |
darienf | 20:6d2af70c92ab | 752 | try |
darienf | 20:6d2af70c92ab | 753 | { |
darienf | 20:6d2af70c92ab | 754 | EventObject = FileIO.CreateEvent(IntPtr.Zero, false, false, String.Empty); |
darienf | 20:6d2af70c92ab | 755 | managedOverlapped.OffsetLow = 0; |
darienf | 20:6d2af70c92ab | 756 | managedOverlapped.OffsetHigh = 0; |
darienf | 20:6d2af70c92ab | 757 | managedOverlapped.EventHandle = EventObject; // HIDOverlapped is the overlapped structure used in ReadFile; EventObject will be signaled upon completion of ReadFile |
darienf | 20:6d2af70c92ab | 758 | nonManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(managedOverlapped)); |
darienf | 20:6d2af70c92ab | 759 | Marshal.StructureToPtr(managedOverlapped, nonManagedOverlapped, false); |
darienf | 20:6d2af70c92ab | 760 | |
darienf | 20:6d2af70c92ab | 761 | nonManagedBuffer = Marshal.AllocHGlobal(REPORT_SIZE); |
darienf | 20:6d2af70c92ab | 762 | } |
darienf | 20:6d2af70c92ab | 763 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 764 | { |
darienf | 20:6d2af70c92ab | 765 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 766 | } |
darienf | 20:6d2af70c92ab | 767 | } |
darienf | 20:6d2af70c92ab | 768 | |
darienf | 20:6d2af70c92ab | 769 | /// <summary> |
darienf | 20:6d2af70c92ab | 770 | /// Requests to receive a notification when a device is attached or removed. |
darienf | 20:6d2af70c92ab | 771 | /// </summary> |
darienf | 20:6d2af70c92ab | 772 | /// |
darienf | 20:6d2af70c92ab | 773 | /// <param name="formHandle"> handle to the window that will receive device events. </param> |
darienf | 20:6d2af70c92ab | 774 | /// <param name="classGuid"> device interface GUID. </param> |
darienf | 20:6d2af70c92ab | 775 | /// <param name="deviceNotificationHandle"> returned device notification handle. </param> |
darienf | 20:6d2af70c92ab | 776 | /// |
darienf | 20:6d2af70c92ab | 777 | /// <returns> |
darienf | 20:6d2af70c92ab | 778 | /// True on success. |
darienf | 20:6d2af70c92ab | 779 | /// </returns> |
darienf | 20:6d2af70c92ab | 780 | /// |
darienf | 20:6d2af70c92ab | 781 | public Boolean RegisterForDeviceNotifications(IntPtr formHandle, Guid classGuid, ref IntPtr deviceNotificationHandle) |
darienf | 20:6d2af70c92ab | 782 | { |
darienf | 20:6d2af70c92ab | 783 | DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE(); |
darienf | 20:6d2af70c92ab | 784 | IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero; |
darienf | 20:6d2af70c92ab | 785 | Int32 size = 0; |
darienf | 20:6d2af70c92ab | 786 | |
darienf | 20:6d2af70c92ab | 787 | try |
darienf | 20:6d2af70c92ab | 788 | { |
darienf | 20:6d2af70c92ab | 789 | size = Marshal.SizeOf(devBroadcastDeviceInterface); |
darienf | 20:6d2af70c92ab | 790 | devBroadcastDeviceInterface.dbcc_size = size; |
darienf | 20:6d2af70c92ab | 791 | devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; |
darienf | 20:6d2af70c92ab | 792 | devBroadcastDeviceInterface.dbcc_reserved = 0; |
darienf | 20:6d2af70c92ab | 793 | devBroadcastDeviceInterface.dbcc_classguid = classGuid; |
darienf | 20:6d2af70c92ab | 794 | |
darienf | 20:6d2af70c92ab | 795 | // Allocate memory for the buffer that holds the DEV_BROADCAST_DEVICEINTERFACE structure. |
darienf | 20:6d2af70c92ab | 796 | devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(size); |
darienf | 20:6d2af70c92ab | 797 | |
darienf | 20:6d2af70c92ab | 798 | // Copy the DEV_BROADCAST_DEVICEINTERFACE structure to the buffer. |
darienf | 20:6d2af70c92ab | 799 | // Set fDeleteOld True to prevent memory leaks. |
darienf | 20:6d2af70c92ab | 800 | Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true); |
darienf | 20:6d2af70c92ab | 801 | |
darienf | 20:6d2af70c92ab | 802 | // *** |
darienf | 20:6d2af70c92ab | 803 | // API function |
darienf | 20:6d2af70c92ab | 804 | |
darienf | 20:6d2af70c92ab | 805 | // summary |
darienf | 20:6d2af70c92ab | 806 | // Request to receive notification messages when a device in an interface class |
darienf | 20:6d2af70c92ab | 807 | // is attached or removed. |
darienf | 20:6d2af70c92ab | 808 | |
darienf | 20:6d2af70c92ab | 809 | // parameters |
darienf | 20:6d2af70c92ab | 810 | // Handle to the window that will receive device events. |
darienf | 20:6d2af70c92ab | 811 | // Pointer to a DEV_BROADCAST_DEVICEINTERFACE to specify the type of |
darienf | 20:6d2af70c92ab | 812 | // device to send notifications for. |
darienf | 20:6d2af70c92ab | 813 | // DEVICE_NOTIFY_WINDOW_HANDLE indicates the handle is a window handle. |
darienf | 20:6d2af70c92ab | 814 | |
darienf | 20:6d2af70c92ab | 815 | // Returns |
darienf | 20:6d2af70c92ab | 816 | // Device notification handle or NULL on failure. |
darienf | 20:6d2af70c92ab | 817 | // *** |
darienf | 20:6d2af70c92ab | 818 | |
darienf | 20:6d2af70c92ab | 819 | deviceNotificationHandle = RegisterDeviceNotification(formHandle, devBroadcastDeviceInterfaceBuffer, DEVICE_NOTIFY_WINDOW_HANDLE); |
darienf | 20:6d2af70c92ab | 820 | |
darienf | 20:6d2af70c92ab | 821 | // Marshal data from the unmanaged block devBroadcastDeviceInterfaceBuffer to the managed object devBroadcastDeviceInterface |
darienf | 20:6d2af70c92ab | 822 | // why? |
darienf | 20:6d2af70c92ab | 823 | Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface); |
darienf | 20:6d2af70c92ab | 824 | |
darienf | 20:6d2af70c92ab | 825 | return deviceNotificationHandle.ToInt32() == IntPtr.Zero.ToInt32() ? false : true; |
darienf | 20:6d2af70c92ab | 826 | } |
darienf | 20:6d2af70c92ab | 827 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 828 | { |
darienf | 20:6d2af70c92ab | 829 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 830 | } |
darienf | 20:6d2af70c92ab | 831 | finally |
darienf | 20:6d2af70c92ab | 832 | { |
darienf | 20:6d2af70c92ab | 833 | // Free the memory allocated previously by AllocHGlobal. |
darienf | 20:6d2af70c92ab | 834 | if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 835 | Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer); |
darienf | 20:6d2af70c92ab | 836 | } |
darienf | 20:6d2af70c92ab | 837 | } |
darienf | 20:6d2af70c92ab | 838 | |
darienf | 20:6d2af70c92ab | 839 | |
darienf | 20:6d2af70c92ab | 840 | |
darienf | 20:6d2af70c92ab | 841 | public Boolean DeviceIDMatch(Message m) |
darienf | 20:6d2af70c92ab | 842 | { |
darienf | 20:6d2af70c92ab | 843 | Int32 stringSize; |
darienf | 20:6d2af70c92ab | 844 | |
darienf | 20:6d2af70c92ab | 845 | try |
darienf | 20:6d2af70c92ab | 846 | { |
darienf | 20:6d2af70c92ab | 847 | DEV_BROADCAST_HDR devBroadcastHeader = new DEV_BROADCAST_HDR(); |
darienf | 20:6d2af70c92ab | 848 | DEV_BROADCAST_DEVICEINTERFACE_1 devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE_1(); |
darienf | 20:6d2af70c92ab | 849 | |
darienf | 20:6d2af70c92ab | 850 | // The LParam parameter of Message is a pointer to a DEV_BROADCAST_HDR structure. |
darienf | 20:6d2af70c92ab | 851 | Marshal.PtrToStructure(m.LParam, devBroadcastHeader); |
darienf | 20:6d2af70c92ab | 852 | if ((devBroadcastHeader.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)) |
darienf | 20:6d2af70c92ab | 853 | { |
darienf | 20:6d2af70c92ab | 854 | // The dbch_devicetype parameter indicates that the event applies to a device interface. |
darienf | 20:6d2af70c92ab | 855 | // So the structure in LParam is actually a DEV_BROADCAST_INTERFACE structure, |
darienf | 20:6d2af70c92ab | 856 | // which begins with a DEV_BROADCAST_HDR. |
darienf | 20:6d2af70c92ab | 857 | |
darienf | 20:6d2af70c92ab | 858 | // Obtain the number of characters in dbch_name by subtracting the 32 bytes |
darienf | 20:6d2af70c92ab | 859 | // in the strucutre that are not part of dbch_name and dividing by 2 because there are |
darienf | 20:6d2af70c92ab | 860 | // 2 bytes per character. |
darienf | 20:6d2af70c92ab | 861 | |
darienf | 20:6d2af70c92ab | 862 | stringSize = System.Convert.ToInt32((devBroadcastHeader.dbch_size - 32) / 2); |
darienf | 20:6d2af70c92ab | 863 | |
darienf | 20:6d2af70c92ab | 864 | // The dbcc_name parameter of devBroadcastDeviceInterface contains the device name. |
darienf | 20:6d2af70c92ab | 865 | // Trim dbcc_name to match the size of the String. |
darienf | 20:6d2af70c92ab | 866 | |
darienf | 20:6d2af70c92ab | 867 | devBroadcastDeviceInterface.dbcc_name = new Char[stringSize + 1]; |
darienf | 20:6d2af70c92ab | 868 | |
darienf | 20:6d2af70c92ab | 869 | // Marshal data from the unmanaged block pointed to by m.LParam |
darienf | 20:6d2af70c92ab | 870 | // to the managed object devBroadcastDeviceInterface. |
darienf | 20:6d2af70c92ab | 871 | |
darienf | 20:6d2af70c92ab | 872 | Marshal.PtrToStructure(m.LParam, devBroadcastDeviceInterface); |
darienf | 20:6d2af70c92ab | 873 | |
darienf | 20:6d2af70c92ab | 874 | // Store the device name in a String. |
darienf | 20:6d2af70c92ab | 875 | |
darienf | 20:6d2af70c92ab | 876 | String DeviceNameString = new String(devBroadcastDeviceInterface.dbcc_name, 0, stringSize); |
darienf | 20:6d2af70c92ab | 877 | |
darienf | 20:6d2af70c92ab | 878 | // Compare the name of the newly attached device with the name of the device |
darienf | 20:6d2af70c92ab | 879 | // the application is accessing (deviceID). |
darienf | 20:6d2af70c92ab | 880 | // Set ignorecase True. |
darienf | 20:6d2af70c92ab | 881 | |
darienf | 20:6d2af70c92ab | 882 | return (DeviceNameString.ToLower().IndexOf(deviceID.ToLower()) == -1) ? false : true; |
darienf | 20:6d2af70c92ab | 883 | } |
darienf | 20:6d2af70c92ab | 884 | else |
darienf | 20:6d2af70c92ab | 885 | return false; |
darienf | 20:6d2af70c92ab | 886 | } |
darienf | 20:6d2af70c92ab | 887 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 888 | { |
darienf | 20:6d2af70c92ab | 889 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 890 | } |
darienf | 20:6d2af70c92ab | 891 | } |
darienf | 20:6d2af70c92ab | 892 | #endregion |
darienf | 20:6d2af70c92ab | 893 | |
darienf | 20:6d2af70c92ab | 894 | #region Send/Receive HID reports |
darienf | 20:6d2af70c92ab | 895 | |
darienf | 20:6d2af70c92ab | 896 | public void FlushQueue() |
darienf | 20:6d2af70c92ab | 897 | { |
darienf | 20:6d2af70c92ab | 898 | try |
darienf | 20:6d2af70c92ab | 899 | { |
darienf | 20:6d2af70c92ab | 900 | if (writeHandle == null) |
darienf | 20:6d2af70c92ab | 901 | { |
darienf | 20:6d2af70c92ab | 902 | return; |
darienf | 20:6d2af70c92ab | 903 | } |
darienf | 20:6d2af70c92ab | 904 | if (readHandle == null) |
darienf | 20:6d2af70c92ab | 905 | { |
darienf | 20:6d2af70c92ab | 906 | return; |
darienf | 20:6d2af70c92ab | 907 | } |
darienf | 20:6d2af70c92ab | 908 | |
darienf | 20:6d2af70c92ab | 909 | HidD_FlushQueue(writeHandle); |
darienf | 20:6d2af70c92ab | 910 | HidD_FlushQueue(readHandle); |
darienf | 20:6d2af70c92ab | 911 | } |
darienf | 20:6d2af70c92ab | 912 | catch |
darienf | 20:6d2af70c92ab | 913 | { |
darienf | 20:6d2af70c92ab | 914 | throw new Exception(new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 915 | } |
darienf | 20:6d2af70c92ab | 916 | } |
darienf | 20:6d2af70c92ab | 917 | |
darienf | 20:6d2af70c92ab | 918 | public void writeReadHID() |
darienf | 20:6d2af70c92ab | 919 | { |
darienf | 20:6d2af70c92ab | 920 | try |
darienf | 20:6d2af70c92ab | 921 | { |
darienf | 20:6d2af70c92ab | 922 | if (writeHandle == null) |
darienf | 20:6d2af70c92ab | 923 | { |
darienf | 20:6d2af70c92ab | 924 | return; |
darienf | 20:6d2af70c92ab | 925 | } |
darienf | 20:6d2af70c92ab | 926 | if (readHandle == null) |
darienf | 20:6d2af70c92ab | 927 | { |
darienf | 20:6d2af70c92ab | 928 | return; |
darienf | 20:6d2af70c92ab | 929 | } |
darienf | 20:6d2af70c92ab | 930 | |
darienf | 20:6d2af70c92ab | 931 | writeHID(); |
darienf | 20:6d2af70c92ab | 932 | readHID(); |
darienf | 20:6d2af70c92ab | 933 | } |
darienf | 20:6d2af70c92ab | 934 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 935 | { |
darienf | 20:6d2af70c92ab | 936 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 937 | } |
darienf | 20:6d2af70c92ab | 938 | } |
darienf | 20:6d2af70c92ab | 939 | |
darienf | 20:6d2af70c92ab | 940 | public void writeHID() |
darienf | 20:6d2af70c92ab | 941 | { |
darienf | 20:6d2af70c92ab | 942 | if (writeHandle == null) |
darienf | 20:6d2af70c92ab | 943 | { |
darienf | 20:6d2af70c92ab | 944 | return; |
darienf | 20:6d2af70c92ab | 945 | } |
darienf | 20:6d2af70c92ab | 946 | if (readHandle == null) |
darienf | 20:6d2af70c92ab | 947 | { |
darienf | 20:6d2af70c92ab | 948 | return; |
darienf | 20:6d2af70c92ab | 949 | } |
darienf | 20:6d2af70c92ab | 950 | |
darienf | 20:6d2af70c92ab | 951 | int BytesSucceed; |
darienf | 20:6d2af70c92ab | 952 | bool api_status; |
darienf | 20:6d2af70c92ab | 953 | |
darienf | 20:6d2af70c92ab | 954 | try |
darienf | 20:6d2af70c92ab | 955 | { |
darienf | 20:6d2af70c92ab | 956 | BytesSucceed = 0; |
darienf | 20:6d2af70c92ab | 957 | //Byte[] outputReportBuffer = new Byte[REPORT_SIZE]; |
darienf | 20:6d2af70c92ab | 958 | |
darienf | 20:6d2af70c92ab | 959 | //for (int i = 0; i < REPORT_SIZE; i++) |
darienf | 20:6d2af70c92ab | 960 | // outputReportBuffer[i] = IOBuf[i]; |
darienf | 20:6d2af70c92ab | 961 | //api_status = FileIO.WriteFile(writeHandle, outputReportBuffer, outputReportBuffer.Length, ref BytesSucceed, IntPtr.Zero); |
darienf | 20:6d2af70c92ab | 962 | |
darienf | 20:6d2af70c92ab | 963 | Marshal.Copy(IOBuf, 0, nonManagedBuffer, REPORT_SIZE); |
darienf | 20:6d2af70c92ab | 964 | api_status = FileIO.WriteFile(writeHandle, nonManagedBuffer, REPORT_SIZE, ref BytesSucceed, IntPtr.Zero); |
darienf | 20:6d2af70c92ab | 965 | |
darienf | 20:6d2af70c92ab | 966 | //endpoint in interrupt at uC occurs after this WriteFile call since the in data is ready and the host takes it; endpoint in interrupt does not occur after ReadFile call |
darienf | 20:6d2af70c92ab | 967 | |
darienf | 20:6d2af70c92ab | 968 | if (api_status == false) |
darienf | 20:6d2af70c92ab | 969 | { |
darienf | 20:6d2af70c92ab | 970 | //MessageBox.Show(Err.LastDllError); |
darienf | 20:6d2af70c92ab | 971 | throw new Exception(support.ResultOfAPICall("API WriteFile error")); |
darienf | 20:6d2af70c92ab | 972 | } |
darienf | 20:6d2af70c92ab | 973 | } |
darienf | 20:6d2af70c92ab | 974 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 975 | { |
darienf | 20:6d2af70c92ab | 976 | throw new Exception(ex.Message + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 977 | } |
darienf | 20:6d2af70c92ab | 978 | } |
darienf | 20:6d2af70c92ab | 979 | |
darienf | 20:6d2af70c92ab | 980 | public void readHID() |
darienf | 20:6d2af70c92ab | 981 | { |
darienf | 20:6d2af70c92ab | 982 | if (writeHandle == null) |
darienf | 20:6d2af70c92ab | 983 | { |
darienf | 20:6d2af70c92ab | 984 | return; |
darienf | 20:6d2af70c92ab | 985 | } |
darienf | 20:6d2af70c92ab | 986 | if (readHandle == null) |
darienf | 20:6d2af70c92ab | 987 | { |
darienf | 20:6d2af70c92ab | 988 | return; |
darienf | 20:6d2af70c92ab | 989 | } |
darienf | 20:6d2af70c92ab | 990 | |
darienf | 20:6d2af70c92ab | 991 | int BytesSucceed; |
darienf | 20:6d2af70c92ab | 992 | bool api_status; |
darienf | 20:6d2af70c92ab | 993 | int status; |
darienf | 20:6d2af70c92ab | 994 | |
darienf | 20:6d2af70c92ab | 995 | try |
darienf | 20:6d2af70c92ab | 996 | { |
darienf | 20:6d2af70c92ab | 997 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 998 | |
darienf | 20:6d2af70c92ab | 999 | BytesSucceed = 0; |
darienf | 20:6d2af70c92ab | 1000 | |
darienf | 20:6d2af70c92ab | 1001 | api_status = FileIO.ReadFile(readHandle, nonManagedBuffer, REPORT_SIZE, ref BytesSucceed, nonManagedOverlapped); |
darienf | 20:6d2af70c92ab | 1002 | |
darienf | 20:6d2af70c92ab | 1003 | if (api_status == false) |
darienf | 20:6d2af70c92ab | 1004 | { |
darienf | 20:6d2af70c92ab | 1005 | //MsgBox(Err.LastDllError) |
darienf | 20:6d2af70c92ab | 1006 | status = FileIO.WaitForSingleObject(EventObject, IOtimeout); |
darienf | 20:6d2af70c92ab | 1007 | |
darienf | 20:6d2af70c92ab | 1008 | if (status != FileIO.WAIT_OBJECT_0) |
darienf | 20:6d2af70c92ab | 1009 | { |
darienf | 20:6d2af70c92ab | 1010 | api_status = FileIO.CancelIo(readHandle); |
darienf | 20:6d2af70c92ab | 1011 | throw new Exception(support.ResultOfAPICall("API ReadFile error")); |
darienf | 20:6d2af70c92ab | 1012 | } |
darienf | 20:6d2af70c92ab | 1013 | FileIO.GetOverlappedResult(readHandle, nonManagedOverlapped, ref BytesSucceed, false); |
darienf | 20:6d2af70c92ab | 1014 | } |
darienf | 20:6d2af70c92ab | 1015 | |
darienf | 20:6d2af70c92ab | 1016 | // TODO1: OS24EVK-57 2015-04-01 myHID.readHID2() needs to return result into IOBuf. But IOBuf = new byte[64], do we replace with IOBuf = new byte[128]? Does this affect readHID()? |
darienf | 20:6d2af70c92ab | 1017 | if (BytesSucceed > IOBuf.Length) |
darienf | 20:6d2af70c92ab | 1018 | { |
darienf | 20:6d2af70c92ab | 1019 | IOBuf = new byte[BytesSucceed]; |
darienf | 20:6d2af70c92ab | 1020 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1021 | } |
darienf | 20:6d2af70c92ab | 1022 | Marshal.Copy(nonManagedBuffer, IOBuf, 0, BytesSucceed); |
darienf | 20:6d2af70c92ab | 1023 | } |
darienf | 20:6d2af70c92ab | 1024 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1025 | { |
darienf | 20:6d2af70c92ab | 1026 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1027 | } |
darienf | 20:6d2af70c92ab | 1028 | } |
darienf | 20:6d2af70c92ab | 1029 | |
darienf | 20:6d2af70c92ab | 1030 | public void readHID2() // this function is for testing multiple report read on a single ReadFile() |
darienf | 20:6d2af70c92ab | 1031 | { |
darienf | 20:6d2af70c92ab | 1032 | if (writeHandle == null) |
darienf | 20:6d2af70c92ab | 1033 | { |
darienf | 20:6d2af70c92ab | 1034 | return; |
darienf | 20:6d2af70c92ab | 1035 | } |
darienf | 20:6d2af70c92ab | 1036 | if (readHandle == null) |
darienf | 20:6d2af70c92ab | 1037 | { |
darienf | 20:6d2af70c92ab | 1038 | return; |
darienf | 20:6d2af70c92ab | 1039 | } |
darienf | 20:6d2af70c92ab | 1040 | |
darienf | 20:6d2af70c92ab | 1041 | int BytesSucceed; |
darienf | 20:6d2af70c92ab | 1042 | bool api_status; |
darienf | 20:6d2af70c92ab | 1043 | int status; |
darienf | 20:6d2af70c92ab | 1044 | |
darienf | 20:6d2af70c92ab | 1045 | try |
darienf | 20:6d2af70c92ab | 1046 | { |
darienf | 20:6d2af70c92ab | 1047 | int size = 128; |
darienf | 20:6d2af70c92ab | 1048 | //byte[] buf = new byte[size]; |
darienf | 20:6d2af70c92ab | 1049 | IntPtr nonManagedBuf = Marshal.AllocHGlobal(size); |
darienf | 20:6d2af70c92ab | 1050 | //Array.Clear(buf, 0, size); |
darienf | 20:6d2af70c92ab | 1051 | |
darienf | 20:6d2af70c92ab | 1052 | BytesSucceed = 0; |
darienf | 20:6d2af70c92ab | 1053 | |
darienf | 20:6d2af70c92ab | 1054 | api_status = FileIO.ReadFile(readHandle, nonManagedBuf, size, ref BytesSucceed, nonManagedOverlapped); |
darienf | 20:6d2af70c92ab | 1055 | |
darienf | 20:6d2af70c92ab | 1056 | if (api_status == false) |
darienf | 20:6d2af70c92ab | 1057 | { |
darienf | 20:6d2af70c92ab | 1058 | //MsgBox(Err.LastDllError) |
darienf | 20:6d2af70c92ab | 1059 | status = FileIO.WaitForSingleObject(EventObject, IOtimeout); |
darienf | 20:6d2af70c92ab | 1060 | |
darienf | 20:6d2af70c92ab | 1061 | if (status != FileIO.WAIT_OBJECT_0) |
darienf | 20:6d2af70c92ab | 1062 | { |
darienf | 20:6d2af70c92ab | 1063 | api_status = FileIO.CancelIo(readHandle); |
darienf | 20:6d2af70c92ab | 1064 | throw new Exception(support.ResultOfAPICall("API ReadFile error")); |
darienf | 20:6d2af70c92ab | 1065 | } |
darienf | 20:6d2af70c92ab | 1066 | FileIO.GetOverlappedResult(readHandle, nonManagedOverlapped, ref BytesSucceed, false); |
darienf | 20:6d2af70c92ab | 1067 | } |
darienf | 20:6d2af70c92ab | 1068 | |
darienf | 20:6d2af70c92ab | 1069 | // TODO1: OS24EVK-57 2015-04-01 myHID.readHID2() needs to return result into IOBuf. But IOBuf = new byte[64], do we replace with IOBuf = new byte[128]? Does this affect readHID()? |
darienf | 20:6d2af70c92ab | 1070 | if (BytesSucceed > IOBuf.Length) |
darienf | 20:6d2af70c92ab | 1071 | { |
darienf | 20:6d2af70c92ab | 1072 | IOBuf = new byte[BytesSucceed]; |
darienf | 20:6d2af70c92ab | 1073 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1074 | } |
darienf | 20:6d2af70c92ab | 1075 | Marshal.Copy(nonManagedBuf, IOBuf, 0, BytesSucceed); |
darienf | 20:6d2af70c92ab | 1076 | |
darienf | 20:6d2af70c92ab | 1077 | if (nonManagedBuf != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 1078 | Marshal.FreeHGlobal(nonManagedBuffer); |
darienf | 20:6d2af70c92ab | 1079 | } |
darienf | 20:6d2af70c92ab | 1080 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1081 | { |
darienf | 20:6d2af70c92ab | 1082 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1083 | } |
darienf | 20:6d2af70c92ab | 1084 | } |
darienf | 20:6d2af70c92ab | 1085 | #endregion |
darienf | 20:6d2af70c92ab | 1086 | |
darienf | 20:6d2af70c92ab | 1087 | #region Close HID |
darienf | 20:6d2af70c92ab | 1088 | public void closeHIDhandles() |
darienf | 20:6d2af70c92ab | 1089 | { |
darienf | 20:6d2af70c92ab | 1090 | try |
darienf | 20:6d2af70c92ab | 1091 | { |
darienf | 20:6d2af70c92ab | 1092 | if (desiredHIDPathNameArray.Count != 0) |
darienf | 20:6d2af70c92ab | 1093 | { |
darienf | 20:6d2af70c92ab | 1094 | foreach (Object obj in writeHandleArray) |
darienf | 20:6d2af70c92ab | 1095 | ((SafeFileHandle)obj).Close(); |
darienf | 20:6d2af70c92ab | 1096 | writeHandleArray.Clear(); |
darienf | 20:6d2af70c92ab | 1097 | writeHandle = null; |
darienf | 20:6d2af70c92ab | 1098 | foreach (Object obj in readHandleArray) |
darienf | 20:6d2af70c92ab | 1099 | ((SafeFileHandle)obj).Close(); |
darienf | 20:6d2af70c92ab | 1100 | readHandleArray.Clear(); |
darienf | 20:6d2af70c92ab | 1101 | readHandle = null; |
darienf | 20:6d2af70c92ab | 1102 | } |
darienf | 20:6d2af70c92ab | 1103 | } |
darienf | 20:6d2af70c92ab | 1104 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1105 | { |
darienf | 20:6d2af70c92ab | 1106 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1107 | } |
darienf | 20:6d2af70c92ab | 1108 | } |
darienf | 20:6d2af70c92ab | 1109 | /// <summary> |
darienf | 20:6d2af70c92ab | 1110 | /// Requests to stop receiving notification messages when a device in an |
darienf | 20:6d2af70c92ab | 1111 | /// interface class is attached or removed. |
darienf | 20:6d2af70c92ab | 1112 | /// </summary> |
darienf | 20:6d2af70c92ab | 1113 | /// |
darienf | 20:6d2af70c92ab | 1114 | /// <param name="deviceNotificationHandle"> handle returned previously by |
darienf | 20:6d2af70c92ab | 1115 | /// RegisterDeviceNotification. </param> |
darienf | 20:6d2af70c92ab | 1116 | |
darienf | 20:6d2af70c92ab | 1117 | public void StopReceivingDeviceNotifications(IntPtr deviceNotificationHandle) |
darienf | 20:6d2af70c92ab | 1118 | { |
darienf | 20:6d2af70c92ab | 1119 | try |
darienf | 20:6d2af70c92ab | 1120 | { |
darienf | 20:6d2af70c92ab | 1121 | UnregisterDeviceNotification(deviceNotificationHandle); |
darienf | 20:6d2af70c92ab | 1122 | } |
darienf | 20:6d2af70c92ab | 1123 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1124 | { |
darienf | 20:6d2af70c92ab | 1125 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1126 | } |
darienf | 20:6d2af70c92ab | 1127 | } |
darienf | 20:6d2af70c92ab | 1128 | public void freeHeap() |
darienf | 20:6d2af70c92ab | 1129 | { |
darienf | 20:6d2af70c92ab | 1130 | try |
darienf | 20:6d2af70c92ab | 1131 | { |
darienf | 20:6d2af70c92ab | 1132 | if (nonManagedBuffer != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 1133 | Marshal.FreeHGlobal(nonManagedBuffer); |
darienf | 20:6d2af70c92ab | 1134 | if (nonManagedOverlapped != IntPtr.Zero) |
darienf | 20:6d2af70c92ab | 1135 | Marshal.FreeHGlobal(nonManagedOverlapped); |
darienf | 20:6d2af70c92ab | 1136 | } |
darienf | 20:6d2af70c92ab | 1137 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1138 | { |
darienf | 20:6d2af70c92ab | 1139 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1140 | } |
darienf | 20:6d2af70c92ab | 1141 | } |
darienf | 20:6d2af70c92ab | 1142 | #endregion |
darienf | 20:6d2af70c92ab | 1143 | |
darienf | 20:6d2af70c92ab | 1144 | #region Create Report |
darienf | 20:6d2af70c92ab | 1145 | public void reportID() |
darienf | 20:6d2af70c92ab | 1146 | { |
darienf | 20:6d2af70c92ab | 1147 | try |
darienf | 20:6d2af70c92ab | 1148 | { |
darienf | 20:6d2af70c92ab | 1149 | if (explicit_report_id) |
darienf | 20:6d2af70c92ab | 1150 | IOBuf[0] = SHORT_REPORT_ID; // explicit out report ID in HID's descriptor |
darienf | 20:6d2af70c92ab | 1151 | else |
darienf | 20:6d2af70c92ab | 1152 | IOBuf[0] = DEFAULT_REPORT_ID; // default report ID; this byte is dropped in transfer, so we don't really waste a byte transmitting it |
darienf | 20:6d2af70c92ab | 1153 | } |
darienf | 20:6d2af70c92ab | 1154 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1155 | { |
darienf | 20:6d2af70c92ab | 1156 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1157 | } |
darienf | 20:6d2af70c92ab | 1158 | } |
darienf | 20:6d2af70c92ab | 1159 | |
darienf | 20:6d2af70c92ab | 1160 | #region I2C Commands |
darienf | 20:6d2af70c92ab | 1161 | |
darienf | 20:6d2af70c92ab | 1162 | #region oldCommands |
darienf | 20:6d2af70c92ab | 1163 | /*public int readI2C(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] readData, byte[] reg, bool ignoreNACK = false) |
darienf | 20:6d2af70c92ab | 1164 | { |
darienf | 20:6d2af70c92ab | 1165 | //readData is passed back to caller with the read data |
darienf | 20:6d2af70c92ab | 1166 | int status; |
darienf | 20:6d2af70c92ab | 1167 | int i; |
darienf | 20:6d2af70c92ab | 1168 | |
darienf | 20:6d2af70c92ab | 1169 | try |
darienf | 20:6d2af70c92ab | 1170 | { |
darienf | 20:6d2af70c92ab | 1171 | if (numDataBytes > REPORT_SIZE - 2) { |
darienf | 20:6d2af70c92ab | 1172 | throw new Exception("USB buffer overflow"); |
darienf | 20:6d2af70c92ab | 1173 | } |
darienf | 20:6d2af70c92ab | 1174 | |
darienf | 20:6d2af70c92ab | 1175 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in readI2C |
darienf | 20:6d2af70c92ab | 1176 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1177 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1178 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1179 | |
darienf | 20:6d2af70c92ab | 1180 | reportID(); |
darienf | 20:6d2af70c92ab | 1181 | IOBuf[1] = I2C_TRANSACTION; // I2C transaction -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1182 | IOBuf[2] = (byte)(deviceAddress | 1); // set read bit |
darienf | 20:6d2af70c92ab | 1183 | IOBuf[3] = numDataBytes; |
darienf | 20:6d2af70c92ab | 1184 | IOBuf[4] = numRegBytes; |
darienf | 20:6d2af70c92ab | 1185 | // TODO1: OS24EVK-57 HID readI2C no validation that numRegBytes == reg.Length ? |
darienf | 20:6d2af70c92ab | 1186 | for (i = 0; i < numRegBytes; i++) { |
darienf | 20:6d2af70c92ab | 1187 | IOBuf[i + 5] = reg[i]; |
darienf | 20:6d2af70c92ab | 1188 | } |
darienf | 20:6d2af70c92ab | 1189 | |
darienf | 20:6d2af70c92ab | 1190 | writeHID(); |
darienf | 20:6d2af70c92ab | 1191 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1192 | |
darienf | 20:6d2af70c92ab | 1193 | status = checkNACK(); |
darienf | 20:6d2af70c92ab | 1194 | |
darienf | 20:6d2af70c92ab | 1195 | // checkNACK also reads the data, assuming NACK didn't occur |
darienf | 20:6d2af70c92ab | 1196 | if (status == I2C_NACK_ERROR && ignoreNACK == false) { |
darienf | 20:6d2af70c92ab | 1197 | throw new Exception("invalid I2C address"); |
darienf | 20:6d2af70c92ab | 1198 | } |
darienf | 20:6d2af70c92ab | 1199 | |
darienf | 20:6d2af70c92ab | 1200 | for (i = 0; i < numDataBytes; i++) { |
darienf | 20:6d2af70c92ab | 1201 | readData[i] = IOBuf[i + 2]; |
darienf | 20:6d2af70c92ab | 1202 | } |
darienf | 20:6d2af70c92ab | 1203 | |
darienf | 20:6d2af70c92ab | 1204 | return status; // the caller will not need the return value if an exception is thrown |
darienf | 20:6d2af70c92ab | 1205 | } |
darienf | 20:6d2af70c92ab | 1206 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1207 | { |
darienf | 20:6d2af70c92ab | 1208 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1209 | } |
darienf | 20:6d2af70c92ab | 1210 | }*/ |
darienf | 20:6d2af70c92ab | 1211 | |
darienf | 20:6d2af70c92ab | 1212 | /*public void writeI2C(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] data, byte[] reg, bool ignoreNACK = false) |
darienf | 20:6d2af70c92ab | 1213 | { |
darienf | 20:6d2af70c92ab | 1214 | int i; |
darienf | 20:6d2af70c92ab | 1215 | |
darienf | 20:6d2af70c92ab | 1216 | try |
darienf | 20:6d2af70c92ab | 1217 | { |
darienf | 20:6d2af70c92ab | 1218 | if (numDataBytes > REPORT_SIZE - 5) { |
darienf | 20:6d2af70c92ab | 1219 | throw new Exception("USB buffer overflow"); |
darienf | 20:6d2af70c92ab | 1220 | } |
darienf | 20:6d2af70c92ab | 1221 | |
darienf | 20:6d2af70c92ab | 1222 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in writeI2C |
darienf | 20:6d2af70c92ab | 1223 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1224 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1225 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1226 | |
darienf | 20:6d2af70c92ab | 1227 | //send data to tell uC to do I2C read from slave |
darienf | 20:6d2af70c92ab | 1228 | reportID(); |
darienf | 20:6d2af70c92ab | 1229 | IOBuf[1] = I2C_TRANSACTION; // I2C transaction -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1230 | IOBuf[2] = deviceAddress; |
darienf | 20:6d2af70c92ab | 1231 | IOBuf[3] = numDataBytes; |
darienf | 20:6d2af70c92ab | 1232 | IOBuf[4] = numRegBytes; |
darienf | 20:6d2af70c92ab | 1233 | for (i = 0; i < numRegBytes; i++) { |
darienf | 20:6d2af70c92ab | 1234 | IOBuf[i + 5] = reg[i]; |
darienf | 20:6d2af70c92ab | 1235 | } |
darienf | 20:6d2af70c92ab | 1236 | for (i = 0; i < numDataBytes; i++) { |
darienf | 20:6d2af70c92ab | 1237 | IOBuf[i + 5 + numRegBytes] = data[i]; |
darienf | 20:6d2af70c92ab | 1238 | } |
darienf | 20:6d2af70c92ab | 1239 | |
darienf | 20:6d2af70c92ab | 1240 | writeHID(); |
darienf | 20:6d2af70c92ab | 1241 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1242 | |
darienf | 20:6d2af70c92ab | 1243 | if (checkNACK() == I2C_NACK_ERROR && ignoreNACK == false) { |
darienf | 20:6d2af70c92ab | 1244 | throw new Exception("invalid I2C address"); |
darienf | 20:6d2af70c92ab | 1245 | } |
darienf | 20:6d2af70c92ab | 1246 | } |
darienf | 20:6d2af70c92ab | 1247 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1248 | { |
darienf | 20:6d2af70c92ab | 1249 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1250 | } |
darienf | 20:6d2af70c92ab | 1251 | } |
darienf | 20:6d2af70c92ab | 1252 | |
darienf | 20:6d2af70c92ab | 1253 | private int checkNACK() |
darienf | 20:6d2af70c92ab | 1254 | { |
darienf | 20:6d2af70c92ab | 1255 | // Check if I2C write was really succesful or a NACK occurred, since this is independent of USB success |
darienf | 20:6d2af70c92ab | 1256 | // This function also reads all the data from the report. If NACK occured, the data is invalid. |
darienf | 20:6d2af70c92ab | 1257 | try |
darienf | 20:6d2af70c92ab | 1258 | { |
darienf | 20:6d2af70c92ab | 1259 | readHID(); |
darienf | 20:6d2af70c92ab | 1260 | return (IOBuf[1] == 0 ? I2C_SUCCESS : I2C_NACK_ERROR); // the caller will not need the return value if an exception is thrown |
darienf | 20:6d2af70c92ab | 1261 | } |
darienf | 20:6d2af70c92ab | 1262 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1263 | { |
darienf | 20:6d2af70c92ab | 1264 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1265 | } |
darienf | 20:6d2af70c92ab | 1266 | }*/ |
darienf | 20:6d2af70c92ab | 1267 | |
darienf | 20:6d2af70c92ab | 1268 | // only allows 2 byte data |
darienf | 20:6d2af70c92ab | 1269 | /*public void setBitI2C(byte deviceAddress, int reg, byte range, int data, bool ignoreNACK = false) |
darienf | 20:6d2af70c92ab | 1270 | { |
darienf | 20:6d2af70c92ab | 1271 | int i; |
darienf | 20:6d2af70c92ab | 1272 | |
darienf | 20:6d2af70c92ab | 1273 | try |
darienf | 20:6d2af70c92ab | 1274 | { |
darienf | 20:6d2af70c92ab | 1275 | int LSb = range & 0xF; |
darienf | 20:6d2af70c92ab | 1276 | int MSb = (range & 0xF0) >> 4; |
darienf | 20:6d2af70c92ab | 1277 | if (MSb < LSb) |
darienf | 20:6d2af70c92ab | 1278 | throw new Exception("invalid bit range"); |
darienf | 20:6d2af70c92ab | 1279 | //if (numDataBytes > REPORT_SIZE - 5) |
darienf | 20:6d2af70c92ab | 1280 | // throw new Exception("USB buffer overflow"); |
darienf | 20:6d2af70c92ab | 1281 | |
darienf | 20:6d2af70c92ab | 1282 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in setBitI2C |
darienf | 20:6d2af70c92ab | 1283 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1284 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1285 | |
darienf | 20:6d2af70c92ab | 1286 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1287 | |
darienf | 20:6d2af70c92ab | 1288 | //send data to tell uC to do I2C read from slave |
darienf | 20:6d2af70c92ab | 1289 | reportID(); |
darienf | 20:6d2af70c92ab | 1290 | IOBuf[1] = I2C_TRANSACTION; // I2C transaction -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1291 | IOBuf[2] = deviceAddress; |
darienf | 20:6d2af70c92ab | 1292 | byte numDataBytes = (byte)(MSb > 7 ? 2 : 1); |
darienf | 20:6d2af70c92ab | 1293 | IOBuf[3] = numDataBytes; |
darienf | 20:6d2af70c92ab | 1294 | byte numRegBytes = (byte)Math.Ceiling(reg / 255.0); |
darienf | 20:6d2af70c92ab | 1295 | IOBuf[4] = numRegBytes; |
darienf | 20:6d2af70c92ab | 1296 | for (i = 0; i < numRegBytes; i++) |
darienf | 20:6d2af70c92ab | 1297 | IOBuf[i + 5] = (byte)((reg>>(8*i)) & 0xFF); |
darienf | 20:6d2af70c92ab | 1298 | //for (i = 0; i < numDataBytes; i++) |
darienf | 20:6d2af70c92ab | 1299 | // IOBuf[i + 5 + numRegBytes] = data[i]; |
darienf | 20:6d2af70c92ab | 1300 | |
darienf | 20:6d2af70c92ab | 1301 | writeHID(); |
darienf | 20:6d2af70c92ab | 1302 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1303 | |
darienf | 20:6d2af70c92ab | 1304 | if (checkNACK() == I2C_NACK_ERROR && ignoreNACK == false) |
darienf | 20:6d2af70c92ab | 1305 | throw new Exception("invalid I2C address"); |
darienf | 20:6d2af70c92ab | 1306 | } |
darienf | 20:6d2af70c92ab | 1307 | catch (Exception ex) |
darienf | 20:6d2af70c92ab | 1308 | { |
darienf | 20:6d2af70c92ab | 1309 | throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); |
darienf | 20:6d2af70c92ab | 1310 | } |
darienf | 20:6d2af70c92ab | 1311 | }*/ |
darienf | 20:6d2af70c92ab | 1312 | |
darienf | 20:6d2af70c92ab | 1313 | |
darienf | 20:6d2af70c92ab | 1314 | /// <summary> |
darienf | 20:6d2af70c92ab | 1315 | /// <para>Firmware command code 4 OUT = I2C configuration </para> |
darienf | 20:6d2af70c92ab | 1316 | /// (IO_BUFFER.Ptr[3+gOffset] & 1) ? (SMB0CF |= 0x10) : (SMB0CF &= 0xEF) |
darienf | 20:6d2af70c92ab | 1317 | /// </summary> |
darienf | 20:6d2af70c92ab | 1318 | /// <param name="gI2Cflags">bit0 == 1: repeated start</param> |
darienf | 20:6d2af70c92ab | 1319 | /// <param name="EXTHOLD">set EXTHOLD bit (SMBus setup / hold time extension)</param> |
darienf | 20:6d2af70c92ab | 1320 | /// <param name="ClearSDAbyTogglingSCL">clear SDA by toggling SCL</param> |
darienf | 20:6d2af70c92ab | 1321 | /* public void I2CConfigSet(byte gI2Cflags, byte EXTHOLD, byte ClearSDAbyTogglingSCL) |
darienf | 20:6d2af70c92ab | 1322 | { |
darienf | 20:6d2af70c92ab | 1323 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CConfigSet(byte gI2Cflags, byte EXTHOLD, byte ClearSDAbyTogglingSCL) |
darienf | 20:6d2af70c92ab | 1324 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CConfigSet |
darienf | 20:6d2af70c92ab | 1325 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1326 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1327 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1328 | reportID(); |
darienf | 20:6d2af70c92ab | 1329 | IOBuf[1] = 4; // case (4): //I2C configuration -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1330 | IOBuf[2] = 0; // case (0): // write |
darienf | 20:6d2af70c92ab | 1331 | IOBuf[3] = gI2Cflags; // gI2Cflags = IO_BUFFER.Ptr[2+gOffset]; |
darienf | 20:6d2af70c92ab | 1332 | // // bit0 == 1: repeated start (versus stop/start) after write before read (applies to random read only) |
darienf | 20:6d2af70c92ab | 1333 | // // bit1 == 1: start random read with a write, but end the write right away without sending reg address (emulate Jungo dongle for debug purposes) |
darienf | 20:6d2af70c92ab | 1334 | // // bit2 == 1: repeat transaction if slave NACKs (suggest not to use this) |
darienf | 20:6d2af70c92ab | 1335 | // // all flags are OR'd |
darienf | 20:6d2af70c92ab | 1336 | IOBuf[4] = EXTHOLD; // (IO_BUFFER.Ptr[3+gOffset] & 1) ? (SMB0CF |= 0x10) : (SMB0CF &= 0xEF); // set EXTHOLD bit (SMBus setup / hold time extension) |
darienf | 20:6d2af70c92ab | 1337 | IOBuf[5] = ClearSDAbyTogglingSCL; // if (IO_BUFFER.Ptr[4+gOffset] & 1) // clear SDA by toggling SCL |
darienf | 20:6d2af70c92ab | 1338 | // {s |
darienf | 20:6d2af70c92ab | 1339 | // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; |
darienf | 20:6d2af70c92ab | 1340 | // IO_BUFFER.Ptr[0+gOffset] = 0; // transaction error status |
darienf | 20:6d2af70c92ab | 1341 | // IO_BUFFER.Ptr[1+gOffset] = clearSDA(); // clearSDA error status |
darienf | 20:6d2af70c92ab | 1342 | // SendPacket(); // send status of clearing SDA to host |
darienf | 20:6d2af70c92ab | 1343 | // } |
darienf | 20:6d2af70c92ab | 1344 | writeHID(); |
darienf | 20:6d2af70c92ab | 1345 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1346 | }*/ |
darienf | 20:6d2af70c92ab | 1347 | |
darienf | 20:6d2af70c92ab | 1348 | /// <summary> |
darienf | 20:6d2af70c92ab | 1349 | /// <para>Firmware command code 4 IN = I2C configuration </para> |
darienf | 20:6d2af70c92ab | 1350 | /// (IO_BUFFER.Ptr[3+gOffset] & 1) ? (SMB0CF |= 0x10) : (SMB0CF &= 0xEF) |
darienf | 20:6d2af70c92ab | 1351 | /// </summary> |
darienf | 20:6d2af70c92ab | 1352 | /// <param name="gI2Cflags">bit0 == 1: repeated start</param> |
darienf | 20:6d2af70c92ab | 1353 | /// <param name="EXTHOLD">SMB0CF & 0x10</param> |
darienf | 20:6d2af70c92ab | 1354 | /* public void I2CConfigGet(out byte gI2Cflags, out byte EXTHOLD) |
darienf | 20:6d2af70c92ab | 1355 | { |
darienf | 20:6d2af70c92ab | 1356 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CConfigGet(out byte gI2Cflags, out byte EXTHOLD) |
darienf | 20:6d2af70c92ab | 1357 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CConfigGet |
darienf | 20:6d2af70c92ab | 1358 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1359 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1360 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1361 | reportID(); |
darienf | 20:6d2af70c92ab | 1362 | IOBuf[1] = 4; // case (4): //I2C configuration -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1363 | IOBuf[2] = 1; // case (1): // read |
darienf | 20:6d2af70c92ab | 1364 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1365 | // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; |
darienf | 20:6d2af70c92ab | 1366 | // IO_BUFFER.Ptr[0+gOffset] = 0; // error status |
darienf | 20:6d2af70c92ab | 1367 | // IO_BUFFER.Ptr[1+gOffset] = gI2Cflags; |
darienf | 20:6d2af70c92ab | 1368 | // IO_BUFFER.Ptr[2+gOffset] = (SMB0CF & 0x10) >> 4; // EXTHOLD |
darienf | 20:6d2af70c92ab | 1369 | gI2Cflags = IOBuf[2]; |
darienf | 20:6d2af70c92ab | 1370 | EXTHOLD = IOBuf[3]; |
darienf | 20:6d2af70c92ab | 1371 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1372 | }*/ |
darienf | 20:6d2af70c92ab | 1373 | |
darienf | 20:6d2af70c92ab | 1374 | /// <summary> |
darienf | 20:6d2af70c92ab | 1375 | /// <para>Firmware command code 5 OUT = I2C clock rate (number of counts to overflow) </para> |
darienf | 20:6d2af70c92ab | 1376 | /// <para>SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</para> |
darienf | 20:6d2af70c92ab | 1377 | /// </summary> |
darienf | 20:6d2af70c92ab | 1378 | /// <param name="ReloadTH1">SMBus timer's count value: ReloadTH1 = (byte)(0.5 + (TimerClockMHz * 1000 / SCL_kHz))</param> |
darienf | 20:6d2af70c92ab | 1379 | /* public void I2CClockSet(byte ReloadTH1) |
darienf | 20:6d2af70c92ab | 1380 | { |
darienf | 20:6d2af70c92ab | 1381 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CClockSet(byte ReloadTH1) |
darienf | 20:6d2af70c92ab | 1382 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CClockSet |
darienf | 20:6d2af70c92ab | 1383 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1384 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1385 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1386 | reportID(); |
darienf | 20:6d2af70c92ab | 1387 | IOBuf[1] = 5; // case (5): //I2C clock rate (number of counts to overflow) -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1388 | IOBuf[2] = 0; // case (0): // write |
darienf | 20:6d2af70c92ab | 1389 | IOBuf[3] = ReloadTH1; |
darienf | 20:6d2af70c92ab | 1390 | // gSMBusClkFreq = gTimer1ClkFreq / 3.0 / IO_BUFFER.Ptr[2+gOffset]; //GUI sends the number of counts to overflow; HID must calculate the desired SMBus clock frequency |
darienf | 20:6d2af70c92ab | 1391 | // TR1 = 0; |
darienf | 20:6d2af70c92ab | 1392 | // Timer1_Init(); |
darienf | 20:6d2af70c92ab | 1393 | writeHID(); |
darienf | 20:6d2af70c92ab | 1394 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1395 | }*/ |
darienf | 20:6d2af70c92ab | 1396 | |
darienf | 20:6d2af70c92ab | 1397 | /// <summary> |
darienf | 20:6d2af70c92ab | 1398 | /// <para>Firmware command code 5 IN = I2C clock rate (number of counts to overflow) </para> |
darienf | 20:6d2af70c92ab | 1399 | /// <para>SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</para> |
darienf | 20:6d2af70c92ab | 1400 | /// </summary> |
darienf | 20:6d2af70c92ab | 1401 | /// <param name="TimerClockMHz">SMBus timer's clock frequency (in MHz); expect constant 8</param> |
darienf | 20:6d2af70c92ab | 1402 | /// <param name="ReloadTH1">SMBus timer's count value: SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</param> |
darienf | 20:6d2af70c92ab | 1403 | /*public void I2CClockGet(out byte TimerClockMHz, out byte ReloadTH1) |
darienf | 20:6d2af70c92ab | 1404 | { |
darienf | 20:6d2af70c92ab | 1405 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CClockGet(out byte TimerClockMHz, out byte ReloadTH1) |
darienf | 20:6d2af70c92ab | 1406 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CClockGet |
darienf | 20:6d2af70c92ab | 1407 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1408 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1409 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1410 | reportID(); |
darienf | 20:6d2af70c92ab | 1411 | IOBuf[1] = 5; // case (5): //I2C clock rate (number of counts to overflow) -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1412 | IOBuf[2] = 1; // case (1): // read |
darienf | 20:6d2af70c92ab | 1413 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1414 | // case (1): // read -- myHID.I2CClockGet(out TimerClockMHz, out ReloadTH1) |
darienf | 20:6d2af70c92ab | 1415 | // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; |
darienf | 20:6d2af70c92ab | 1416 | // IO_BUFFER.Ptr[0+gOffset] = 0; // error status |
darienf | 20:6d2af70c92ab | 1417 | // IO_BUFFER.Ptr[1+gOffset] = gTimer1ClkFreq / 1000000 / 3; //return the SMBus timer's clock frequency (in MHz) |
darienf | 20:6d2af70c92ab | 1418 | // IO_BUFFER.Ptr[2+gOffset] = 256-TH1; //and return the SMBus timer's count value in order to calculate the SMBus clock frequency; TH1 is the reload value that gets loaded into TL0 upon overflow; the reload value is 256-TH1 since (0)-TH1 gives the proper number of counts to overflow |
darienf | 20:6d2af70c92ab | 1419 | // SendPacket(); // no need to check for internal call since only the GUI will request a read through this function |
darienf | 20:6d2af70c92ab | 1420 | // break; |
darienf | 20:6d2af70c92ab | 1421 | TimerClockMHz = IOBuf[2]; |
darienf | 20:6d2af70c92ab | 1422 | ReloadTH1 = IOBuf[3]; |
darienf | 20:6d2af70c92ab | 1423 | // todo: OS24EVK-24 how determine SCL from TimerClockMHZ? Observed I2CClockGet() TimerClockMHz = 8 when SCL = 400kHz. |
darienf | 20:6d2af70c92ab | 1424 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1425 | }*/ |
darienf | 20:6d2af70c92ab | 1426 | |
darienf | 20:6d2af70c92ab | 1427 | /// <summary> |
darienf | 20:6d2af70c92ab | 1428 | /// <para>Firmware command code 6 OUT = I2C transaction </para> |
darienf | 20:6d2af70c92ab | 1429 | /// |
darienf | 20:6d2af70c92ab | 1430 | /// </summary> |
darienf | 20:6d2af70c92ab | 1431 | /// <param name="deviceAddress">I2C device address, 8-bit left-justified (LSB=R/w bit)</param> |
darienf | 20:6d2af70c92ab | 1432 | /// <param name="numDataBytes">I2C burst write register data count, in bytes</param> |
darienf | 20:6d2af70c92ab | 1433 | /// <param name="numRegBytes">I2C device register address length, normally 1 byte. Can be 0 for SMBusQuick protocol.</param> |
darienf | 20:6d2af70c92ab | 1434 | /// <param name="data">byte array containing the register data to transmit</param> |
darienf | 20:6d2af70c92ab | 1435 | /// <param name="reg">byte array containing the device register address</param> |
darienf | 20:6d2af70c92ab | 1436 | /// <param name="ignoreNACK"></param> |
darienf | 20:6d2af70c92ab | 1437 | /*public void I2CWrite(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] data, byte[] reg, bool ignoreNACK = false) |
darienf | 20:6d2af70c92ab | 1438 | { |
darienf | 20:6d2af70c92ab | 1439 | // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers |
darienf | 20:6d2af70c92ab | 1440 | // alias of existing function |
darienf | 20:6d2af70c92ab | 1441 | // IOBuf[1] = 6; // case (6): // I2C transaction -- HID.cs void writeI2C() readI2C() -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1442 | writeI2C(deviceAddress, numDataBytes, numRegBytes, data, reg, ignoreNACK); |
darienf | 20:6d2af70c92ab | 1443 | }*/ |
darienf | 20:6d2af70c92ab | 1444 | |
darienf | 20:6d2af70c92ab | 1445 | /// <summary> |
darienf | 20:6d2af70c92ab | 1446 | /// <para>Firmware command code 6 IN = I2C transaction </para> |
darienf | 20:6d2af70c92ab | 1447 | /// |
darienf | 20:6d2af70c92ab | 1448 | /// </summary> |
darienf | 20:6d2af70c92ab | 1449 | /// <param name="deviceAddress">I2C device address, 8-bit left-justified (LSB=R/w bit)</param> |
darienf | 20:6d2af70c92ab | 1450 | /// <param name="numDataBytes">I2C burst read register data count, in bytes</param> |
darienf | 20:6d2af70c92ab | 1451 | /// <param name="numRegBytes">I2C device register address length, normally 1 byte. Can be 0 for SMBusQuick protocol.</param> |
darienf | 20:6d2af70c92ab | 1452 | /// <param name="readData">byte array which receives the register data</param> |
darienf | 20:6d2af70c92ab | 1453 | /// <param name="reg">byte array containing the device register address</param> |
darienf | 20:6d2af70c92ab | 1454 | /// <param name="ignoreNACK"></param> |
darienf | 20:6d2af70c92ab | 1455 | /// <returns>status value; may be HID.I2C_NACK_ERROR if ignoreNACK parameter is true</returns> |
darienf | 20:6d2af70c92ab | 1456 | /* public int I2CRead(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] readData, byte[] reg, bool ignoreNACK = false) |
darienf | 20:6d2af70c92ab | 1457 | { |
darienf | 20:6d2af70c92ab | 1458 | // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers |
darienf | 20:6d2af70c92ab | 1459 | // alias of existing function |
darienf | 20:6d2af70c92ab | 1460 | // IOBuf[1] = 6; // case (6): // I2C transaction -- HID.cs void writeI2C() readI2C() -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1461 | return readI2C(deviceAddress, numDataBytes, numRegBytes, readData, reg, ignoreNACK); |
darienf | 20:6d2af70c92ab | 1462 | }*/ |
darienf | 20:6d2af70c92ab | 1463 | |
darienf | 20:6d2af70c92ab | 1464 | /*/// <summary> |
darienf | 20:6d2af70c92ab | 1465 | /// Search for a device attached to I2C bus, |
darienf | 20:6d2af70c92ab | 1466 | /// given a list of poossible device addresses, |
darienf | 20:6d2af70c92ab | 1467 | /// and a constant device ID register to test. |
darienf | 20:6d2af70c92ab | 1468 | /// </summary> |
darienf | 20:6d2af70c92ab | 1469 | /// <param name="I2C_DeviceAddressList_8bitLeftJustified">List of possible I2C device addresses to test. I2C device addresses are 8-bit left-justified (LSB=R/w bit)</param> |
darienf | 20:6d2af70c92ab | 1470 | /// <param name="DeviceId_RegAddress">device register address of a constant "Device ID" register</param> |
darienf | 20:6d2af70c92ab | 1471 | /// <param name="DeviceId_RegValue_Expect">register value of the constant "Device ID" register</param> |
darienf | 20:6d2af70c92ab | 1472 | /// <returns>I2C device addresses, or 0 if not found</returns> |
darienf | 20:6d2af70c92ab | 1473 | public byte SearchI2CdeviceAddressList(byte[] I2C_DeviceAddressList_8bitLeftJustified, byte DeviceId_RegAddress, byte DeviceId_RegValue_Expect) |
darienf | 20:6d2af70c92ab | 1474 | { |
darienf | 20:6d2af70c92ab | 1475 | // https://jira.maxim-ic.com/browse/OS24EVK-57 accelerometer support: SearchI2CdeviceAddressList optional I2C device |
darienf | 20:6d2af70c92ab | 1476 | foreach (byte test_I2C_Address in I2C_DeviceAddressList_8bitLeftJustified) |
darienf | 20:6d2af70c92ab | 1477 | { |
darienf | 20:6d2af70c92ab | 1478 | //try |
darienf | 20:6d2af70c92ab | 1479 | //{ |
darienf | 20:6d2af70c92ab | 1480 | byte[] data = new byte[2]; |
darienf | 20:6d2af70c92ab | 1481 | byte[] reg = new byte[1]; |
darienf | 20:6d2af70c92ab | 1482 | reg[0] = (byte)DeviceId_RegAddress; |
darienf | 20:6d2af70c92ab | 1483 | // readI2C should already take care of mutex lock / unlock |
darienf | 20:6d2af70c92ab | 1484 | // https://jira.maxim-ic.com/browse/OS24EVK-59 avoid NACK exception in SearchI2CdeviceAddressList |
darienf | 20:6d2af70c92ab | 1485 | bool ignoreNACK = true; |
darienf | 20:6d2af70c92ab | 1486 | int status = readI2C(test_I2C_Address, 2, 1, data, reg, ignoreNACK); |
darienf | 20:6d2af70c92ab | 1487 | if (status == HID.I2C_NACK_ERROR) |
darienf | 20:6d2af70c92ab | 1488 | { |
darienf | 20:6d2af70c92ab | 1489 | continue; |
darienf | 20:6d2af70c92ab | 1490 | } |
darienf | 20:6d2af70c92ab | 1491 | else |
darienf | 20:6d2af70c92ab | 1492 | { |
darienf | 20:6d2af70c92ab | 1493 | byte DeviceId_RegValue_Actual = data[0]; |
darienf | 20:6d2af70c92ab | 1494 | if (DeviceId_RegValue_Actual == DeviceId_RegValue_Expect) |
darienf | 20:6d2af70c92ab | 1495 | { |
darienf | 20:6d2af70c92ab | 1496 | return test_I2C_Address; |
darienf | 20:6d2af70c92ab | 1497 | } |
darienf | 20:6d2af70c92ab | 1498 | } |
darienf | 20:6d2af70c92ab | 1499 | //} |
darienf | 20:6d2af70c92ab | 1500 | //catch (Exception) |
darienf | 20:6d2af70c92ab | 1501 | //{ |
darienf | 20:6d2af70c92ab | 1502 | // // myHID.readI2C can throw Exception("invalid I2C address"); |
darienf | 20:6d2af70c92ab | 1503 | //} |
darienf | 20:6d2af70c92ab | 1504 | } |
darienf | 20:6d2af70c92ab | 1505 | return 0; |
darienf | 20:6d2af70c92ab | 1506 | }*/ |
darienf | 20:6d2af70c92ab | 1507 | #endregion |
darienf | 20:6d2af70c92ab | 1508 | |
darienf | 20:6d2af70c92ab | 1509 | public bool I2C_Initialize(byte index, byte clockSpeed) |
darienf | 20:6d2af70c92ab | 1510 | { |
darienf | 20:6d2af70c92ab | 1511 | bool success = false; |
darienf | 20:6d2af70c92ab | 1512 | |
darienf | 20:6d2af70c92ab | 1513 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1514 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1515 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1516 | |
darienf | 20:6d2af70c92ab | 1517 | reportID(); |
darienf | 20:6d2af70c92ab | 1518 | IOBuf[1] = I2C_INIT; // command code -- see usb_app int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1519 | IOBuf[2] = index; |
darienf | 20:6d2af70c92ab | 1520 | IOBuf[3] = clockSpeed; // 0 = 100KHz, 1 = 400KHz, 2 = 1MHz |
darienf | 20:6d2af70c92ab | 1521 | |
darienf | 20:6d2af70c92ab | 1522 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1523 | |
darienf | 20:6d2af70c92ab | 1524 | if (IOBuf[1] == COMMAND_SUCCESS) |
darienf | 20:6d2af70c92ab | 1525 | success = true; |
darienf | 20:6d2af70c92ab | 1526 | |
darienf | 20:6d2af70c92ab | 1527 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1528 | |
darienf | 20:6d2af70c92ab | 1529 | return success; |
darienf | 20:6d2af70c92ab | 1530 | } |
darienf | 20:6d2af70c92ab | 1531 | |
darienf | 20:6d2af70c92ab | 1532 | public byte SearchI2CdeviceAddressList(byte index, byte[] I2C_DeviceAddressList_8bitLeftJustified, byte DeviceId_RegAddress, byte DeviceId_RegValue_Expect) |
darienf | 20:6d2af70c92ab | 1533 | { |
darienf | 20:6d2af70c92ab | 1534 | foreach (byte test_I2C_Address in I2C_DeviceAddressList_8bitLeftJustified) |
darienf | 20:6d2af70c92ab | 1535 | { |
darienf | 20:6d2af70c92ab | 1536 | byte[] data = new byte[2]; |
darienf | 20:6d2af70c92ab | 1537 | byte[] reg = new byte[1]; |
darienf | 20:6d2af70c92ab | 1538 | reg[0] = (byte)DeviceId_RegAddress; |
darienf | 20:6d2af70c92ab | 1539 | |
darienf | 20:6d2af70c92ab | 1540 | bool success = I2C_Read(index, test_I2C_Address, 1, reg, 2, ref data); |
darienf | 20:6d2af70c92ab | 1541 | |
darienf | 20:6d2af70c92ab | 1542 | if (success) |
darienf | 20:6d2af70c92ab | 1543 | { |
darienf | 20:6d2af70c92ab | 1544 | byte DeviceId_RegValue_Actual = data[0]; |
darienf | 20:6d2af70c92ab | 1545 | if (DeviceId_RegValue_Actual == DeviceId_RegValue_Expect) |
darienf | 20:6d2af70c92ab | 1546 | { |
darienf | 20:6d2af70c92ab | 1547 | return test_I2C_Address; |
darienf | 20:6d2af70c92ab | 1548 | } |
darienf | 20:6d2af70c92ab | 1549 | } |
darienf | 20:6d2af70c92ab | 1550 | } |
darienf | 20:6d2af70c92ab | 1551 | return 0; |
darienf | 20:6d2af70c92ab | 1552 | } |
darienf | 20:6d2af70c92ab | 1553 | |
darienf | 20:6d2af70c92ab | 1554 | public bool I2C_Read(byte index, byte slaveAddress, byte num_cmd_bytes, byte[] cmd_data, byte num_data_bytes, ref byte[] data) |
darienf | 20:6d2af70c92ab | 1555 | { |
darienf | 20:6d2af70c92ab | 1556 | bool success = false; |
darienf | 20:6d2af70c92ab | 1557 | |
darienf | 20:6d2af70c92ab | 1558 | if ((5 + num_cmd_bytes) > 63) |
darienf | 20:6d2af70c92ab | 1559 | return false; |
darienf | 20:6d2af70c92ab | 1560 | if ((1 + num_data_bytes) > 63) |
darienf | 20:6d2af70c92ab | 1561 | return false; |
darienf | 20:6d2af70c92ab | 1562 | |
darienf | 20:6d2af70c92ab | 1563 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1564 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1565 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1566 | |
darienf | 20:6d2af70c92ab | 1567 | reportID(); |
darienf | 20:6d2af70c92ab | 1568 | IOBuf[1] = I2C_TRANSACTION; // command code -- see usb_app int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1569 | IOBuf[2] = index; |
darienf | 20:6d2af70c92ab | 1570 | IOBuf[3] = (byte)(slaveAddress | 0x01); //LSB = 1 for read |
darienf | 20:6d2af70c92ab | 1571 | IOBuf[4] = num_cmd_bytes; |
darienf | 20:6d2af70c92ab | 1572 | |
darienf | 20:6d2af70c92ab | 1573 | for (int i = 0; i < num_cmd_bytes; i++) |
darienf | 20:6d2af70c92ab | 1574 | IOBuf[5 + i] = cmd_data[i]; |
darienf | 20:6d2af70c92ab | 1575 | |
darienf | 20:6d2af70c92ab | 1576 | IOBuf[5 + num_cmd_bytes] = num_data_bytes; |
darienf | 20:6d2af70c92ab | 1577 | |
darienf | 20:6d2af70c92ab | 1578 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1579 | |
darienf | 20:6d2af70c92ab | 1580 | if (IOBuf[1] == COMMAND_SUCCESS) |
darienf | 20:6d2af70c92ab | 1581 | success = true; |
darienf | 20:6d2af70c92ab | 1582 | |
darienf | 20:6d2af70c92ab | 1583 | for (int i = 0; i < num_data_bytes; i++) |
darienf | 20:6d2af70c92ab | 1584 | data[i] = IOBuf[2 + i]; |
darienf | 20:6d2af70c92ab | 1585 | |
darienf | 20:6d2af70c92ab | 1586 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1587 | |
darienf | 20:6d2af70c92ab | 1588 | return success; |
darienf | 20:6d2af70c92ab | 1589 | } |
darienf | 20:6d2af70c92ab | 1590 | public bool I2C_Write(byte index, byte slaveAddress, byte num_cmd_bytes, byte[] cmd_data, byte num_data_bytes, byte[] data) |
darienf | 20:6d2af70c92ab | 1591 | { |
darienf | 20:6d2af70c92ab | 1592 | bool success = false; |
darienf | 20:6d2af70c92ab | 1593 | |
darienf | 20:6d2af70c92ab | 1594 | if ((5 + num_cmd_bytes) > 63) |
darienf | 20:6d2af70c92ab | 1595 | return false; |
darienf | 20:6d2af70c92ab | 1596 | if ((1 + num_data_bytes) > 63) |
darienf | 20:6d2af70c92ab | 1597 | return false; |
darienf | 20:6d2af70c92ab | 1598 | |
darienf | 20:6d2af70c92ab | 1599 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1600 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1601 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1602 | |
darienf | 20:6d2af70c92ab | 1603 | reportID(); |
darienf | 20:6d2af70c92ab | 1604 | IOBuf[1] = I2C_TRANSACTION; // command code -- see usb_app int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1605 | IOBuf[2] = index; |
darienf | 20:6d2af70c92ab | 1606 | IOBuf[3] = (byte)(slaveAddress | 0x01); //LSB = 1 for read |
darienf | 20:6d2af70c92ab | 1607 | IOBuf[4] = num_cmd_bytes; |
darienf | 20:6d2af70c92ab | 1608 | |
darienf | 20:6d2af70c92ab | 1609 | for (int i = 0; i < num_cmd_bytes; i++) |
darienf | 20:6d2af70c92ab | 1610 | IOBuf[5 + i] = cmd_data[i]; |
darienf | 20:6d2af70c92ab | 1611 | |
darienf | 20:6d2af70c92ab | 1612 | IOBuf[5 + num_cmd_bytes] = num_data_bytes; |
darienf | 20:6d2af70c92ab | 1613 | |
darienf | 20:6d2af70c92ab | 1614 | for (int i = 0; i < num_data_bytes; i++) |
darienf | 20:6d2af70c92ab | 1615 | IOBuf[6 + num_cmd_bytes + i] = data[i]; |
darienf | 20:6d2af70c92ab | 1616 | |
darienf | 20:6d2af70c92ab | 1617 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1618 | |
darienf | 20:6d2af70c92ab | 1619 | if (IOBuf[1] == COMMAND_SUCCESS) |
darienf | 20:6d2af70c92ab | 1620 | success = true; |
darienf | 20:6d2af70c92ab | 1621 | |
darienf | 20:6d2af70c92ab | 1622 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1623 | |
darienf | 20:6d2af70c92ab | 1624 | return success; |
darienf | 20:6d2af70c92ab | 1625 | } |
darienf | 20:6d2af70c92ab | 1626 | |
darienf | 20:6d2af70c92ab | 1627 | public String RPC_Call(String str) { |
darienf | 20:6d2af70c92ab | 1628 | |
darienf | 20:6d2af70c92ab | 1629 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1630 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1631 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1632 | |
darienf | 20:6d2af70c92ab | 1633 | reportID(); |
darienf | 20:6d2af70c92ab | 1634 | int i = 1; |
darienf | 20:6d2af70c92ab | 1635 | foreach (char ch in str) |
darienf | 20:6d2af70c92ab | 1636 | { |
darienf | 20:6d2af70c92ab | 1637 | IOBuf[i] = (byte)ch; |
darienf | 20:6d2af70c92ab | 1638 | i++; |
darienf | 20:6d2af70c92ab | 1639 | } |
darienf | 20:6d2af70c92ab | 1640 | |
darienf | 20:6d2af70c92ab | 1641 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1642 | |
darienf | 20:6d2af70c92ab | 1643 | StringBuilder sb = new StringBuilder(); |
darienf | 20:6d2af70c92ab | 1644 | for (i = 1; i < 64; i++) |
darienf | 20:6d2af70c92ab | 1645 | { |
darienf | 20:6d2af70c92ab | 1646 | if (IOBuf[i] == 13) break; |
darienf | 20:6d2af70c92ab | 1647 | sb.Append((char)IOBuf[i]); |
darienf | 20:6d2af70c92ab | 1648 | } |
darienf | 20:6d2af70c92ab | 1649 | |
darienf | 20:6d2af70c92ab | 1650 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1651 | return sb.ToString(); |
darienf | 20:6d2af70c92ab | 1652 | } |
darienf | 20:6d2af70c92ab | 1653 | |
darienf | 20:6d2af70c92ab | 1654 | #endregion |
darienf | 20:6d2af70c92ab | 1655 | |
darienf | 20:6d2af70c92ab | 1656 | #region General Commmands |
darienf | 20:6d2af70c92ab | 1657 | /// <summary> |
darienf | 20:6d2af70c92ab | 1658 | /// <para>Firmware command code 0 IN = Firmware version</para> |
darienf | 20:6d2af70c92ab | 1659 | /// |
darienf | 20:6d2af70c92ab | 1660 | /// </summary> |
darienf | 20:6d2af70c92ab | 1661 | /// <param name="VerMajor"></param> |
darienf | 20:6d2af70c92ab | 1662 | /// <param name="VerMinor"></param> |
darienf | 20:6d2af70c92ab | 1663 | /// <param name="verYearHundreds"></param> |
darienf | 20:6d2af70c92ab | 1664 | /// <param name="verYear"></param> |
darienf | 20:6d2af70c92ab | 1665 | /// <param name="verMonth"></param> |
darienf | 20:6d2af70c92ab | 1666 | /// <param name="verDay"></param> |
darienf | 20:6d2af70c92ab | 1667 | public bool FirmwareVersion(out byte VerMajor, out byte VerMinor, out byte verYearHundreds, out byte verYear, out byte verMonth, out byte verDay) |
darienf | 20:6d2af70c92ab | 1668 | { |
darienf | 20:6d2af70c92ab | 1669 | bool success = false; |
darienf | 20:6d2af70c92ab | 1670 | |
darienf | 20:6d2af70c92ab | 1671 | if (FirmwareINT0Enabled != 0) |
darienf | 20:6d2af70c92ab | 1672 | { |
darienf | 20:6d2af70c92ab | 1673 | // firmware is busy streaming out HID reports, |
darienf | 20:6d2af70c92ab | 1674 | // so return a previously retrieved firmware version. |
darienf | 20:6d2af70c92ab | 1675 | VerMajor = _VerMajor; |
darienf | 20:6d2af70c92ab | 1676 | VerMinor = _VerMinor; |
darienf | 20:6d2af70c92ab | 1677 | verYearHundreds = _verYearHundreds; |
darienf | 20:6d2af70c92ab | 1678 | verYear = _verYear; |
darienf | 20:6d2af70c92ab | 1679 | verMonth = _verMonth; |
darienf | 20:6d2af70c92ab | 1680 | verDay = _verDay; |
darienf | 20:6d2af70c92ab | 1681 | return true; |
darienf | 20:6d2af70c92ab | 1682 | } |
darienf | 20:6d2af70c92ab | 1683 | // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers |
darienf | 20:6d2af70c92ab | 1684 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in FirmwareVersion |
darienf | 20:6d2af70c92ab | 1685 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1686 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1687 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1688 | reportID(); |
darienf | 20:6d2af70c92ab | 1689 | IOBuf[1] = 0; // Firmware version -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1690 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1691 | VerMajor = IOBuf[2]; |
darienf | 20:6d2af70c92ab | 1692 | VerMinor = IOBuf[3]; |
darienf | 20:6d2af70c92ab | 1693 | verYearHundreds = IOBuf[4]; |
darienf | 20:6d2af70c92ab | 1694 | verYear = IOBuf[5]; |
darienf | 20:6d2af70c92ab | 1695 | verMonth = IOBuf[6]; |
darienf | 20:6d2af70c92ab | 1696 | verDay = IOBuf[7]; |
darienf | 20:6d2af70c92ab | 1697 | |
darienf | 20:6d2af70c92ab | 1698 | if (IOBuf[1] == COMMAND_SUCCESS) |
darienf | 20:6d2af70c92ab | 1699 | { |
darienf | 20:6d2af70c92ab | 1700 | success = true; |
darienf | 20:6d2af70c92ab | 1701 | |
darienf | 20:6d2af70c92ab | 1702 | // save the recently read values |
darienf | 20:6d2af70c92ab | 1703 | _VerMajor = VerMajor; |
darienf | 20:6d2af70c92ab | 1704 | _VerMinor = VerMinor; |
darienf | 20:6d2af70c92ab | 1705 | _verYearHundreds = verYearHundreds; |
darienf | 20:6d2af70c92ab | 1706 | _verYear = verYear; |
darienf | 20:6d2af70c92ab | 1707 | _verMonth = verMonth; |
darienf | 20:6d2af70c92ab | 1708 | _verDay = verDay; |
darienf | 20:6d2af70c92ab | 1709 | } |
darienf | 20:6d2af70c92ab | 1710 | |
darienf | 20:6d2af70c92ab | 1711 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1712 | |
darienf | 20:6d2af70c92ab | 1713 | return success; |
darienf | 20:6d2af70c92ab | 1714 | } |
darienf | 20:6d2af70c92ab | 1715 | private byte _VerMajor = 0; |
darienf | 20:6d2af70c92ab | 1716 | private byte _VerMinor = 0; |
darienf | 20:6d2af70c92ab | 1717 | private byte _verYearHundreds = 0; |
darienf | 20:6d2af70c92ab | 1718 | private byte _verYear = 0; |
darienf | 20:6d2af70c92ab | 1719 | private byte _verMonth = 0; |
darienf | 20:6d2af70c92ab | 1720 | private byte _verDay = 0; |
darienf | 20:6d2af70c92ab | 1721 | /// <summary> |
darienf | 20:6d2af70c92ab | 1722 | /// <para>Firmware command code 1 </para> |
darienf | 20:6d2af70c92ab | 1723 | /// |
darienf | 20:6d2af70c92ab | 1724 | /// </summary> |
darienf | 20:6d2af70c92ab | 1725 | /// <param name="ON">ON = true: LED turns on</param> |
darienf | 20:6d2af70c92ab | 1726 | public bool LEDSet(bool ON) |
darienf | 20:6d2af70c92ab | 1727 | { |
darienf | 20:6d2af70c92ab | 1728 | bool success = false; |
darienf | 20:6d2af70c92ab | 1729 | |
darienf | 20:6d2af70c92ab | 1730 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1731 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1732 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1733 | reportID(); |
darienf | 20:6d2af70c92ab | 1734 | IOBuf[1] = 1; // command code -- see usb_app int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1735 | |
darienf | 20:6d2af70c92ab | 1736 | if(ON) |
darienf | 20:6d2af70c92ab | 1737 | IOBuf[2] = 1; |
darienf | 20:6d2af70c92ab | 1738 | else |
darienf | 20:6d2af70c92ab | 1739 | IOBuf[2] = 0; |
darienf | 20:6d2af70c92ab | 1740 | |
darienf | 20:6d2af70c92ab | 1741 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1742 | |
darienf | 20:6d2af70c92ab | 1743 | if (IOBuf[1] == COMMAND_SUCCESS) |
darienf | 20:6d2af70c92ab | 1744 | success = true; |
darienf | 20:6d2af70c92ab | 1745 | |
darienf | 20:6d2af70c92ab | 1746 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1747 | |
darienf | 20:6d2af70c92ab | 1748 | return success; |
darienf | 20:6d2af70c92ab | 1749 | } |
darienf | 20:6d2af70c92ab | 1750 | #endregion |
darienf | 20:6d2af70c92ab | 1751 | |
darienf | 20:6d2af70c92ab | 1752 | #region GPIO commands |
darienf | 20:6d2af70c92ab | 1753 | /// <summary> |
darienf | 20:6d2af70c92ab | 1754 | /// <para>Firmware command code 1 IN = GPIOP0Get read I/O pins P0.6, P0.7</para> |
darienf | 20:6d2af70c92ab | 1755 | /// |
darienf | 20:6d2af70c92ab | 1756 | /// </summary> |
darienf | 20:6d2af70c92ab | 1757 | /// <param name="xxxxxxP06P07"></param> |
darienf | 20:6d2af70c92ab | 1758 | public void GPIOP0Get(out byte xxxxxxP06P07) |
darienf | 20:6d2af70c92ab | 1759 | { |
darienf | 20:6d2af70c92ab | 1760 | // todo: verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers GPIOP0Get(out byte xxxxxxP06P07) |
darienf | 20:6d2af70c92ab | 1761 | // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: Rename LEDGet(out byte xxxxxxP06P07) to GPIOP0Get(out byte xxxxxxP06P07) |
darienf | 20:6d2af70c92ab | 1762 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP0Get |
darienf | 20:6d2af70c92ab | 1763 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1764 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1765 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1766 | reportID(); |
darienf | 20:6d2af70c92ab | 1767 | IOBuf[1] = 1; // case (1): //LED (C51F321 P2.2=red, P2.1=green) -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1768 | IOBuf[2] = 1; // case (1): // read |
darienf | 20:6d2af70c92ab | 1769 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1770 | // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; |
darienf | 20:6d2af70c92ab | 1771 | // IO_BUFFER.Ptr[0 + gOffset] = 0; // error status |
darienf | 20:6d2af70c92ab | 1772 | // IO_BUFFER.Ptr[1 + gOffset] = ((P0 & 0x80) >> 7) + ((P0 & 0x40) >> 5); |
darienf | 20:6d2af70c92ab | 1773 | xxxxxxP06P07 = IOBuf[2]; |
darienf | 20:6d2af70c92ab | 1774 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1775 | } |
darienf | 20:6d2af70c92ab | 1776 | |
darienf | 20:6d2af70c92ab | 1777 | /// <summary> |
darienf | 20:6d2af70c92ab | 1778 | /// <para>Firmware command code 2 OUT = GPIO configuration (C51F321 P1 and P2) </para> |
darienf | 20:6d2af70c92ab | 1779 | /// |
darienf | 20:6d2af70c92ab | 1780 | /// </summary> |
darienf | 20:6d2af70c92ab | 1781 | /// <param name="P1MDOUT"></param> |
darienf | 20:6d2af70c92ab | 1782 | /// <param name="P2MDOUT"></param> |
darienf | 20:6d2af70c92ab | 1783 | /// <param name="weakPullupDisable"></param> |
darienf | 20:6d2af70c92ab | 1784 | public void GPIOP1P2ConfigSet(byte P1MDOUT, byte P2MDOUT, byte weakPullupDisable) |
darienf | 20:6d2af70c92ab | 1785 | { |
darienf | 20:6d2af70c92ab | 1786 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers GPIOP1P2ConfigSet(byte P1MDOUT, byte P2MDOUT, byte weakPullupDisable) |
darienf | 20:6d2af70c92ab | 1787 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP1P2ConfigSet |
darienf | 20:6d2af70c92ab | 1788 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1789 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1790 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1791 | reportID(); |
darienf | 20:6d2af70c92ab | 1792 | IOBuf[1] = 2; // case (2): //GPIO configuration (C51F321 P1 and P2) -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1793 | IOBuf[2] = 0; // case (0): // write |
darienf | 20:6d2af70c92ab | 1794 | IOBuf[3] = P1MDOUT; // P1MDOUT = IO_BUFFER.Ptr[2+gOffset]; // P1 push-pull (1) or open-collector (0) |
darienf | 20:6d2af70c92ab | 1795 | IOBuf[4] = P2MDOUT; // P2MDOUT = IO_BUFFER.Ptr[3 + gOffset]; // P2 push-pull (1) or open-collector (0) |
darienf | 20:6d2af70c92ab | 1796 | IOBuf[5] = weakPullupDisable; // (IO_BUFFER.Ptr[4 + gOffset] & 1) ? (XBR1 |= 0x80) : (XBR1 &= 0x7F); // weak pull up disable (open collector only); 1 disabled, 0 enabled |
darienf | 20:6d2af70c92ab | 1797 | writeHID(); |
darienf | 20:6d2af70c92ab | 1798 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1799 | } |
darienf | 20:6d2af70c92ab | 1800 | |
darienf | 20:6d2af70c92ab | 1801 | /// <summary> |
darienf | 20:6d2af70c92ab | 1802 | /// <para>Firmware command code 2 IN = GPIO configuration (C51F321 P1 and P2) </para> |
darienf | 20:6d2af70c92ab | 1803 | /// |
darienf | 20:6d2af70c92ab | 1804 | /// </summary> |
darienf | 20:6d2af70c92ab | 1805 | /// <param name="P1MDOUT"></param> |
darienf | 20:6d2af70c92ab | 1806 | /// <param name="P2MDOUT"></param> |
darienf | 20:6d2af70c92ab | 1807 | /// <param name="weakPullupDisable"></param> |
darienf | 20:6d2af70c92ab | 1808 | public void GPIOP1P2ConfigGet(out byte P1MDOUT, out byte P2MDOUT, out byte weakPullupDisable) |
darienf | 20:6d2af70c92ab | 1809 | { |
darienf | 20:6d2af70c92ab | 1810 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers GPIOP1P2ConfigGet(out byte P1MDOUT, out byte P2MDOUT, out byte weakPullupDisable) |
darienf | 20:6d2af70c92ab | 1811 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP1P2ConfigGet |
darienf | 20:6d2af70c92ab | 1812 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1813 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1814 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1815 | reportID(); |
darienf | 20:6d2af70c92ab | 1816 | IOBuf[1] = 2; // case (2): //GPIO configuration (C51F321 P1 and P2) -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1817 | IOBuf[2] = 1; // case (1): // read |
darienf | 20:6d2af70c92ab | 1818 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1819 | // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; |
darienf | 20:6d2af70c92ab | 1820 | // IO_BUFFER.Ptr[0 + gOffset] = 0; // error status |
darienf | 20:6d2af70c92ab | 1821 | // IO_BUFFER.Ptr[1 + gOffset] = P1MDOUT; // P1 push-pull (1) or open-collector (0) |
darienf | 20:6d2af70c92ab | 1822 | // IO_BUFFER.Ptr[2 + gOffset] = P2MDOUT; // P2 push-pull (1) or open-collector (0) |
darienf | 20:6d2af70c92ab | 1823 | // IO_BUFFER.Ptr[3 + gOffset] = (XBR1 & 0x80) >> 7; // weakPullupDisable |
darienf | 20:6d2af70c92ab | 1824 | P1MDOUT = IOBuf[2]; |
darienf | 20:6d2af70c92ab | 1825 | P2MDOUT = IOBuf[3]; |
darienf | 20:6d2af70c92ab | 1826 | weakPullupDisable = IOBuf[4]; |
darienf | 20:6d2af70c92ab | 1827 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1828 | } |
darienf | 20:6d2af70c92ab | 1829 | |
darienf | 20:6d2af70c92ab | 1830 | /// <summary> |
darienf | 20:6d2af70c92ab | 1831 | /// <para>Firmware command code 3 OUT = GPIO value (C51F321 P1 and P2) </para> |
darienf | 20:6d2af70c92ab | 1832 | /// |
darienf | 20:6d2af70c92ab | 1833 | /// </summary> |
darienf | 20:6d2af70c92ab | 1834 | /// <param name="P1"></param> |
darienf | 20:6d2af70c92ab | 1835 | /// <param name="P2"></param> |
darienf | 20:6d2af70c92ab | 1836 | public void GPIOP1P2Out(byte P1, byte P2) |
darienf | 20:6d2af70c92ab | 1837 | { |
darienf | 20:6d2af70c92ab | 1838 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers GPIOP1P2Out(byte P1, byte P2) |
darienf | 20:6d2af70c92ab | 1839 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP1P2Out |
darienf | 20:6d2af70c92ab | 1840 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1841 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1842 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1843 | reportID(); |
darienf | 20:6d2af70c92ab | 1844 | IOBuf[1] = 3; // case (3): //GPIO value (C51F321 P1 and P2) -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1845 | IOBuf[2] = 0; // case (0): // write |
darienf | 20:6d2af70c92ab | 1846 | IOBuf[3] = P1; // P1 = IO_BUFFER.Ptr[2 + gOffset]; // P1 HI (1) or LO (0); set P1==1 and P1MDOUT==1 for HI-Z |
darienf | 20:6d2af70c92ab | 1847 | IOBuf[4] = P2; // P2 = IO_BUFFER.Ptr[3 + gOffset]; // P2 HI (1) or LO (0); set P2==1 and P1MDOUT==2 for HI-Z |
darienf | 20:6d2af70c92ab | 1848 | writeHID(); |
darienf | 20:6d2af70c92ab | 1849 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1850 | } |
darienf | 20:6d2af70c92ab | 1851 | |
darienf | 20:6d2af70c92ab | 1852 | /// <summary> |
darienf | 20:6d2af70c92ab | 1853 | /// <para>Firmware command code 3 IN = GPIO value (C51F321 P1 and P2) </para> |
darienf | 20:6d2af70c92ab | 1854 | /// |
darienf | 20:6d2af70c92ab | 1855 | /// </summary> |
darienf | 20:6d2af70c92ab | 1856 | /// <param name="P1"></param> |
darienf | 20:6d2af70c92ab | 1857 | /// <param name="P2"></param> |
darienf | 20:6d2af70c92ab | 1858 | public void GPIOP1P2In(out byte P1, out byte P2) |
darienf | 20:6d2af70c92ab | 1859 | { |
darienf | 20:6d2af70c92ab | 1860 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers GPIOP1P2In(out byte P1, out byte P2) |
darienf | 20:6d2af70c92ab | 1861 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP1P2In |
darienf | 20:6d2af70c92ab | 1862 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1863 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1864 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1865 | reportID(); |
darienf | 20:6d2af70c92ab | 1866 | IOBuf[1] = 3; // case (3): //GPIO value (C51F321 P1 and P2) -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1867 | IOBuf[2] = 1; // case (1): // read |
darienf | 20:6d2af70c92ab | 1868 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1869 | // temp = XBR1; |
darienf | 20:6d2af70c92ab | 1870 | // if (IO_BUFFER.Ptr[2+gOffset] & 1) // enable weak pullups in case GP pins are open-collector and not connected to anything (which would falsely give '0') |
darienf | 20:6d2af70c92ab | 1871 | // { |
darienf | 20:6d2af70c92ab | 1872 | // XBR1 &= 0x7F; |
darienf | 20:6d2af70c92ab | 1873 | // Timer0_Init(HALFMS); |
darienf | 20:6d2af70c92ab | 1874 | // T0_Wait(2); |
darienf | 20:6d2af70c92ab | 1875 | // } |
darienf | 20:6d2af70c92ab | 1876 | // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; |
darienf | 20:6d2af70c92ab | 1877 | // IO_BUFFER.Ptr[0+gOffset] = 0; // error status |
darienf | 20:6d2af70c92ab | 1878 | // IO_BUFFER.Ptr[1+gOffset] = P1; // P1 HI (1) or LO (0) |
darienf | 20:6d2af70c92ab | 1879 | // IO_BUFFER.Ptr[2+gOffset] = P2; // P2 HI (1) or LO (0) |
darienf | 20:6d2af70c92ab | 1880 | // XBR1 = temp; |
darienf | 20:6d2af70c92ab | 1881 | // SendPacket(); // no need to check for internal call since only the GUI will request a read through this function |
darienf | 20:6d2af70c92ab | 1882 | P1 = IOBuf[2]; |
darienf | 20:6d2af70c92ab | 1883 | P2 = IOBuf[3]; |
darienf | 20:6d2af70c92ab | 1884 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1885 | } |
darienf | 20:6d2af70c92ab | 1886 | #endregion |
darienf | 20:6d2af70c92ab | 1887 | |
darienf | 20:6d2af70c92ab | 1888 | #region SPI Commands |
darienf | 20:6d2af70c92ab | 1889 | /* |
darienf | 20:6d2af70c92ab | 1890 | |
darienf | 20:6d2af70c92ab | 1891 | /// <summary> |
darienf | 20:6d2af70c92ab | 1892 | /// <para>Firmware command code 5 OUT = I2C clock rate (number of counts to overflow) </para> |
darienf | 20:6d2af70c92ab | 1893 | /// <para>SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</para> |
darienf | 20:6d2af70c92ab | 1894 | /// </summary> |
darienf | 20:6d2af70c92ab | 1895 | /// <param name="ReloadTH1">SMBus timer's count value: ReloadTH1 = (byte)(0.5 + (TimerClockMHz * 1000 / SCL_kHz))</param> |
darienf | 20:6d2af70c92ab | 1896 | public void I2CClockSet(byte ReloadTH1) |
darienf | 20:6d2af70c92ab | 1897 | { |
darienf | 20:6d2af70c92ab | 1898 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CClockSet(byte ReloadTH1) |
darienf | 20:6d2af70c92ab | 1899 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CClockSet |
darienf | 20:6d2af70c92ab | 1900 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1901 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1902 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1903 | reportID(); |
darienf | 20:6d2af70c92ab | 1904 | IOBuf[1] = 5; // case (5): //I2C clock rate (number of counts to overflow) -- see F3xx_USB0_ReportHandler.c void OUT_REPORT_HANDLER(int internalCall) |
darienf | 20:6d2af70c92ab | 1905 | IOBuf[2] = 0; // case (0): // write |
darienf | 20:6d2af70c92ab | 1906 | IOBuf[3] = ReloadTH1; |
darienf | 20:6d2af70c92ab | 1907 | // gSMBusClkFreq = gTimer1ClkFreq / 3.0 / IO_BUFFER.Ptr[2+gOffset]; //GUI sends the number of counts to overflow; HID must calculate the desired SMBus clock frequency |
darienf | 20:6d2af70c92ab | 1908 | // TR1 = 0; |
darienf | 20:6d2af70c92ab | 1909 | // Timer1_Init(); |
darienf | 20:6d2af70c92ab | 1910 | writeHID(); |
darienf | 20:6d2af70c92ab | 1911 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1912 | } |
darienf | 20:6d2af70c92ab | 1913 | |
darienf | 20:6d2af70c92ab | 1914 | /// <summary> |
darienf | 20:6d2af70c92ab | 1915 | /// <para>Firmware command code 5 IN = I2C clock rate (number of counts to overflow) </para> |
darienf | 20:6d2af70c92ab | 1916 | /// <para>SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</para> |
darienf | 20:6d2af70c92ab | 1917 | /// </summary> |
darienf | 20:6d2af70c92ab | 1918 | /// <param name="TimerClockMHz">SMBus timer's clock frequency (in MHz); expect constant 8</param> |
darienf | 20:6d2af70c92ab | 1919 | /// <param name="ReloadTH1">SMBus timer's count value: SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</param> |
darienf | 20:6d2af70c92ab | 1920 | public void I2CClockGet(out byte TimerClockMHz, out byte ReloadTH1) |
darienf | 20:6d2af70c92ab | 1921 | { |
darienf | 20:6d2af70c92ab | 1922 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CClockGet(out byte TimerClockMHz, out byte ReloadTH1) |
darienf | 20:6d2af70c92ab | 1923 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CClockGet |
darienf | 20:6d2af70c92ab | 1924 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 1925 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 1926 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 1927 | reportID(); |
darienf | 20:6d2af70c92ab | 1928 | IOBuf[1] = 5; // case (5): //I2C clock rate (number of counts to overflow) -- see F3xx_USB0_ReportHandler.c void OUT_REPORT_HANDLER(int internalCall) |
darienf | 20:6d2af70c92ab | 1929 | IOBuf[2] = 1; // case (1): // read |
darienf | 20:6d2af70c92ab | 1930 | writeReadHID(); |
darienf | 20:6d2af70c92ab | 1931 | // case (1): // read -- myHID.I2CClockGet(out TimerClockMHz, out ReloadTH1) |
darienf | 20:6d2af70c92ab | 1932 | // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; |
darienf | 20:6d2af70c92ab | 1933 | // IO_BUFFER.Ptr[0+gOffset] = 0; // error status |
darienf | 20:6d2af70c92ab | 1934 | // IO_BUFFER.Ptr[1+gOffset] = gTimer1ClkFreq / 1000000 / 3; //return the SMBus timer's clock frequency (in MHz) |
darienf | 20:6d2af70c92ab | 1935 | // IO_BUFFER.Ptr[2+gOffset] = 256-TH1; //and return the SMBus timer's count value in order to calculate the SMBus clock frequency; TH1 is the reload value that gets loaded into TL0 upon overflow; the reload value is 256-TH1 since (0)-TH1 gives the proper number of counts to overflow |
darienf | 20:6d2af70c92ab | 1936 | // SendPacket(); // no need to check for internal call since only the GUI will request a read through this function |
darienf | 20:6d2af70c92ab | 1937 | // break; |
darienf | 20:6d2af70c92ab | 1938 | TimerClockMHz = IOBuf[2]; |
darienf | 20:6d2af70c92ab | 1939 | ReloadTH1 = IOBuf[3]; |
darienf | 20:6d2af70c92ab | 1940 | // todo: OS24EVK-24 how determine SCL from TimerClockMHZ? Observed I2CClockGet() TimerClockMHz = 8 when SCL = 400kHz. |
darienf | 20:6d2af70c92ab | 1941 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 1942 | } |
darienf | 20:6d2af70c92ab | 1943 | |
darienf | 20:6d2af70c92ab | 1944 | /// <summary> |
darienf | 20:6d2af70c92ab | 1945 | /// <para>Firmware command code 6 OUT = I2C transaction </para> |
darienf | 20:6d2af70c92ab | 1946 | /// |
darienf | 20:6d2af70c92ab | 1947 | /// </summary> |
darienf | 20:6d2af70c92ab | 1948 | /// <param name="deviceAddress">I2C device address, 8-bit left-justified (LSB=R/w bit)</param> |
darienf | 20:6d2af70c92ab | 1949 | /// <param name="numDataBytes">I2C burst write register data count, in bytes</param> |
darienf | 20:6d2af70c92ab | 1950 | /// <param name="numRegBytes">I2C device register address length, normally 1 byte. Can be 0 for SMBusQuick protocol.</param> |
darienf | 20:6d2af70c92ab | 1951 | /// <param name="data">byte array containing the register data to transmit</param> |
darienf | 20:6d2af70c92ab | 1952 | /// <param name="reg">byte array containing the device register address</param> |
darienf | 20:6d2af70c92ab | 1953 | /// <param name="ignoreNACK"></param> |
darienf | 20:6d2af70c92ab | 1954 | public void I2CWrite(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] data, byte[] reg, bool ignoreNACK = false) |
darienf | 20:6d2af70c92ab | 1955 | { |
darienf | 20:6d2af70c92ab | 1956 | // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers |
darienf | 20:6d2af70c92ab | 1957 | // alias of existing function |
darienf | 20:6d2af70c92ab | 1958 | // IOBuf[1] = 6; // case (6): // I2C transaction -- HID.cs void writeI2C() readI2C() -- see F3xx_USB0_ReportHandler.c void OUT_REPORT_HANDLER(int internalCall) |
darienf | 20:6d2af70c92ab | 1959 | writeI2C(deviceAddress, numDataBytes, numRegBytes, data, reg, ignoreNACK); |
darienf | 20:6d2af70c92ab | 1960 | } |
darienf | 20:6d2af70c92ab | 1961 | |
darienf | 20:6d2af70c92ab | 1962 | /// <summary> |
darienf | 20:6d2af70c92ab | 1963 | /// <para>Firmware command code 6 IN = I2C transaction </para> |
darienf | 20:6d2af70c92ab | 1964 | /// |
darienf | 20:6d2af70c92ab | 1965 | /// </summary> |
darienf | 20:6d2af70c92ab | 1966 | /// <param name="deviceAddress">I2C device address, 8-bit left-justified (LSB=R/w bit)</param> |
darienf | 20:6d2af70c92ab | 1967 | /// <param name="numDataBytes">I2C burst read register data count, in bytes</param> |
darienf | 20:6d2af70c92ab | 1968 | /// <param name="numRegBytes">I2C device register address length, normally 1 byte. Can be 0 for SMBusQuick protocol.</param> |
darienf | 20:6d2af70c92ab | 1969 | /// <param name="readData">byte array which receives the register data</param> |
darienf | 20:6d2af70c92ab | 1970 | /// <param name="reg">byte array containing the device register address</param> |
darienf | 20:6d2af70c92ab | 1971 | /// <param name="ignoreNACK"></param> |
darienf | 20:6d2af70c92ab | 1972 | /// <returns>status value; may be HID.I2C_NACK_ERROR if ignoreNACK parameter is true</returns> |
darienf | 20:6d2af70c92ab | 1973 | public int I2CRead(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] readData, byte[] reg, bool ignoreNACK = false) |
darienf | 20:6d2af70c92ab | 1974 | { |
darienf | 20:6d2af70c92ab | 1975 | // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers |
darienf | 20:6d2af70c92ab | 1976 | // alias of existing function |
darienf | 20:6d2af70c92ab | 1977 | // IOBuf[1] = 6; // case (6): // I2C transaction -- HID.cs void writeI2C() readI2C() -- see F3xx_USB0_ReportHandler.c void OUT_REPORT_HANDLER(int internalCall) |
darienf | 20:6d2af70c92ab | 1978 | return readI2C(deviceAddress, numDataBytes, numRegBytes, readData, reg, ignoreNACK); |
darienf | 20:6d2af70c92ab | 1979 | } |
darienf | 20:6d2af70c92ab | 1980 | */ |
darienf | 20:6d2af70c92ab | 1981 | /// <summary> |
darienf | 20:6d2af70c92ab | 1982 | /// <para>Firmware command code 7 OUT = SPI config </para> |
darienf | 20:6d2af70c92ab | 1983 | /// ((SPI0CFG & 0x30) >> 4) + (SPI0CN & 4) |
darienf | 20:6d2af70c92ab | 1984 | /// </summary> |
darienf | 20:6d2af70c92ab | 1985 | /// <param name="config"></param> |
darienf | 20:6d2af70c92ab | 1986 | public void SPIConfigSet(byte config) |
darienf | 20:6d2af70c92ab | 1987 | { |
darienf | 20:6d2af70c92ab | 1988 | // todo: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers SPIConfigSet(byte config) |
darienf | 20:6d2af70c92ab | 1989 | // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. |
darienf | 20:6d2af70c92ab | 1990 | // IOBuf[1] = 7; // case (7): // SPI config -- HID.cs void writeI2C() readI2C() -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 1991 | } |
darienf | 20:6d2af70c92ab | 1992 | |
darienf | 20:6d2af70c92ab | 1993 | /// <summary> |
darienf | 20:6d2af70c92ab | 1994 | /// <para>Firmware command code 7 IN = SPI config </para> |
darienf | 20:6d2af70c92ab | 1995 | /// ((SPI0CFG & 0x30) >> 4) + (SPI0CN & 4) |
darienf | 20:6d2af70c92ab | 1996 | /// </summary> |
darienf | 20:6d2af70c92ab | 1997 | /// <param name="config"></param> |
darienf | 20:6d2af70c92ab | 1998 | public void SPIConfigGet(out byte config) |
darienf | 20:6d2af70c92ab | 1999 | { |
darienf | 20:6d2af70c92ab | 2000 | // todo: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers SPIConfigGet(out byte config) |
darienf | 20:6d2af70c92ab | 2001 | // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. |
darienf | 20:6d2af70c92ab | 2002 | // IOBuf[1] = 7; // case (7): // SPI config -- HID.cs void writeI2C() readI2C() -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 2003 | config = 0; |
darienf | 20:6d2af70c92ab | 2004 | } |
darienf | 20:6d2af70c92ab | 2005 | |
darienf | 20:6d2af70c92ab | 2006 | /// <summary> |
darienf | 20:6d2af70c92ab | 2007 | /// <para>Firmware command code 8 OUT = SPI clock rate </para> |
darienf | 20:6d2af70c92ab | 2008 | /// </summary> |
darienf | 20:6d2af70c92ab | 2009 | /// <param name="SPI0CKR"></param> |
darienf | 20:6d2af70c92ab | 2010 | public void SPIClockSet(byte SPI0CKR) |
darienf | 20:6d2af70c92ab | 2011 | { |
darienf | 20:6d2af70c92ab | 2012 | // todo: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers SPIClockSet(byte SPI0CKR) |
darienf | 20:6d2af70c92ab | 2013 | // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. |
darienf | 20:6d2af70c92ab | 2014 | // IOBuf[1] = 8; // case (8): // SPI clock rate -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 2015 | } |
darienf | 20:6d2af70c92ab | 2016 | |
darienf | 20:6d2af70c92ab | 2017 | /// <summary> |
darienf | 20:6d2af70c92ab | 2018 | /// <para>Firmware command code 8 IN = SPI clock rate </para> |
darienf | 20:6d2af70c92ab | 2019 | /// </summary> |
darienf | 20:6d2af70c92ab | 2020 | /// <param name="SPI0CKR"></param> |
darienf | 20:6d2af70c92ab | 2021 | public void SPIClockGet(out byte SPI0CKR) |
darienf | 20:6d2af70c92ab | 2022 | { |
darienf | 20:6d2af70c92ab | 2023 | // todo: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers SPIClockGet(out byte SPI0CKR) |
darienf | 20:6d2af70c92ab | 2024 | // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. |
darienf | 20:6d2af70c92ab | 2025 | // IOBuf[1] = 8; // case (8): // SPI clock rate -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 2026 | SPI0CKR = 0; |
darienf | 20:6d2af70c92ab | 2027 | } |
darienf | 20:6d2af70c92ab | 2028 | |
darienf | 20:6d2af70c92ab | 2029 | /// <summary> |
darienf | 20:6d2af70c92ab | 2030 | /// <para>Firmware command code 9 = SPI transaction </para> |
darienf | 20:6d2af70c92ab | 2031 | /// </summary> |
darienf | 20:6d2af70c92ab | 2032 | /// <param name="mosiData">SPI MOSI (Master-Out, Slave-In) data to write into slave device</param> |
darienf | 20:6d2af70c92ab | 2033 | /// <param name="misoBuffer">SPI MISO (Master-In, Slave-Out) data buffer containing data bytes received from slave device |
darienf | 20:6d2af70c92ab | 2034 | /// (size will be allocated same size as mosiData)</param> |
darienf | 20:6d2af70c92ab | 2035 | public void SPITransfer(byte[] mosiData, out byte[] misoBuffer) |
darienf | 20:6d2af70c92ab | 2036 | { |
darienf | 20:6d2af70c92ab | 2037 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 SPITransfer(byte[] mosiData, out byte[] misoBuffer) |
darienf | 20:6d2af70c92ab | 2038 | // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. |
darienf | 20:6d2af70c92ab | 2039 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CConfigSet |
darienf | 20:6d2af70c92ab | 2040 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 2041 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 2042 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 2043 | reportID(); |
darienf | 20:6d2af70c92ab | 2044 | // assign default out values in case of failure |
darienf | 20:6d2af70c92ab | 2045 | int byteCount = mosiData.Length; |
darienf | 20:6d2af70c92ab | 2046 | byte num_bytes = (byte)(byteCount & 0xFF); |
darienf | 20:6d2af70c92ab | 2047 | misoBuffer = new byte[byteCount]; |
darienf | 20:6d2af70c92ab | 2048 | for (int byteIndex = 0; byteIndex < byteCount; byteIndex++) |
darienf | 20:6d2af70c92ab | 2049 | { |
darienf | 20:6d2af70c92ab | 2050 | // initial dummy data |
darienf | 20:6d2af70c92ab | 2051 | misoBuffer[byteIndex] = 0x55; |
darienf | 20:6d2af70c92ab | 2052 | } |
darienf | 20:6d2af70c92ab | 2053 | IOBuf[1] = 9; // case (9): // SPI transaction -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 2054 | //IOBuf[8] = x; // IO_BUFFER.Ptr[7+gOffset] -- first byte of data starts on the (7 + offset) byte |
darienf | 20:6d2af70c92ab | 2055 | for (uint byteIndex = 0; byteIndex < num_bytes; byteIndex++) |
darienf | 20:6d2af70c92ab | 2056 | { |
darienf | 20:6d2af70c92ab | 2057 | IOBuf[8 + byteIndex] = (byte)(mosiData[byteIndex]); |
darienf | 20:6d2af70c92ab | 2058 | } |
darienf | 20:6d2af70c92ab | 2059 | //switch (SPImode) |
darienf | 20:6d2af70c92ab | 2060 | //{ |
darienf | 20:6d2af70c92ab | 2061 | // case 0: |
darienf | 20:6d2af70c92ab | 2062 | IOBuf[2] = 0; // IO_BUFFER.Ptr[1+gOffset] -- 0 for SPI_mode0: multi-byte SPI transfer. |
darienf | 20:6d2af70c92ab | 2063 | IOBuf[3] = 0; // IO_BUFFER.Ptr[2+gOffset] -- not used |
darienf | 20:6d2af70c92ab | 2064 | IOBuf[4] = 0; // IO_BUFFER.Ptr[3+gOffset] -- phase_change // !=0 enable changing the clock phase. some slaves change phase between write/read |
darienf | 20:6d2af70c92ab | 2065 | IOBuf[5] = 0; // IO_BUFFER.Ptr[4+gOffset] -- phase_change_byte // byte index where phase change should happen |
darienf | 20:6d2af70c92ab | 2066 | IOBuf[6] = num_bytes; // IO_BUFFER.Ptr[5+gOffset] -- num_bytes |
darienf | 20:6d2af70c92ab | 2067 | IOBuf[7] = 0; // IO_BUFFER.Ptr[6+gOffset] -- not used |
darienf | 20:6d2af70c92ab | 2068 | // IO_BUFFER.Ptr[7+gOffset] -- first byte of data starts on the (7 + offset) byte |
darienf | 20:6d2af70c92ab | 2069 | // SPI_mode0(IO_BUFFER.Ptr[3 + gOffset], IO_BUFFER.Ptr[4 + gOffset], IO_BUFFER.Ptr[5 + gOffset], IO_BUFFER.Ptr); |
darienf | 20:6d2af70c92ab | 2070 | // break; |
darienf | 20:6d2af70c92ab | 2071 | //case 1: |
darienf | 20:6d2af70c92ab | 2072 | // IOBuf[2] = 1; // IO_BUFFER.Ptr[1+gOffset] -- 1 for SPI_mode1: two-byte SPI transfer. read flag: enable changing the clock phase on first byte and changing phase between first and second byte |
darienf | 20:6d2af70c92ab | 2073 | // IOBuf[3] = 0; // IO_BUFFER.Ptr[2+gOffset] -- read flag |
darienf | 20:6d2af70c92ab | 2074 | // // IO_BUFFER.Ptr[3+gOffset] -- not used |
darienf | 20:6d2af70c92ab | 2075 | // // IO_BUFFER.Ptr[4+gOffset] -- not used |
darienf | 20:6d2af70c92ab | 2076 | // // IO_BUFFER.Ptr[5+gOffset] -- not used; num_bytes = 2 |
darienf | 20:6d2af70c92ab | 2077 | // // IO_BUFFER.Ptr[6+gOffset] -- not used |
darienf | 20:6d2af70c92ab | 2078 | // // IO_BUFFER.Ptr[7+gOffset] -- first byte of data starts on the (7 + offset) byte |
darienf | 20:6d2af70c92ab | 2079 | // // SPI_mode1(temp, IO_BUFFER.Ptr); |
darienf | 20:6d2af70c92ab | 2080 | // break; |
darienf | 20:6d2af70c92ab | 2081 | //case 2: |
darienf | 20:6d2af70c92ab | 2082 | // IOBuf[2] = 2; // IO_BUFFER.Ptr[1+gOffset] --2 for SPI_mode2: two-byte SPI transfer. read flag: enable changing the clock phase on first byte and sampling the LSb after the second byte read |
darienf | 20:6d2af70c92ab | 2083 | // IOBuf[3] = 0; // IO_BUFFER.Ptr[2+gOffset] -- read flag |
darienf | 20:6d2af70c92ab | 2084 | // // IO_BUFFER.Ptr[3+gOffset] -- not used |
darienf | 20:6d2af70c92ab | 2085 | // // IO_BUFFER.Ptr[4+gOffset] -- not used |
darienf | 20:6d2af70c92ab | 2086 | // // IO_BUFFER.Ptr[5+gOffset] -- not used; num_bytes = 2 |
darienf | 20:6d2af70c92ab | 2087 | // // IO_BUFFER.Ptr[6+gOffset] -- not used |
darienf | 20:6d2af70c92ab | 2088 | // // IO_BUFFER.Ptr[7+gOffset] -- first byte of data starts on the (7 + offset) byte |
darienf | 20:6d2af70c92ab | 2089 | // // SPI_mode2(temp, IO_BUFFER.Ptr); |
darienf | 20:6d2af70c92ab | 2090 | // break; |
darienf | 20:6d2af70c92ab | 2091 | //} |
darienf | 20:6d2af70c92ab | 2092 | writeHID(); |
darienf | 20:6d2af70c92ab | 2093 | // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; |
darienf | 20:6d2af70c92ab | 2094 | // IO_BUFFER.Ptr[0+gOffset] = 0; // error status |
darienf | 20:6d2af70c92ab | 2095 | // IO_BUFFER.Ptr[1+gOffset] = gI2Cflags; |
darienf | 20:6d2af70c92ab | 2096 | // IO_BUFFER.Ptr[2+gOffset] = (SMB0CF & 0x10) >> 4; // EXTHOLD |
darienf | 20:6d2af70c92ab | 2097 | //gI2Cflags = IOBuf[2]; |
darienf | 20:6d2af70c92ab | 2098 | //EXTHOLD = IOBuf[3]; |
darienf | 20:6d2af70c92ab | 2099 | for (uint byteIndex = 0; byteIndex < byteCount; byteIndex++) |
darienf | 20:6d2af70c92ab | 2100 | { |
darienf | 20:6d2af70c92ab | 2101 | misoBuffer[byteIndex] = IOBuf[byteIndex + 2]; |
darienf | 20:6d2af70c92ab | 2102 | } |
darienf | 20:6d2af70c92ab | 2103 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 2104 | } |
darienf | 20:6d2af70c92ab | 2105 | #endregion |
darienf | 20:6d2af70c92ab | 2106 | |
darienf | 20:6d2af70c92ab | 2107 | #region Interrupt Commands |
darienf | 20:6d2af70c92ab | 2108 | /// <summary> |
darienf | 20:6d2af70c92ab | 2109 | /// <para>Firmware command code 23 OUT = enable INT0 (or Mock HID FIFO data diagnostic) </para> |
darienf | 20:6d2af70c92ab | 2110 | /// <para> |
darienf | 20:6d2af70c92ab | 2111 | /// - INT0Enable(0) disabled (EX0=0) |
darienf | 20:6d2af70c92ab | 2112 | /// - INT0Enable(1) real hardware (EX0=1) |
darienf | 20:6d2af70c92ab | 2113 | /// - INT0Enable(2) Mock HID x1 channel 101, 102, 103, ... |
darienf | 20:6d2af70c92ab | 2114 | /// - INT0Enable(3) Mock HID x2 channels 101, 201, 102, 202, 103, 203, ... |
darienf | 20:6d2af70c92ab | 2115 | /// - INT0Enable(4) Mock HID x3 channels 101, 201, 301, 102, 202, 302, 103, 203, 303, ... |
darienf | 20:6d2af70c92ab | 2116 | /// - INT0Enable(5) Mock HID x4 channels 101, 201, 301, 401, 102, 202, 302, 402, 103, 203, 303, 403, ... |
darienf | 20:6d2af70c92ab | 2117 | /// </para> |
darienf | 20:6d2af70c92ab | 2118 | /// </summary> |
darienf | 20:6d2af70c92ab | 2119 | /// <param name="EX0"></param> |
darienf | 20:6d2af70c92ab | 2120 | public void INT0Enable(byte EX0) |
darienf | 20:6d2af70c92ab | 2121 | { |
darienf | 20:6d2af70c92ab | 2122 | // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers |
darienf | 20:6d2af70c92ab | 2123 | // reset report counter in the HID and enable INT0 |
darienf | 20:6d2af70c92ab | 2124 | // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in INT0Enable |
darienf | 20:6d2af70c92ab | 2125 | mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. |
darienf | 20:6d2af70c92ab | 2126 | FlushQueue(); |
darienf | 20:6d2af70c92ab | 2127 | Array.Clear(IOBuf, 0, IOBuf.Length); |
darienf | 20:6d2af70c92ab | 2128 | reportID(); |
darienf | 20:6d2af70c92ab | 2129 | IOBuf[1] = 23; // enable INT0 -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) |
darienf | 20:6d2af70c92ab | 2130 | IOBuf[2] = EX0; // reportTypeFlag; // 1; |
darienf | 20:6d2af70c92ab | 2131 | writeHID(); |
darienf | 20:6d2af70c92ab | 2132 | _firmwareINT0Enabled = EX0; |
darienf | 20:6d2af70c92ab | 2133 | mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. |
darienf | 20:6d2af70c92ab | 2134 | } |
darienf | 20:6d2af70c92ab | 2135 | private byte _firmwareINT0Enabled = 0; |
darienf | 20:6d2af70c92ab | 2136 | public byte FirmwareINT0Enabled { get { return _firmwareINT0Enabled; } } |
darienf | 20:6d2af70c92ab | 2137 | #endregion |
darienf | 20:6d2af70c92ab | 2138 | |
darienf | 20:6d2af70c92ab | 2139 | #endregion |
darienf | 20:6d2af70c92ab | 2140 | |
darienf | 20:6d2af70c92ab | 2141 | |
darienf | 20:6d2af70c92ab | 2142 | } |
darienf | 20:6d2af70c92ab | 2143 | } |