Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed MAX14720 MAX30205 USBDevice
HID.cs
00001 /******************************************************************************* 00002 * Copyright (C) 2016 Maxim Integrated Products, Inc., All rights Reserved. 00003 * 00004 * This software is protected by copyright laws of the United States and 00005 * of foreign countries. This material may also be protected by patent laws 00006 * and technology transfer regulations of the United States and of foreign 00007 * countries. This software is furnished under a license agreement and/or a 00008 * nondisclosure agreement and may only be used or reproduced in accordance 00009 * with the terms of those agreements. Dissemination of this information to 00010 * any party or parties not specified in the license agreement and/or 00011 * nondisclosure agreement is expressly prohibited. 00012 * 00013 * The above copyright notice and this permission notice shall be included 00014 * in all copies or substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00017 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00019 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00020 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00021 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00022 * OTHER DEALINGS IN THE SOFTWARE. 00023 * 00024 * Except as contained in this notice, the name of Maxim Integrated 00025 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00026 * Products, Inc. Branding Policy. 00027 * 00028 * The mere transfer of this software does not imply any licenses 00029 * of trade secrets, proprietary technology, copyrights, patents, 00030 * trademarks, maskwork rights, or any other form of intellectual 00031 * property whatsoever. Maxim Integrated Products, Inc. retains all 00032 * ownership rights. 00033 ******************************************************************************* 00034 */ 00035 00036 using System; 00037 using System.Collections; 00038 using System.Threading; 00039 using System.IO; 00040 using System.Windows.Forms; 00041 using System.Runtime.InteropServices; 00042 using Microsoft.Win32.SafeHandles; 00043 using System.Text; 00044 00045 //------------------------------------------------------------------------------------------ 00046 // OS24EVK-59 split into HeartRateApp EXE and MAX30101 DLL. 00047 // Moved all MAX30101 DLL classes into namespace Maxim.MAX30101GUI 00048 // Moved all HeartRateApp GUI classes into namespace Maxim.MAX30101 00049 // OS24EVK-59 Create separate project that builds Maxim.MAX30101GUI DLL library 00050 00051 // OS24EVK-59 moved class HID into namespace Maxim.MAX30101 instead of namespace HeartRateApp 00052 namespace RPCSupport 00053 { 00054 #pragma warning disable 1574 00055 /// <summary> 00056 /// USB Human Interface Device functions to connect to EV kit without requiring a custom device driver 00057 /// </summary> 00058 #pragma warning restore 1574 00059 internal class HID 00060 { 00061 00062 #region Globals 00063 private IntPtr EventObject; 00064 private System.Threading.NativeOverlapped managedOverlapped; 00065 private IntPtr nonManagedOverlapped; 00066 private IntPtr nonManagedBuffer; 00067 public SafeFileHandle writeHandle; 00068 public ArrayList writeHandleArray = new ArrayList(); 00069 public SafeFileHandle readHandle; 00070 public ArrayList readHandleArray = new ArrayList(); 00071 public ArrayList desiredHIDPathNameArray = new ArrayList(); 00072 00073 public const int DEFAULT_VENDOR_ID = 0x0B6A; // update USB VID PID from default Vid_16C0&Pid_0830 00074 public const int DEFAULT_PRODUCT_ID = 0x1366; // MAX30100EVKit USB Vid_0B6A&Pid_1364; MAX30101EVKit USB Vid_0B6A&Pid_1365 00075 public const byte DEFAULT_I2C_ADDRESS = 0xAE; // 8-bit address (write address) 00076 00077 public String deviceID = System.String.Format("Vid_{0:x4}&Pid_{1:x4}", DEFAULT_VENDOR_ID, DEFAULT_PRODUCT_ID); 00078 00079 private bool explicit_report_id = false; 00080 private const byte DEFAULT_REPORT_ID = 0; 00081 private const byte SHORT_REPORT_ID = 1; 00082 public const byte HID_REPORT_ID_1 = 1; // MAX30101 optical data, 3 bytes per channel, up to 3 channels per sample 00083 public const byte HID_REPORT_ID_2 = 2; // LIS2DH accelerometer data, 2 bytes per channel, 3 channels per sample 00084 public const byte HID_REPORT_ID_3 = 3; // reserved 00085 private const byte USB_OVERFLOW = 8; 00086 private const byte USB_WRITE_ERROR = 4; 00087 private const byte USB_READ_ERROR = 2; 00088 public const byte I2C_NACK_ERROR = 1; 00089 private const byte API_FAIL = 0; //API functions return non-0 upon success, to easily denote 'true' for C programs 00090 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. 00091 private const byte GP_SUCCESS = 3; 00092 private const byte GP_FAIL = 0; 00093 private const byte REPORT_SIZE = 65; 00094 00095 #region I2C clock speeds 00096 public const byte I2C_ClOCK_100KHz = 0; 00097 public const byte I2C_ClOCK_400KHz = 1; 00098 public const byte I2C_ClOCK_1MHz = 2; 00099 00100 #endregion 00101 00102 #region Command Codes 00103 private const byte COMMAND_SUCCESS = 0xEE; 00104 private const byte COMMAND_FAILED = 0xFF; 00105 00106 private const byte GET_FIRMWARE_VERSION = 0x00; 00107 private const byte SET_LED = 0x01; 00108 private const byte I2C_INIT = 0x03; 00109 private const byte I2C_CONFIG = 0x04; 00110 private const byte I2C_TRANSACTION = 0x06; 00111 #endregion 00112 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] before FlushQueue() 00113 // mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 00114 // mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 00115 public static Mutex mutexGuardIOBuf = new Mutex(); 00116 // 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()? 00117 public byte[] IOBuf = new byte[REPORT_SIZE]; 00118 00119 private const int IOtimeout = 10000; 00120 00121 // API declarations relating to device management (SetupDixxx and 00122 // RegisterDeviceNotification functions). 00123 00124 // from dbt.h 00125 00126 internal const Int32 DBT_DEVNODES_CHANGED = 7; 00127 internal const Int32 DBT_DEVICEARRIVAL = 0X8000; 00128 internal const Int32 DBT_DEVICEREMOVECOMPLETE = 0X8004; 00129 internal const Int32 DBT_DEVTYP_DEVICEINTERFACE = 5; 00130 internal const Int32 DBT_DEVTYP_HANDLE = 6; 00131 internal const Int32 DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 4; 00132 internal const Int32 DEVICE_NOTIFY_SERVICE_HANDLE = 1; 00133 internal const Int32 DEVICE_NOTIFY_WINDOW_HANDLE = 0; 00134 internal const Int32 WM_DEVICECHANGE = 0X219; 00135 internal const Int32 SPDRP_HARDWAREID = 1; 00136 00137 // from setupapi.h 00138 00139 internal const Int32 DIGCF_PRESENT = 2; 00140 internal const Int32 DIGCF_DEVICEINTERFACE = 0X10; 00141 #endregion 00142 00143 #region Variable Stuctures 00144 // Two declarations for the DEV_BROADCAST_DEVICEINTERFACE structure. 00145 00146 // Use this one in the call to RegisterDeviceNotification() and 00147 // in checking dbch_devicetype in a DEV_BROADCAST_HDR structure: 00148 00149 [StructLayout(LayoutKind.Sequential)] 00150 internal class DEV_BROADCAST_DEVICEINTERFACE 00151 { 00152 internal Int32 dbcc_size; 00153 internal Int32 dbcc_devicetype; 00154 internal Int32 dbcc_reserved; 00155 internal Guid dbcc_classguid; 00156 internal Int16 dbcc_name; 00157 } 00158 00159 // Use this to read the dbcc_name String and classguid: 00160 00161 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 00162 internal class DEV_BROADCAST_DEVICEINTERFACE_1 00163 { 00164 internal Int32 dbcc_size; 00165 internal Int32 dbcc_devicetype; 00166 internal Int32 dbcc_reserved; 00167 [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)] 00168 internal Byte[] dbcc_classguid; 00169 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)] 00170 internal Char[] dbcc_name; 00171 } 00172 00173 [StructLayout(LayoutKind.Sequential)] 00174 internal class DEV_BROADCAST_HDR 00175 { 00176 internal Int32 dbch_size; 00177 internal Int32 dbch_devicetype; 00178 internal Int32 dbch_reserved; 00179 } 00180 00181 internal struct SP_DEVICE_INTERFACE_DATA 00182 { 00183 internal Int32 cbSize; 00184 internal System.Guid InterfaceClassGuid; 00185 internal Int32 Flags; 00186 internal IntPtr Reserved; 00187 } 00188 00189 //[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 00190 //internal struct SP_DEVICE_INTERFACE_DETAIL_DATA 00191 //{ 00192 // internal Int32 cbSize; 00193 // //internal String DevicePath; 00194 // internal Char[] DevicePath; 00195 //} 00196 00197 // warning CS0649: Field 'Maxim.MAX30101.HID.SP_DEVINFO_DATA.cbSize' is never assigned to, and will always have its default value 0 00198 #pragma warning disable 0649 00199 internal struct SP_DEVINFO_DATA 00200 { 00201 internal Int32 cbSize; 00202 internal System.Guid ClassGuid; 00203 internal Int32 DevInst; 00204 internal Int32 Reserved; 00205 } 00206 #pragma warning restore 0649 00207 #endregion 00208 00209 #region External Functions from dll 00210 //HDEVINFO SetupDiGetClassDevs(const GUID *ClassGuid, PCTSTR Enumerator, HWND hwndParent, DWORD Flags); 00211 [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 00212 internal static extern IntPtr SetupDiGetClassDevs(ref System.Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, Int32 Flags); 00213 00214 //BOOL SetupDiDestroyDeviceInfoList(HDEVINFO DeviceInfoSet); 00215 [DllImport("setupapi.dll", SetLastError = true)] 00216 internal static extern Boolean SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); 00217 00218 //BOOL SetupDiEnumDeviceInterfaces(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, const GUID *InterfaceClassGuid, DWORD MemberIndex, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); 00219 [DllImport("setupapi.dll", SetLastError = true)] 00220 internal static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, ref System.Guid InterfaceClassGuid, Int32 MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); 00221 [DllImport("setupapi.dll", SetLastError = true)] 00222 // required to pass DeviceInfoData=null 00223 internal static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref System.Guid InterfaceClassGuid, Int32 MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); 00224 00225 //BOOL SetupDiGetDeviceInterfaceDetail(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, DWORD DeviceInterfaceDetailDataSize, PDWORD RequiredSize, PSP_DEVINFO_DATA DeviceInfoData); 00226 //[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 00227 //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); 00228 //[DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 00229 //// required to pass DeviceInfoData=null 00230 //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); 00231 // cannot get SP_DEVICE_INTERFACE_DETAIL_DATA's DevicePath field to work properly, so use IntPtr instead of ref SP_DEVICE_INTERFACE_DATA 00232 [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 00233 // required to pass DeviceInterfaceDetailData=null 00234 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); 00235 [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 00236 // required to pass DeviceInterfaceDetailData=null, DeviceInfoData=null 00237 internal static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, IntPtr DeviceInfoData); 00238 00239 //BOOL SetupDiEnumDeviceInfo(HDEVINFO DeviceInfoSet, DWORD MemberIndex, PSP_DEVINFO_DATA DeviceInfoData); 00240 [DllImport("setupapi.dll", SetLastError = true)] 00241 internal static extern Boolean SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, Int32 MemberIndex, ref SP_DEVINFO_DATA DevInfoData); 00242 00243 //BOOL SetupDiGetDeviceRegistryProperty(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize); 00244 [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)] 00245 internal static extern Boolean SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DevInfoData, Int32 Property, IntPtr PropertyRegDataType, IntPtr PropertyBuffer, Int32 PropertyBufferSize, ref Int32 RequiredSize); 00246 00247 [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 00248 internal static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, Int32 Flags); 00249 00250 [DllImport("user32.dll", SetLastError = true)] 00251 internal static extern Boolean UnregisterDeviceNotification(IntPtr Handle); 00252 00253 // API declarations for HID communications. 00254 00255 // from hidpi.h 00256 // Typedef enum defines a set of integer constants for HidP_Report_Type 00257 00258 internal const Int16 HidP_Input = 0; 00259 internal const Int16 HidP_Output = 1; 00260 internal const Int16 HidP_Feature = 2; 00261 00262 [StructLayout(LayoutKind.Sequential)] 00263 internal struct HIDD_ATTRIBUTES 00264 { 00265 internal Int32 Size; 00266 internal UInt16 VendorID; 00267 internal UInt16 ProductID; 00268 internal UInt16 VersionNumber; 00269 } 00270 00271 [DllImport("hid.dll", SetLastError = true)] 00272 internal static extern Boolean HidD_FlushQueue(SafeFileHandle HidDeviceObject); 00273 00274 [DllImport("hid.dll", SetLastError = true)] 00275 internal static extern Boolean HidD_GetAttributes(SafeFileHandle HidDeviceObject, ref HIDD_ATTRIBUTES Attributes); 00276 00277 [DllImport("hid.dll", SetLastError = true)] 00278 internal static extern void HidD_GetHidGuid(ref System.Guid HidGuid); 00279 #endregion 00280 00281 #region Setup HID 00282 public void getHidGuid(ref System.Guid hidGuid) 00283 { 00284 DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00285 #if DEBUG 00286 HidD_GetHidGuid(ref hidGuid); 00287 #else 00288 try 00289 { 00290 HidD_GetHidGuid(ref hidGuid); 00291 } 00292 catch (Exception ex) 00293 { 00294 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00295 } 00296 #endif 00297 DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00298 } 00299 00300 public string DebugMessage; 00301 //public void TraceMessage(string message, 00302 //[System.Runtime.CompilerServices.CallerMemberName] string memberName = "", 00303 //[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", 00304 //[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) 00305 //{ 00306 // Console.WriteLine("message: " + message); 00307 // Console.WriteLine("member name: " + memberName); 00308 // Console.WriteLine("source file path: " + sourceFilePath); 00309 // Console.WriteLine("source line number: " + sourceLineNumber); 00310 //} 00311 00312 /// <summary> 00313 /// FindDesiredHIDPathNamesFromGuid() only appends to desiredHIDPathNameArray. 00314 /// Desired HIDs that have been removed from the system are removed from desiredHIDPathNameArray in openHIDhandles 00315 /// </summary> 00316 /// <param name="myGuid"></param> 00317 private void FindDesiredHIDPathNamesFromGuid(System.Guid myGuid) 00318 { 00319 DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00320 // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. 00321 // But I never see this kind of exception thrown from within the C# GUI. 00322 // HID.findHIDs() still raises the exception in Matlab, 00323 // Message: Arithmetic operation resulted in an overflow. 00324 // 00325 // % Required: connect to MAX30101EVKIT hardware 00326 // fprintf('Connecting to MAX30101EVKIT hardware...\n'); 00327 // for trial=0:2000 00328 // try 00329 // %pause(1) % delay at least 1 second 00330 // myMAX30101.myHID.findHIDs(); 00331 // % Sometimes we get Error using MAX30101Example 00332 // % If this happens, try clearing the workspace and run again. 00333 // % Message: Arithmetic operation resulted in an overflow. 00334 // % FindDesiredHIDPathNamesFromGuid 00335 // % findHIDs 00336 // % Source: MAX30101 00337 // % HelpLink: 00338 // if (myMAX30101.myHID.isConnected()) 00339 // break 00340 // end 00341 // catch me 00342 // % disp(me) 00343 // end 00344 // end 00345 // 00346 // If matlab does successfully connect to USB, it is able to get 00347 // streaming data through the PartialArrayIntAvailable event 00348 // handler -- even though it can't understand 00349 // System.Collections.ArrayList data, it does at least understand 00350 // Array<System.Int32> or int[] data. 00351 // 00352 Int32 memberIndex = 0; 00353 Int32 bufferSize = 0; 00354 IntPtr deviceInfoSet = new System.IntPtr(); 00355 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(); 00356 IntPtr deviceInterfaceDetailDataBuffer = IntPtr.Zero; 00357 00358 // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. 00359 // diagnostic: trying to avoid "Arithmetic overflow" from matlab. Limit the number of HID devices to be checked. 00360 const int memberIndexLimit = 100; 00361 00362 #if DEBUG 00363 #else 00364 try 00365 { 00366 #endif 00367 DebugMessage = string.Format("{0} first deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00368 deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 00369 00370 memberIndex = 0; 00371 00372 // The cbSize element of the DeviceInterfaceData structure must be set to the structure's size in bytes. 00373 // The size is 28 bytes for 32-bit code and 32 bits for 64-bit code. 00374 DeviceInterfaceData.cbSize = Marshal.SizeOf(DeviceInterfaceData); 00375 00376 while (memberIndex < memberIndexLimit) 00377 { 00378 // Begin with memberIndex = 0 and increment through the device information set until no more devices are available. 00379 DebugMessage = string.Format("{0} memberIndex={1} first SetupDiEnumDeviceInterfaces ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00380 if (!SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref myGuid, memberIndex, ref DeviceInterfaceData)) 00381 { 00382 break; 00383 } 00384 00385 DebugMessage = string.Format("{0} memberIndex={1} first SetupDiGetDeviceInterfaceDetail ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00386 SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); 00387 //tempLastError = GetLastError(); 00388 //if (tempLastError != ERROR_INSUFFICIENT_BUFFER) // ERROR_INSUFFICIENT_BUFFER is expected on this first call 00389 // break; 00390 //FIXME add error check 00391 00392 // Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size. 00393 DebugMessage = string.Format("{0} memberIndex={1} Marshal.AllocHGlobal(bufferSize) ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00394 deviceInterfaceDetailDataBuffer = Marshal.AllocHGlobal(bufferSize); 00395 // Returns a System.IntPtr pointer to the newly allocated global heap memory. 00396 // This memory must be released using the Marshal.FreeHGlobal method. 00397 // Marshal.AllocHGlobal(numBytes) could throw OutOfMemoryException ? 00398 00399 // Store cbSize in the first bytes of the array. The number of bytes varies with 32- and 64-bit systems. 00400 DebugMessage = string.Format("{0} memberIndex={1} Marshal.WriteInt32 ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00401 Marshal.WriteInt32(deviceInterfaceDetailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); 00402 00403 // Call SetupDiGetDeviceInterfaceDetail again. 00404 // This time, pass a pointer to DetailDataBuffer and the returned required buffer size. 00405 DebugMessage = string.Format("{0} memberIndex={1} second SetupDiGetDeviceInterfaceDetail ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00406 if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, deviceInterfaceDetailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero)) 00407 break; 00408 00409 // Skip over cbsize (4 bytes) to get the address of the devicePathName. 00410 // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message 00411 DebugMessage = string.Format("{0} memberIndex={1} IntPtr pDevicePathName = IntPtr.Add(deviceInterfaceDetailDataBuffer, 4); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00412 IntPtr pDevicePathName = IntPtr.Add(deviceInterfaceDetailDataBuffer, 4); 00413 // DebugMessage = string.Format("{0} memberIndex={1} new IntPtr(deviceInterfaceDetailDataBuffer.ToInt32() + 4); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00414 // BAD CODE. IntPtr pDevicePathName = new IntPtr(deviceInterfaceDetailDataBuffer.ToInt32() + 4); 00415 // BAD CODE. assumes the pointer is a 32-bit address, intermittently fails from 64-bit matlab client. 00416 00417 // Get the String containing the devicePathName. 00418 DebugMessage = string.Format("{0} memberIndex={1} Marshal.PtrToStringAuto(pDevicePathName); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00419 string tempPathName = Marshal.PtrToStringAuto(pDevicePathName); 00420 00421 // match any device pathname that contains deviceID (case-insensitive match) "Vid_{0:x4}&Pid_{1:x4}" 00422 DebugMessage = string.Format("{0} memberIndex={1} if (tempPathName.ToLower().IndexOf(deviceID.ToLower()) != -1) ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00423 if (tempPathName.ToLower().IndexOf(deviceID.ToLower()) != -1) 00424 { 00425 DebugMessage = string.Format("{0} memberIndex={1} desiredHIDPathNameArray.Add(tempPathName); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00426 desiredHIDPathNameArray.Add(tempPathName); 00427 } 00428 00429 DebugMessage = string.Format("{0} memberIndex={1} memberIndex = memberIndex + 1; ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00430 00431 // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message 00432 // why didn't they call Marshal.FreeHGlobal here, inside the while loop? Isn't this a memory leak? 00433 // Free the memory allocated previously by AllocHGlobal. 00434 if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) 00435 { 00436 Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); 00437 deviceInterfaceDetailDataBuffer = IntPtr.Zero; 00438 } 00439 00440 memberIndex = memberIndex + 1; 00441 } 00442 #if DEBUG 00443 // Free the memory allocated previously by AllocHGlobal. 00444 if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) 00445 Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); 00446 00447 if (deviceInfoSet != IntPtr.Zero) 00448 SetupDiDestroyDeviceInfoList(deviceInfoSet); 00449 #else 00450 } 00451 catch (Exception ex) 00452 { 00453 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00454 } 00455 finally 00456 { 00457 // Free the memory allocated previously by AllocHGlobal. 00458 if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) 00459 Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); 00460 00461 if (deviceInfoSet != IntPtr.Zero) 00462 SetupDiDestroyDeviceInfoList(deviceInfoSet); 00463 } 00464 #endif 00465 DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00466 } 00467 00468 private void FindAllHIDPathNamesFromGuid(System.Guid myGuid, ArrayList allHIDPathNameArray) 00469 { 00470 DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00471 // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. 00472 // But I never see this kind of exception thrown from within the C# GUI. 00473 // HID.findHIDs() still raises the exception in Matlab, 00474 // Message: Arithmetic operation resulted in an overflow. 00475 Int32 memberIndex = 0; 00476 Int32 bufferSize = 0; 00477 IntPtr deviceInfoSet = new System.IntPtr(); 00478 SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(); 00479 IntPtr deviceInterfaceDetailDataBuffer = IntPtr.Zero; 00480 00481 // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. 00482 // diagnostic: trying to avoid "Arithmetic overflow" from matlab. Limit the number of HID devices to be checked. 00483 const int memberIndexLimit = 100; 00484 00485 00486 #if DEBUG 00487 #else 00488 try 00489 { 00490 #endif 00491 DebugMessage = string.Format("{0} first deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00492 deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); 00493 00494 memberIndex = 0; 00495 00496 // The cbSize element of the DeviceInterfaceData structure must be set to the structure's size in bytes. 00497 // The size is 28 bytes for 32-bit code and 32 bits for 64-bit code. 00498 DeviceInterfaceData.cbSize = Marshal.SizeOf(DeviceInterfaceData); 00499 00500 // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. 00501 while (memberIndex < memberIndexLimit) 00502 { 00503 DebugMessage = string.Format("{0} memberIndex={1} first SetupDiEnumDeviceInterfaces ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00504 if (!SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref myGuid, memberIndex, ref DeviceInterfaceData)) 00505 { 00506 break; 00507 } 00508 00509 DebugMessage = string.Format("{0} memberIndex={1} first SetupDiGetDeviceInterfaceDetail ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00510 SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); 00511 00512 // Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size. 00513 DebugMessage = string.Format("{0} memberIndex={1} Marshal.AllocHGlobal(bufferSize) ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00514 deviceInterfaceDetailDataBuffer = Marshal.AllocHGlobal(bufferSize); 00515 00516 // Store cbSize in the first bytes of the array. The number of bytes varies with 32- and 64-bit systems. 00517 DebugMessage = string.Format("{0} memberIndex={1} Marshal.WriteInt32 ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00518 Marshal.WriteInt32(deviceInterfaceDetailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); 00519 00520 // Call SetupDiGetDeviceInterfaceDetail again. 00521 // This time, pass a pointer to deviceInterfaceDetailDataBuffer and the returned required buffer size. 00522 DebugMessage = string.Format("{0} memberIndex={1} second SetupDiGetDeviceInterfaceDetail ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00523 if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, deviceInterfaceDetailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero)) 00524 break; 00525 00526 // Skip over cbsize (4 bytes) to get the address of the devicePathName. 00527 // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message 00528 DebugMessage = string.Format("{0} memberIndex={1} IntPtr pDevicePathName = IntPtr.Add(deviceInterfaceDetailDataBuffer, 4); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00529 // example: IntPtr right way to add an offset (portable to 64-bit clients) 00530 IntPtr pDevicePathName = IntPtr.Add(deviceInterfaceDetailDataBuffer, 4); 00531 // DebugMessage = string.Format("{0} memberIndex={1} IntPtr pDevicePathName = new IntPtr(deviceInterfaceDetailDataBuffer.ToInt32() + 4); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00532 // BAD CODE. IntPtr pDevicePathName = new IntPtr(deviceInterfaceDetailDataBuffer.ToInt32() + 4); 00533 // BAD CODE. assumes the pointer is a 32-bit address, intermittently fails from 64-bit matlab client. 00534 00535 // Get the String containing the devicePathName. 00536 DebugMessage = string.Format("{0} memberIndex={1} Marshal.PtrToStringAuto(pDevicePathName); ", System.Reflection.MethodInfo.GetCurrentMethod().Name, memberIndex); 00537 allHIDPathNameArray.Add(Marshal.PtrToStringAuto(pDevicePathName)); 00538 00539 // VERIFY: https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message 00540 // why didn't they call Marshal.FreeHGlobal here, inside the while loop? Isn't this a memory leak? 00541 // Free the memory allocated previously by AllocHGlobal. 00542 if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) 00543 { 00544 Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); 00545 deviceInterfaceDetailDataBuffer = IntPtr.Zero; 00546 } 00547 00548 memberIndex = memberIndex + 1; 00549 } 00550 #if DEBUG 00551 // Free the memory allocated previously by AllocHGlobal. 00552 if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) 00553 Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); 00554 00555 if (deviceInfoSet != IntPtr.Zero) 00556 SetupDiDestroyDeviceInfoList(deviceInfoSet); 00557 #else 00558 } 00559 catch (Exception ex) 00560 { 00561 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00562 } 00563 finally 00564 { 00565 // Free the memory allocated previously by AllocHGlobal. 00566 if (deviceInterfaceDetailDataBuffer != IntPtr.Zero) 00567 Marshal.FreeHGlobal(deviceInterfaceDetailDataBuffer); 00568 00569 if (deviceInfoSet != IntPtr.Zero) 00570 SetupDiDestroyDeviceInfoList(deviceInfoSet); 00571 } 00572 #endif 00573 DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00574 } 00575 00576 public bool isConnected() 00577 { 00578 try 00579 { 00580 return desiredHIDPathNameArray.Count != 0 ? true : false; 00581 } 00582 catch (Exception ex) 00583 { 00584 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00585 } 00586 } 00587 00588 00589 /// <summary> 00590 /// Called when a WM_DEVICECHANGE message has arrived, 00591 /// indicating that a device has been attached or removed. 00592 /// 00593 /// </summary> 00594 /// <param name="m"> a message with information about the device </param> 00595 /// <returns>true on HID device arrival or remove complete</returns> 00596 public bool HandleWMDeviceChangeMessage(Message m) 00597 { 00598 // Example code: 00599 // 00600 // <code> 00601 // protected override void WndProc(ref Message m) 00602 // { 00603 // if (myHID != null) 00604 // { 00605 // if (myHID.HandleWMDeviceChangeMessage(m) /* m.Msg == HID.WM_DEVICECHANGE */ ) 00606 // { 00607 // // optional: handle newly arrived connection or surprise disconnect 00608 // } 00609 // } 00610 // // Let the base form process the message. 00611 // base.WndProc(ref m); 00612 // } 00613 // </code> 00614 // 00615 // https://jira.maxim-ic.com/browse/OS24EVK-59 WndProc if HID.WM_DEVICECHANGE do HID.OnDeviceChange(Message m) 00616 try 00617 { 00618 if (m.Msg == HID.WM_DEVICECHANGE) 00619 { 00620 //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. 00621 if ( 00622 ( m.WParam.ToInt32() == HID.DBT_DEVICEARRIVAL 00623 || m.WParam.ToInt32() == HID.DBT_DEVICEREMOVECOMPLETE 00624 ) 00625 && 00626 (m.LParam.ToInt32() != 0) 00627 && 00628 DeviceIDMatch(m) 00629 ) 00630 { 00631 closeHIDhandles(); 00632 findHIDs(); 00633 // cboEVB_init(); 00634 return true; 00635 } 00636 } 00637 return false; 00638 } 00639 catch (Exception ex) 00640 { 00641 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00642 } 00643 } 00644 00645 /// <summary> 00646 /// findHIDs() called upon startup or if a desired HID has been inserted or removed 00647 /// </summary> 00648 public void findHIDs() 00649 { 00650 DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00651 ArrayList allHIDPathNameArray = new ArrayList(); 00652 System.Guid hidGuid = new System.Guid(); 00653 00654 // https://jira.maxim-ic.com/browse/OS24EVK-59 (intermittent) Matlab Exception Message: Arithmetic operation resulted in an overflow. 00655 #if DEBUG 00656 #else 00657 try 00658 { 00659 #endif 00660 HidD_GetHidGuid(ref hidGuid); 00661 // FindDesiredHIDPathNamesFromGuid() builds desiredHIDPathNameArray which is a list of all desired HIDs in the system 00662 // desiredHIDPathNameArray is a global list and is used to maintain the order of desired HIDs in the selection list. 00663 // USB ports have different priorities, and the user could have attached the first desired HID to a lower priority port. 00664 // 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. 00665 // Note that desiredHIDPathNameArray is only appended to or deleted from; it is never recreated in whole. 00666 // 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. 00667 // These duplicates pathnames are appended after the initial list, so they won't affect order. 00668 FindDesiredHIDPathNamesFromGuid(hidGuid); 00669 // 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. 00670 FindAllHIDPathNamesFromGuid(hidGuid, allHIDPathNameArray); 00671 // openHIDhandles() gets handles for all desired HIDs 00672 // openHIDhandles() loops through all attached HIDs and checks for a match of each item in desiredHIDPathNameArray. This maintains the attachement order. 00673 // If a previously attached HID has been removed, it won't be found in allHIDPathNameArray and it will be removed from desiredHIDPathNameArray. 00674 openHIDhandles(allHIDPathNameArray); 00675 if (desiredHIDPathNameArray.Count != 0) 00676 { 00677 prepareForOverlappedTransfer(); 00678 } 00679 #if DEBUG 00680 #else 00681 } 00682 catch (Exception ex) 00683 { 00684 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00685 } 00686 #endif 00687 DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00688 } 00689 00690 private void openHIDhandles(ArrayList allHIDPathNameArray) 00691 { 00692 DebugMessage = string.Format("{0} entered", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00693 int desiredHIDPathNameArrayCounter; 00694 int allHIDPathNameArrayCounter; 00695 bool found_installed_device; 00696 try 00697 { 00698 desiredHIDPathNameArrayCounter = 0; 00699 while (desiredHIDPathNameArrayCounter < desiredHIDPathNameArray.Count) // count will change if a previously installed device has been removed, so don't use a for loop 00700 { 00701 found_installed_device = false; 00702 allHIDPathNameArrayCounter = 0; 00703 while (allHIDPathNameArrayCounter < allHIDPathNameArray.Count) 00704 { 00705 if ((string)allHIDPathNameArray[allHIDPathNameArrayCounter] == (string)desiredHIDPathNameArray[desiredHIDPathNameArrayCounter]) 00706 { 00707 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); 00708 if (!(writeHandle.IsInvalid)) 00709 { 00710 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); 00711 if (!(readHandle.IsInvalid)) 00712 { 00713 writeHandleArray.Add(writeHandle); 00714 readHandleArray.Add(readHandle); 00715 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) 00716 found_installed_device = true; 00717 } 00718 else 00719 { 00720 writeHandle.Close(); 00721 writeHandle = null; 00722 readHandle = null; 00723 } 00724 } 00725 else 00726 { 00727 writeHandle = null; 00728 readHandle = null; 00729 } 00730 break; 00731 } 00732 allHIDPathNameArrayCounter++; 00733 } 00734 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. 00735 desiredHIDPathNameArray.RemoveAt(desiredHIDPathNameArrayCounter); // decrements count by 1; don't increment desiredHIDPathNameArrayCounter 00736 else 00737 desiredHIDPathNameArrayCounter++; 00738 } 00739 } 00740 catch (Exception ex) 00741 { 00742 DebugMessage = string.Format("{0} exception {1}", System.Reflection.MethodInfo.GetCurrentMethod().Name, ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00743 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00744 } 00745 DebugMessage = string.Format("{0} exited", System.Reflection.MethodInfo.GetCurrentMethod().Name); 00746 } 00747 00748 00749 00750 private void prepareForOverlappedTransfer() 00751 { 00752 try 00753 { 00754 EventObject = FileIO.CreateEvent(IntPtr.Zero, false, false, String.Empty); 00755 managedOverlapped.OffsetLow = 0; 00756 managedOverlapped.OffsetHigh = 0; 00757 managedOverlapped.EventHandle = EventObject; // HIDOverlapped is the overlapped structure used in ReadFile; EventObject will be signaled upon completion of ReadFile 00758 nonManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(managedOverlapped)); 00759 Marshal.StructureToPtr(managedOverlapped, nonManagedOverlapped, false); 00760 00761 nonManagedBuffer = Marshal.AllocHGlobal(REPORT_SIZE); 00762 } 00763 catch (Exception ex) 00764 { 00765 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00766 } 00767 } 00768 00769 /// <summary> 00770 /// Requests to receive a notification when a device is attached or removed. 00771 /// </summary> 00772 /// 00773 /// <param name="formHandle"> handle to the window that will receive device events. </param> 00774 /// <param name="classGuid"> device interface GUID. </param> 00775 /// <param name="deviceNotificationHandle"> returned device notification handle. </param> 00776 /// 00777 /// <returns> 00778 /// True on success. 00779 /// </returns> 00780 /// 00781 public Boolean RegisterForDeviceNotifications(IntPtr formHandle, Guid classGuid, ref IntPtr deviceNotificationHandle) 00782 { 00783 DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE(); 00784 IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero; 00785 Int32 size = 0; 00786 00787 try 00788 { 00789 size = Marshal.SizeOf(devBroadcastDeviceInterface); 00790 devBroadcastDeviceInterface.dbcc_size = size; 00791 devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 00792 devBroadcastDeviceInterface.dbcc_reserved = 0; 00793 devBroadcastDeviceInterface.dbcc_classguid = classGuid; 00794 00795 // Allocate memory for the buffer that holds the DEV_BROADCAST_DEVICEINTERFACE structure. 00796 devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(size); 00797 00798 // Copy the DEV_BROADCAST_DEVICEINTERFACE structure to the buffer. 00799 // Set fDeleteOld True to prevent memory leaks. 00800 Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true); 00801 00802 // *** 00803 // API function 00804 00805 // summary 00806 // Request to receive notification messages when a device in an interface class 00807 // is attached or removed. 00808 00809 // parameters 00810 // Handle to the window that will receive device events. 00811 // Pointer to a DEV_BROADCAST_DEVICEINTERFACE to specify the type of 00812 // device to send notifications for. 00813 // DEVICE_NOTIFY_WINDOW_HANDLE indicates the handle is a window handle. 00814 00815 // Returns 00816 // Device notification handle or NULL on failure. 00817 // *** 00818 00819 deviceNotificationHandle = RegisterDeviceNotification(formHandle, devBroadcastDeviceInterfaceBuffer, DEVICE_NOTIFY_WINDOW_HANDLE); 00820 00821 // Marshal data from the unmanaged block devBroadcastDeviceInterfaceBuffer to the managed object devBroadcastDeviceInterface 00822 // why? 00823 Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface); 00824 00825 return deviceNotificationHandle.ToInt32() == IntPtr.Zero.ToInt32() ? false : true; 00826 } 00827 catch (Exception ex) 00828 { 00829 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00830 } 00831 finally 00832 { 00833 // Free the memory allocated previously by AllocHGlobal. 00834 if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero) 00835 Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer); 00836 } 00837 } 00838 00839 00840 00841 public Boolean DeviceIDMatch(Message m) 00842 { 00843 Int32 stringSize; 00844 00845 try 00846 { 00847 DEV_BROADCAST_HDR devBroadcastHeader = new DEV_BROADCAST_HDR(); 00848 DEV_BROADCAST_DEVICEINTERFACE_1 devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE_1(); 00849 00850 // The LParam parameter of Message is a pointer to a DEV_BROADCAST_HDR structure. 00851 Marshal.PtrToStructure(m.LParam, devBroadcastHeader); 00852 if ((devBroadcastHeader.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)) 00853 { 00854 // The dbch_devicetype parameter indicates that the event applies to a device interface. 00855 // So the structure in LParam is actually a DEV_BROADCAST_INTERFACE structure, 00856 // which begins with a DEV_BROADCAST_HDR. 00857 00858 // Obtain the number of characters in dbch_name by subtracting the 32 bytes 00859 // in the strucutre that are not part of dbch_name and dividing by 2 because there are 00860 // 2 bytes per character. 00861 00862 stringSize = System.Convert.ToInt32((devBroadcastHeader.dbch_size - 32) / 2); 00863 00864 // The dbcc_name parameter of devBroadcastDeviceInterface contains the device name. 00865 // Trim dbcc_name to match the size of the String. 00866 00867 devBroadcastDeviceInterface.dbcc_name = new Char[stringSize + 1]; 00868 00869 // Marshal data from the unmanaged block pointed to by m.LParam 00870 // to the managed object devBroadcastDeviceInterface. 00871 00872 Marshal.PtrToStructure(m.LParam, devBroadcastDeviceInterface); 00873 00874 // Store the device name in a String. 00875 00876 String DeviceNameString = new String(devBroadcastDeviceInterface.dbcc_name, 0, stringSize); 00877 00878 // Compare the name of the newly attached device with the name of the device 00879 // the application is accessing (deviceID). 00880 // Set ignorecase True. 00881 00882 return (DeviceNameString.ToLower().IndexOf(deviceID.ToLower()) == -1) ? false : true; 00883 } 00884 else 00885 return false; 00886 } 00887 catch (Exception ex) 00888 { 00889 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00890 } 00891 } 00892 #endregion 00893 00894 #region Send/Receive HID reports 00895 00896 public void FlushQueue() 00897 { 00898 try 00899 { 00900 if (writeHandle == null) 00901 { 00902 return; 00903 } 00904 if (readHandle == null) 00905 { 00906 return; 00907 } 00908 00909 HidD_FlushQueue(writeHandle); 00910 HidD_FlushQueue(readHandle); 00911 } 00912 catch 00913 { 00914 throw new Exception(new System.Diagnostics.StackFrame().GetMethod().Name); 00915 } 00916 } 00917 00918 public void writeReadHID() 00919 { 00920 try 00921 { 00922 if (writeHandle == null) 00923 { 00924 return; 00925 } 00926 if (readHandle == null) 00927 { 00928 return; 00929 } 00930 00931 writeHID(); 00932 readHID(); 00933 } 00934 catch (Exception ex) 00935 { 00936 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 00937 } 00938 } 00939 00940 public void writeHID() 00941 { 00942 if (writeHandle == null) 00943 { 00944 return; 00945 } 00946 if (readHandle == null) 00947 { 00948 return; 00949 } 00950 00951 int BytesSucceed; 00952 bool api_status; 00953 00954 try 00955 { 00956 BytesSucceed = 0; 00957 //Byte[] outputReportBuffer = new Byte[REPORT_SIZE]; 00958 00959 //for (int i = 0; i < REPORT_SIZE; i++) 00960 // outputReportBuffer[i] = IOBuf[i]; 00961 //api_status = FileIO.WriteFile(writeHandle, outputReportBuffer, outputReportBuffer.Length, ref BytesSucceed, IntPtr.Zero); 00962 00963 Marshal.Copy(IOBuf, 0, nonManagedBuffer, REPORT_SIZE); 00964 api_status = FileIO.WriteFile(writeHandle, nonManagedBuffer, REPORT_SIZE, ref BytesSucceed, IntPtr.Zero); 00965 00966 //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 00967 00968 if (api_status == false) 00969 { 00970 //MessageBox.Show(Err.LastDllError); 00971 throw new Exception(support.ResultOfAPICall("API WriteFile error")); 00972 } 00973 } 00974 catch (Exception ex) 00975 { 00976 throw new Exception(ex.Message + new System.Diagnostics.StackFrame().GetMethod().Name); 00977 } 00978 } 00979 00980 public void readHID() 00981 { 00982 if (writeHandle == null) 00983 { 00984 return; 00985 } 00986 if (readHandle == null) 00987 { 00988 return; 00989 } 00990 00991 int BytesSucceed; 00992 bool api_status; 00993 int status; 00994 00995 try 00996 { 00997 Array.Clear(IOBuf, 0, IOBuf.Length); 00998 00999 BytesSucceed = 0; 01000 01001 api_status = FileIO.ReadFile(readHandle, nonManagedBuffer, REPORT_SIZE, ref BytesSucceed, nonManagedOverlapped); 01002 01003 if (api_status == false) 01004 { 01005 //MsgBox(Err.LastDllError) 01006 status = FileIO.WaitForSingleObject(EventObject, IOtimeout); 01007 01008 if (status != FileIO.WAIT_OBJECT_0) 01009 { 01010 api_status = FileIO.CancelIo(readHandle); 01011 throw new Exception(support.ResultOfAPICall("API ReadFile error")); 01012 } 01013 FileIO.GetOverlappedResult(readHandle, nonManagedOverlapped, ref BytesSucceed, false); 01014 } 01015 01016 // 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()? 01017 if (BytesSucceed > IOBuf.Length) 01018 { 01019 IOBuf = new byte[BytesSucceed]; 01020 Array.Clear(IOBuf, 0, IOBuf.Length); 01021 } 01022 Marshal.Copy(nonManagedBuffer, IOBuf, 0, BytesSucceed); 01023 } 01024 catch (Exception ex) 01025 { 01026 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01027 } 01028 } 01029 01030 public void readHID2() // this function is for testing multiple report read on a single ReadFile() 01031 { 01032 if (writeHandle == null) 01033 { 01034 return; 01035 } 01036 if (readHandle == null) 01037 { 01038 return; 01039 } 01040 01041 int BytesSucceed; 01042 bool api_status; 01043 int status; 01044 01045 try 01046 { 01047 int size = 128; 01048 //byte[] buf = new byte[size]; 01049 IntPtr nonManagedBuf = Marshal.AllocHGlobal(size); 01050 //Array.Clear(buf, 0, size); 01051 01052 BytesSucceed = 0; 01053 01054 api_status = FileIO.ReadFile(readHandle, nonManagedBuf, size, ref BytesSucceed, nonManagedOverlapped); 01055 01056 if (api_status == false) 01057 { 01058 //MsgBox(Err.LastDllError) 01059 status = FileIO.WaitForSingleObject(EventObject, IOtimeout); 01060 01061 if (status != FileIO.WAIT_OBJECT_0) 01062 { 01063 api_status = FileIO.CancelIo(readHandle); 01064 throw new Exception(support.ResultOfAPICall("API ReadFile error")); 01065 } 01066 FileIO.GetOverlappedResult(readHandle, nonManagedOverlapped, ref BytesSucceed, false); 01067 } 01068 01069 // 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()? 01070 if (BytesSucceed > IOBuf.Length) 01071 { 01072 IOBuf = new byte[BytesSucceed]; 01073 Array.Clear(IOBuf, 0, IOBuf.Length); 01074 } 01075 Marshal.Copy(nonManagedBuf, IOBuf, 0, BytesSucceed); 01076 01077 if (nonManagedBuf != IntPtr.Zero) 01078 Marshal.FreeHGlobal(nonManagedBuffer); 01079 } 01080 catch (Exception ex) 01081 { 01082 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01083 } 01084 } 01085 #endregion 01086 01087 #region Close HID 01088 public void closeHIDhandles() 01089 { 01090 try 01091 { 01092 if (desiredHIDPathNameArray.Count != 0) 01093 { 01094 foreach (Object obj in writeHandleArray) 01095 ((SafeFileHandle)obj).Close(); 01096 writeHandleArray.Clear(); 01097 writeHandle = null; 01098 foreach (Object obj in readHandleArray) 01099 ((SafeFileHandle)obj).Close(); 01100 readHandleArray.Clear(); 01101 readHandle = null; 01102 } 01103 } 01104 catch (Exception ex) 01105 { 01106 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01107 } 01108 } 01109 /// <summary> 01110 /// Requests to stop receiving notification messages when a device in an 01111 /// interface class is attached or removed. 01112 /// </summary> 01113 /// 01114 /// <param name="deviceNotificationHandle"> handle returned previously by 01115 /// RegisterDeviceNotification. </param> 01116 01117 public void StopReceivingDeviceNotifications(IntPtr deviceNotificationHandle) 01118 { 01119 try 01120 { 01121 UnregisterDeviceNotification(deviceNotificationHandle); 01122 } 01123 catch (Exception ex) 01124 { 01125 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01126 } 01127 } 01128 public void freeHeap() 01129 { 01130 try 01131 { 01132 if (nonManagedBuffer != IntPtr.Zero) 01133 Marshal.FreeHGlobal(nonManagedBuffer); 01134 if (nonManagedOverlapped != IntPtr.Zero) 01135 Marshal.FreeHGlobal(nonManagedOverlapped); 01136 } 01137 catch (Exception ex) 01138 { 01139 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01140 } 01141 } 01142 #endregion 01143 01144 #region Create Report 01145 public void reportID() 01146 { 01147 try 01148 { 01149 if (explicit_report_id) 01150 IOBuf[0] = SHORT_REPORT_ID; // explicit out report ID in HID's descriptor 01151 else 01152 IOBuf[0] = DEFAULT_REPORT_ID; // default report ID; this byte is dropped in transfer, so we don't really waste a byte transmitting it 01153 } 01154 catch (Exception ex) 01155 { 01156 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01157 } 01158 } 01159 01160 #region I2C Commands 01161 01162 #region oldCommands 01163 /*public int readI2C(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] readData, byte[] reg, bool ignoreNACK = false) 01164 { 01165 //readData is passed back to caller with the read data 01166 int status; 01167 int i; 01168 01169 try 01170 { 01171 if (numDataBytes > REPORT_SIZE - 2) { 01172 throw new Exception("USB buffer overflow"); 01173 } 01174 01175 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in readI2C 01176 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01177 FlushQueue(); 01178 Array.Clear(IOBuf, 0, IOBuf.Length); 01179 01180 reportID(); 01181 IOBuf[1] = I2C_TRANSACTION; // I2C transaction -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01182 IOBuf[2] = (byte)(deviceAddress | 1); // set read bit 01183 IOBuf[3] = numDataBytes; 01184 IOBuf[4] = numRegBytes; 01185 // TODO1: OS24EVK-57 HID readI2C no validation that numRegBytes == reg.Length ? 01186 for (i = 0; i < numRegBytes; i++) { 01187 IOBuf[i + 5] = reg[i]; 01188 } 01189 01190 writeHID(); 01191 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01192 01193 status = checkNACK(); 01194 01195 // checkNACK also reads the data, assuming NACK didn't occur 01196 if (status == I2C_NACK_ERROR && ignoreNACK == false) { 01197 throw new Exception("invalid I2C address"); 01198 } 01199 01200 for (i = 0; i < numDataBytes; i++) { 01201 readData[i] = IOBuf[i + 2]; 01202 } 01203 01204 return status; // the caller will not need the return value if an exception is thrown 01205 } 01206 catch (Exception ex) 01207 { 01208 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01209 } 01210 }*/ 01211 01212 /*public void writeI2C(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] data, byte[] reg, bool ignoreNACK = false) 01213 { 01214 int i; 01215 01216 try 01217 { 01218 if (numDataBytes > REPORT_SIZE - 5) { 01219 throw new Exception("USB buffer overflow"); 01220 } 01221 01222 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in writeI2C 01223 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01224 FlushQueue(); 01225 Array.Clear(IOBuf, 0, IOBuf.Length); 01226 01227 //send data to tell uC to do I2C read from slave 01228 reportID(); 01229 IOBuf[1] = I2C_TRANSACTION; // I2C transaction -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01230 IOBuf[2] = deviceAddress; 01231 IOBuf[3] = numDataBytes; 01232 IOBuf[4] = numRegBytes; 01233 for (i = 0; i < numRegBytes; i++) { 01234 IOBuf[i + 5] = reg[i]; 01235 } 01236 for (i = 0; i < numDataBytes; i++) { 01237 IOBuf[i + 5 + numRegBytes] = data[i]; 01238 } 01239 01240 writeHID(); 01241 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01242 01243 if (checkNACK() == I2C_NACK_ERROR && ignoreNACK == false) { 01244 throw new Exception("invalid I2C address"); 01245 } 01246 } 01247 catch (Exception ex) 01248 { 01249 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01250 } 01251 } 01252 01253 private int checkNACK() 01254 { 01255 // Check if I2C write was really succesful or a NACK occurred, since this is independent of USB success 01256 // This function also reads all the data from the report. If NACK occured, the data is invalid. 01257 try 01258 { 01259 readHID(); 01260 return (IOBuf[1] == 0 ? I2C_SUCCESS : I2C_NACK_ERROR); // the caller will not need the return value if an exception is thrown 01261 } 01262 catch (Exception ex) 01263 { 01264 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01265 } 01266 }*/ 01267 01268 // only allows 2 byte data 01269 /*public void setBitI2C(byte deviceAddress, int reg, byte range, int data, bool ignoreNACK = false) 01270 { 01271 int i; 01272 01273 try 01274 { 01275 int LSb = range & 0xF; 01276 int MSb = (range & 0xF0) >> 4; 01277 if (MSb < LSb) 01278 throw new Exception("invalid bit range"); 01279 //if (numDataBytes > REPORT_SIZE - 5) 01280 // throw new Exception("USB buffer overflow"); 01281 01282 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in setBitI2C 01283 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01284 FlushQueue(); 01285 01286 Array.Clear(IOBuf, 0, IOBuf.Length); 01287 01288 //send data to tell uC to do I2C read from slave 01289 reportID(); 01290 IOBuf[1] = I2C_TRANSACTION; // I2C transaction -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01291 IOBuf[2] = deviceAddress; 01292 byte numDataBytes = (byte)(MSb > 7 ? 2 : 1); 01293 IOBuf[3] = numDataBytes; 01294 byte numRegBytes = (byte)Math.Ceiling(reg / 255.0); 01295 IOBuf[4] = numRegBytes; 01296 for (i = 0; i < numRegBytes; i++) 01297 IOBuf[i + 5] = (byte)((reg>>(8*i)) & 0xFF); 01298 //for (i = 0; i < numDataBytes; i++) 01299 // IOBuf[i + 5 + numRegBytes] = data[i]; 01300 01301 writeHID(); 01302 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01303 01304 if (checkNACK() == I2C_NACK_ERROR && ignoreNACK == false) 01305 throw new Exception("invalid I2C address"); 01306 } 01307 catch (Exception ex) 01308 { 01309 throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name); 01310 } 01311 }*/ 01312 01313 01314 /// <summary> 01315 /// <para>Firmware command code 4 OUT = I2C configuration </para> 01316 /// (IO_BUFFER.Ptr[3+gOffset] & 1) ? (SMB0CF |= 0x10) : (SMB0CF &= 0xEF) 01317 /// </summary> 01318 /// <param name="gI2Cflags">bit0 == 1: repeated start</param> 01319 /// <param name="EXTHOLD">set EXTHOLD bit (SMBus setup / hold time extension)</param> 01320 /// <param name="ClearSDAbyTogglingSCL">clear SDA by toggling SCL</param> 01321 /* public void I2CConfigSet(byte gI2Cflags, byte EXTHOLD, byte ClearSDAbyTogglingSCL) 01322 { 01323 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CConfigSet(byte gI2Cflags, byte EXTHOLD, byte ClearSDAbyTogglingSCL) 01324 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CConfigSet 01325 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01326 FlushQueue(); 01327 Array.Clear(IOBuf, 0, IOBuf.Length); 01328 reportID(); 01329 IOBuf[1] = 4; // case (4): //I2C configuration -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01330 IOBuf[2] = 0; // case (0): // write 01331 IOBuf[3] = gI2Cflags; // gI2Cflags = IO_BUFFER.Ptr[2+gOffset]; 01332 // // bit0 == 1: repeated start (versus stop/start) after write before read (applies to random read only) 01333 // // bit1 == 1: start random read with a write, but end the write right away without sending reg address (emulate Jungo dongle for debug purposes) 01334 // // bit2 == 1: repeat transaction if slave NACKs (suggest not to use this) 01335 // // all flags are OR'd 01336 IOBuf[4] = EXTHOLD; // (IO_BUFFER.Ptr[3+gOffset] & 1) ? (SMB0CF |= 0x10) : (SMB0CF &= 0xEF); // set EXTHOLD bit (SMBus setup / hold time extension) 01337 IOBuf[5] = ClearSDAbyTogglingSCL; // if (IO_BUFFER.Ptr[4+gOffset] & 1) // clear SDA by toggling SCL 01338 // {s 01339 // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; 01340 // IO_BUFFER.Ptr[0+gOffset] = 0; // transaction error status 01341 // IO_BUFFER.Ptr[1+gOffset] = clearSDA(); // clearSDA error status 01342 // SendPacket(); // send status of clearing SDA to host 01343 // } 01344 writeHID(); 01345 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01346 }*/ 01347 01348 /// <summary> 01349 /// <para>Firmware command code 4 IN = I2C configuration </para> 01350 /// (IO_BUFFER.Ptr[3+gOffset] & 1) ? (SMB0CF |= 0x10) : (SMB0CF &= 0xEF) 01351 /// </summary> 01352 /// <param name="gI2Cflags">bit0 == 1: repeated start</param> 01353 /// <param name="EXTHOLD">SMB0CF & 0x10</param> 01354 /* public void I2CConfigGet(out byte gI2Cflags, out byte EXTHOLD) 01355 { 01356 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CConfigGet(out byte gI2Cflags, out byte EXTHOLD) 01357 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CConfigGet 01358 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01359 FlushQueue(); 01360 Array.Clear(IOBuf, 0, IOBuf.Length); 01361 reportID(); 01362 IOBuf[1] = 4; // case (4): //I2C configuration -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01363 IOBuf[2] = 1; // case (1): // read 01364 writeReadHID(); 01365 // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; 01366 // IO_BUFFER.Ptr[0+gOffset] = 0; // error status 01367 // IO_BUFFER.Ptr[1+gOffset] = gI2Cflags; 01368 // IO_BUFFER.Ptr[2+gOffset] = (SMB0CF & 0x10) >> 4; // EXTHOLD 01369 gI2Cflags = IOBuf[2]; 01370 EXTHOLD = IOBuf[3]; 01371 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01372 }*/ 01373 01374 /// <summary> 01375 /// <para>Firmware command code 5 OUT = I2C clock rate (number of counts to overflow) </para> 01376 /// <para>SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</para> 01377 /// </summary> 01378 /// <param name="ReloadTH1">SMBus timer's count value: ReloadTH1 = (byte)(0.5 + (TimerClockMHz * 1000 / SCL_kHz))</param> 01379 /* public void I2CClockSet(byte ReloadTH1) 01380 { 01381 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CClockSet(byte ReloadTH1) 01382 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CClockSet 01383 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01384 FlushQueue(); 01385 Array.Clear(IOBuf, 0, IOBuf.Length); 01386 reportID(); 01387 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) 01388 IOBuf[2] = 0; // case (0): // write 01389 IOBuf[3] = ReloadTH1; 01390 // 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 01391 // TR1 = 0; 01392 // Timer1_Init(); 01393 writeHID(); 01394 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01395 }*/ 01396 01397 /// <summary> 01398 /// <para>Firmware command code 5 IN = I2C clock rate (number of counts to overflow) </para> 01399 /// <para>SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</para> 01400 /// </summary> 01401 /// <param name="TimerClockMHz">SMBus timer's clock frequency (in MHz); expect constant 8</param> 01402 /// <param name="ReloadTH1">SMBus timer's count value: SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</param> 01403 /*public void I2CClockGet(out byte TimerClockMHz, out byte ReloadTH1) 01404 { 01405 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CClockGet(out byte TimerClockMHz, out byte ReloadTH1) 01406 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CClockGet 01407 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01408 FlushQueue(); 01409 Array.Clear(IOBuf, 0, IOBuf.Length); 01410 reportID(); 01411 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) 01412 IOBuf[2] = 1; // case (1): // read 01413 writeReadHID(); 01414 // case (1): // read -- myHID.I2CClockGet(out TimerClockMHz, out ReloadTH1) 01415 // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; 01416 // IO_BUFFER.Ptr[0+gOffset] = 0; // error status 01417 // IO_BUFFER.Ptr[1+gOffset] = gTimer1ClkFreq / 1000000 / 3; //return the SMBus timer's clock frequency (in MHz) 01418 // 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 01419 // SendPacket(); // no need to check for internal call since only the GUI will request a read through this function 01420 // break; 01421 TimerClockMHz = IOBuf[2]; 01422 ReloadTH1 = IOBuf[3]; 01423 // todo: OS24EVK-24 how determine SCL from TimerClockMHZ? Observed I2CClockGet() TimerClockMHz = 8 when SCL = 400kHz. 01424 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01425 }*/ 01426 01427 /// <summary> 01428 /// <para>Firmware command code 6 OUT = I2C transaction </para> 01429 /// 01430 /// </summary> 01431 /// <param name="deviceAddress">I2C device address, 8-bit left-justified (LSB=R/w bit)</param> 01432 /// <param name="numDataBytes">I2C burst write register data count, in bytes</param> 01433 /// <param name="numRegBytes">I2C device register address length, normally 1 byte. Can be 0 for SMBusQuick protocol.</param> 01434 /// <param name="data">byte array containing the register data to transmit</param> 01435 /// <param name="reg">byte array containing the device register address</param> 01436 /// <param name="ignoreNACK"></param> 01437 /*public void I2CWrite(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] data, byte[] reg, bool ignoreNACK = false) 01438 { 01439 // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers 01440 // alias of existing function 01441 // 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) 01442 writeI2C(deviceAddress, numDataBytes, numRegBytes, data, reg, ignoreNACK); 01443 }*/ 01444 01445 /// <summary> 01446 /// <para>Firmware command code 6 IN = I2C transaction </para> 01447 /// 01448 /// </summary> 01449 /// <param name="deviceAddress">I2C device address, 8-bit left-justified (LSB=R/w bit)</param> 01450 /// <param name="numDataBytes">I2C burst read register data count, in bytes</param> 01451 /// <param name="numRegBytes">I2C device register address length, normally 1 byte. Can be 0 for SMBusQuick protocol.</param> 01452 /// <param name="readData">byte array which receives the register data</param> 01453 /// <param name="reg">byte array containing the device register address</param> 01454 /// <param name="ignoreNACK"></param> 01455 /// <returns>status value; may be HID.I2C_NACK_ERROR if ignoreNACK parameter is true</returns> 01456 /* public int I2CRead(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] readData, byte[] reg, bool ignoreNACK = false) 01457 { 01458 // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers 01459 // alias of existing function 01460 // 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) 01461 return readI2C(deviceAddress, numDataBytes, numRegBytes, readData, reg, ignoreNACK); 01462 }*/ 01463 01464 /*/// <summary> 01465 /// Search for a device attached to I2C bus, 01466 /// given a list of poossible device addresses, 01467 /// and a constant device ID register to test. 01468 /// </summary> 01469 /// <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> 01470 /// <param name="DeviceId_RegAddress">device register address of a constant "Device ID" register</param> 01471 /// <param name="DeviceId_RegValue_Expect">register value of the constant "Device ID" register</param> 01472 /// <returns>I2C device addresses, or 0 if not found</returns> 01473 public byte SearchI2CdeviceAddressList(byte[] I2C_DeviceAddressList_8bitLeftJustified, byte DeviceId_RegAddress, byte DeviceId_RegValue_Expect) 01474 { 01475 // https://jira.maxim-ic.com/browse/OS24EVK-57 accelerometer support: SearchI2CdeviceAddressList optional I2C device 01476 foreach (byte test_I2C_Address in I2C_DeviceAddressList_8bitLeftJustified) 01477 { 01478 //try 01479 //{ 01480 byte[] data = new byte[2]; 01481 byte[] reg = new byte[1]; 01482 reg[0] = (byte)DeviceId_RegAddress; 01483 // readI2C should already take care of mutex lock / unlock 01484 // https://jira.maxim-ic.com/browse/OS24EVK-59 avoid NACK exception in SearchI2CdeviceAddressList 01485 bool ignoreNACK = true; 01486 int status = readI2C(test_I2C_Address, 2, 1, data, reg, ignoreNACK); 01487 if (status == HID.I2C_NACK_ERROR) 01488 { 01489 continue; 01490 } 01491 else 01492 { 01493 byte DeviceId_RegValue_Actual = data[0]; 01494 if (DeviceId_RegValue_Actual == DeviceId_RegValue_Expect) 01495 { 01496 return test_I2C_Address; 01497 } 01498 } 01499 //} 01500 //catch (Exception) 01501 //{ 01502 // // myHID.readI2C can throw Exception("invalid I2C address"); 01503 //} 01504 } 01505 return 0; 01506 }*/ 01507 #endregion 01508 01509 public bool I2C_Initialize(byte index, byte clockSpeed) 01510 { 01511 bool success = false; 01512 01513 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01514 FlushQueue(); 01515 Array.Clear(IOBuf, 0, IOBuf.Length); 01516 01517 reportID(); 01518 IOBuf[1] = I2C_INIT; // command code -- see usb_app int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01519 IOBuf[2] = index; 01520 IOBuf[3] = clockSpeed; // 0 = 100KHz, 1 = 400KHz, 2 = 1MHz 01521 01522 writeReadHID(); 01523 01524 if (IOBuf[1] == COMMAND_SUCCESS) 01525 success = true; 01526 01527 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01528 01529 return success; 01530 } 01531 01532 public byte SearchI2CdeviceAddressList(byte index, byte[] I2C_DeviceAddressList_8bitLeftJustified, byte DeviceId_RegAddress, byte DeviceId_RegValue_Expect) 01533 { 01534 foreach (byte test_I2C_Address in I2C_DeviceAddressList_8bitLeftJustified) 01535 { 01536 byte[] data = new byte[2]; 01537 byte[] reg = new byte[1]; 01538 reg[0] = (byte)DeviceId_RegAddress; 01539 01540 bool success = I2C_Read(index, test_I2C_Address, 1, reg, 2, ref data); 01541 01542 if (success) 01543 { 01544 byte DeviceId_RegValue_Actual = data[0]; 01545 if (DeviceId_RegValue_Actual == DeviceId_RegValue_Expect) 01546 { 01547 return test_I2C_Address; 01548 } 01549 } 01550 } 01551 return 0; 01552 } 01553 01554 public bool I2C_Read(byte index, byte slaveAddress, byte num_cmd_bytes, byte[] cmd_data, byte num_data_bytes, ref byte[] data) 01555 { 01556 bool success = false; 01557 01558 if ((5 + num_cmd_bytes) > 63) 01559 return false; 01560 if ((1 + num_data_bytes) > 63) 01561 return false; 01562 01563 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01564 FlushQueue(); 01565 Array.Clear(IOBuf, 0, IOBuf.Length); 01566 01567 reportID(); 01568 IOBuf[1] = I2C_TRANSACTION; // command code -- see usb_app int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01569 IOBuf[2] = index; 01570 IOBuf[3] = (byte)(slaveAddress | 0x01); //LSB = 1 for read 01571 IOBuf[4] = num_cmd_bytes; 01572 01573 for (int i = 0; i < num_cmd_bytes; i++) 01574 IOBuf[5 + i] = cmd_data[i]; 01575 01576 IOBuf[5 + num_cmd_bytes] = num_data_bytes; 01577 01578 writeReadHID(); 01579 01580 if (IOBuf[1] == COMMAND_SUCCESS) 01581 success = true; 01582 01583 for (int i = 0; i < num_data_bytes; i++) 01584 data[i] = IOBuf[2 + i]; 01585 01586 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01587 01588 return success; 01589 } 01590 public bool I2C_Write(byte index, byte slaveAddress, byte num_cmd_bytes, byte[] cmd_data, byte num_data_bytes, byte[] data) 01591 { 01592 bool success = false; 01593 01594 if ((5 + num_cmd_bytes) > 63) 01595 return false; 01596 if ((1 + num_data_bytes) > 63) 01597 return false; 01598 01599 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01600 FlushQueue(); 01601 Array.Clear(IOBuf, 0, IOBuf.Length); 01602 01603 reportID(); 01604 IOBuf[1] = I2C_TRANSACTION; // command code -- see usb_app int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01605 IOBuf[2] = index; 01606 IOBuf[3] = (byte)(slaveAddress | 0x01); //LSB = 1 for read 01607 IOBuf[4] = num_cmd_bytes; 01608 01609 for (int i = 0; i < num_cmd_bytes; i++) 01610 IOBuf[5 + i] = cmd_data[i]; 01611 01612 IOBuf[5 + num_cmd_bytes] = num_data_bytes; 01613 01614 for (int i = 0; i < num_data_bytes; i++) 01615 IOBuf[6 + num_cmd_bytes + i] = data[i]; 01616 01617 writeReadHID(); 01618 01619 if (IOBuf[1] == COMMAND_SUCCESS) 01620 success = true; 01621 01622 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01623 01624 return success; 01625 } 01626 01627 public String RPC_Call(String str) { 01628 01629 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01630 FlushQueue(); 01631 Array.Clear(IOBuf, 0, IOBuf.Length); 01632 01633 reportID(); 01634 int i = 1; 01635 foreach (char ch in str) 01636 { 01637 IOBuf[i] = (byte)ch; 01638 i++; 01639 } 01640 01641 writeReadHID(); 01642 01643 StringBuilder sb = new StringBuilder(); 01644 for (i = 1; i < 64; i++) 01645 { 01646 if (IOBuf[i] == 13) break; 01647 sb.Append((char)IOBuf[i]); 01648 } 01649 01650 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01651 return sb.ToString(); 01652 } 01653 01654 #endregion 01655 01656 #region General Commmands 01657 /// <summary> 01658 /// <para>Firmware command code 0 IN = Firmware version</para> 01659 /// 01660 /// </summary> 01661 /// <param name="VerMajor"></param> 01662 /// <param name="VerMinor"></param> 01663 /// <param name="verYearHundreds"></param> 01664 /// <param name="verYear"></param> 01665 /// <param name="verMonth"></param> 01666 /// <param name="verDay"></param> 01667 public bool FirmwareVersion(out byte VerMajor, out byte VerMinor, out byte verYearHundreds, out byte verYear, out byte verMonth, out byte verDay) 01668 { 01669 bool success = false; 01670 01671 if (FirmwareINT0Enabled != 0) 01672 { 01673 // firmware is busy streaming out HID reports, 01674 // so return a previously retrieved firmware version. 01675 VerMajor = _VerMajor; 01676 VerMinor = _VerMinor; 01677 verYearHundreds = _verYearHundreds; 01678 verYear = _verYear; 01679 verMonth = _verMonth; 01680 verDay = _verDay; 01681 return true; 01682 } 01683 // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers 01684 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in FirmwareVersion 01685 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01686 FlushQueue(); 01687 Array.Clear(IOBuf, 0, IOBuf.Length); 01688 reportID(); 01689 IOBuf[1] = 0; // Firmware version -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01690 writeReadHID(); 01691 VerMajor = IOBuf[2]; 01692 VerMinor = IOBuf[3]; 01693 verYearHundreds = IOBuf[4]; 01694 verYear = IOBuf[5]; 01695 verMonth = IOBuf[6]; 01696 verDay = IOBuf[7]; 01697 01698 if (IOBuf[1] == COMMAND_SUCCESS) 01699 { 01700 success = true; 01701 01702 // save the recently read values 01703 _VerMajor = VerMajor; 01704 _VerMinor = VerMinor; 01705 _verYearHundreds = verYearHundreds; 01706 _verYear = verYear; 01707 _verMonth = verMonth; 01708 _verDay = verDay; 01709 } 01710 01711 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01712 01713 return success; 01714 } 01715 private byte _VerMajor = 0; 01716 private byte _VerMinor = 0; 01717 private byte _verYearHundreds = 0; 01718 private byte _verYear = 0; 01719 private byte _verMonth = 0; 01720 private byte _verDay = 0; 01721 /// <summary> 01722 /// <para>Firmware command code 1 </para> 01723 /// 01724 /// </summary> 01725 /// <param name="ON">ON = true: LED turns on</param> 01726 public bool LEDSet(bool ON) 01727 { 01728 bool success = false; 01729 01730 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01731 FlushQueue(); 01732 Array.Clear(IOBuf, 0, IOBuf.Length); 01733 reportID(); 01734 IOBuf[1] = 1; // command code -- see usb_app int parseHIDReport(uint8_t *data_from_host, unsigned int len) 01735 01736 if(ON) 01737 IOBuf[2] = 1; 01738 else 01739 IOBuf[2] = 0; 01740 01741 writeReadHID(); 01742 01743 if (IOBuf[1] == COMMAND_SUCCESS) 01744 success = true; 01745 01746 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01747 01748 return success; 01749 } 01750 #endregion 01751 01752 #region GPIO commands 01753 /// <summary> 01754 /// <para>Firmware command code 1 IN = GPIOP0Get read I/O pins P0.6, P0.7</para> 01755 /// 01756 /// </summary> 01757 /// <param name="xxxxxxP06P07"></param> 01758 public void GPIOP0Get(out byte xxxxxxP06P07) 01759 { 01760 // todo: verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers GPIOP0Get(out byte xxxxxxP06P07) 01761 // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: Rename LEDGet(out byte xxxxxxP06P07) to GPIOP0Get(out byte xxxxxxP06P07) 01762 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP0Get 01763 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01764 FlushQueue(); 01765 Array.Clear(IOBuf, 0, IOBuf.Length); 01766 reportID(); 01767 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) 01768 IOBuf[2] = 1; // case (1): // read 01769 writeReadHID(); 01770 // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; 01771 // IO_BUFFER.Ptr[0 + gOffset] = 0; // error status 01772 // IO_BUFFER.Ptr[1 + gOffset] = ((P0 & 0x80) >> 7) + ((P0 & 0x40) >> 5); 01773 xxxxxxP06P07 = IOBuf[2]; 01774 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01775 } 01776 01777 /// <summary> 01778 /// <para>Firmware command code 2 OUT = GPIO configuration (C51F321 P1 and P2) </para> 01779 /// 01780 /// </summary> 01781 /// <param name="P1MDOUT"></param> 01782 /// <param name="P2MDOUT"></param> 01783 /// <param name="weakPullupDisable"></param> 01784 public void GPIOP1P2ConfigSet(byte P1MDOUT, byte P2MDOUT, byte weakPullupDisable) 01785 { 01786 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers GPIOP1P2ConfigSet(byte P1MDOUT, byte P2MDOUT, byte weakPullupDisable) 01787 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP1P2ConfigSet 01788 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01789 FlushQueue(); 01790 Array.Clear(IOBuf, 0, IOBuf.Length); 01791 reportID(); 01792 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) 01793 IOBuf[2] = 0; // case (0): // write 01794 IOBuf[3] = P1MDOUT; // P1MDOUT = IO_BUFFER.Ptr[2+gOffset]; // P1 push-pull (1) or open-collector (0) 01795 IOBuf[4] = P2MDOUT; // P2MDOUT = IO_BUFFER.Ptr[3 + gOffset]; // P2 push-pull (1) or open-collector (0) 01796 IOBuf[5] = weakPullupDisable; // (IO_BUFFER.Ptr[4 + gOffset] & 1) ? (XBR1 |= 0x80) : (XBR1 &= 0x7F); // weak pull up disable (open collector only); 1 disabled, 0 enabled 01797 writeHID(); 01798 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01799 } 01800 01801 /// <summary> 01802 /// <para>Firmware command code 2 IN = GPIO configuration (C51F321 P1 and P2) </para> 01803 /// 01804 /// </summary> 01805 /// <param name="P1MDOUT"></param> 01806 /// <param name="P2MDOUT"></param> 01807 /// <param name="weakPullupDisable"></param> 01808 public void GPIOP1P2ConfigGet(out byte P1MDOUT, out byte P2MDOUT, out byte weakPullupDisable) 01809 { 01810 // 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) 01811 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP1P2ConfigGet 01812 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01813 FlushQueue(); 01814 Array.Clear(IOBuf, 0, IOBuf.Length); 01815 reportID(); 01816 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) 01817 IOBuf[2] = 1; // case (1): // read 01818 writeReadHID(); 01819 // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; 01820 // IO_BUFFER.Ptr[0 + gOffset] = 0; // error status 01821 // IO_BUFFER.Ptr[1 + gOffset] = P1MDOUT; // P1 push-pull (1) or open-collector (0) 01822 // IO_BUFFER.Ptr[2 + gOffset] = P2MDOUT; // P2 push-pull (1) or open-collector (0) 01823 // IO_BUFFER.Ptr[3 + gOffset] = (XBR1 & 0x80) >> 7; // weakPullupDisable 01824 P1MDOUT = IOBuf[2]; 01825 P2MDOUT = IOBuf[3]; 01826 weakPullupDisable = IOBuf[4]; 01827 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01828 } 01829 01830 /// <summary> 01831 /// <para>Firmware command code 3 OUT = GPIO value (C51F321 P1 and P2) </para> 01832 /// 01833 /// </summary> 01834 /// <param name="P1"></param> 01835 /// <param name="P2"></param> 01836 public void GPIOP1P2Out(byte P1, byte P2) 01837 { 01838 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers GPIOP1P2Out(byte P1, byte P2) 01839 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP1P2Out 01840 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01841 FlushQueue(); 01842 Array.Clear(IOBuf, 0, IOBuf.Length); 01843 reportID(); 01844 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) 01845 IOBuf[2] = 0; // case (0): // write 01846 IOBuf[3] = P1; // P1 = IO_BUFFER.Ptr[2 + gOffset]; // P1 HI (1) or LO (0); set P1==1 and P1MDOUT==1 for HI-Z 01847 IOBuf[4] = P2; // P2 = IO_BUFFER.Ptr[3 + gOffset]; // P2 HI (1) or LO (0); set P2==1 and P1MDOUT==2 for HI-Z 01848 writeHID(); 01849 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01850 } 01851 01852 /// <summary> 01853 /// <para>Firmware command code 3 IN = GPIO value (C51F321 P1 and P2) </para> 01854 /// 01855 /// </summary> 01856 /// <param name="P1"></param> 01857 /// <param name="P2"></param> 01858 public void GPIOP1P2In(out byte P1, out byte P2) 01859 { 01860 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers GPIOP1P2In(out byte P1, out byte P2) 01861 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in GPIOP1P2In 01862 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01863 FlushQueue(); 01864 Array.Clear(IOBuf, 0, IOBuf.Length); 01865 reportID(); 01866 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) 01867 IOBuf[2] = 1; // case (1): // read 01868 writeReadHID(); 01869 // temp = XBR1; 01870 // 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') 01871 // { 01872 // XBR1 &= 0x7F; 01873 // Timer0_Init(HALFMS); 01874 // T0_Wait(2); 01875 // } 01876 // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; 01877 // IO_BUFFER.Ptr[0+gOffset] = 0; // error status 01878 // IO_BUFFER.Ptr[1+gOffset] = P1; // P1 HI (1) or LO (0) 01879 // IO_BUFFER.Ptr[2+gOffset] = P2; // P2 HI (1) or LO (0) 01880 // XBR1 = temp; 01881 // SendPacket(); // no need to check for internal call since only the GUI will request a read through this function 01882 P1 = IOBuf[2]; 01883 P2 = IOBuf[3]; 01884 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01885 } 01886 #endregion 01887 01888 #region SPI Commands 01889 /* 01890 01891 /// <summary> 01892 /// <para>Firmware command code 5 OUT = I2C clock rate (number of counts to overflow) </para> 01893 /// <para>SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</para> 01894 /// </summary> 01895 /// <param name="ReloadTH1">SMBus timer's count value: ReloadTH1 = (byte)(0.5 + (TimerClockMHz * 1000 / SCL_kHz))</param> 01896 public void I2CClockSet(byte ReloadTH1) 01897 { 01898 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CClockSet(byte ReloadTH1) 01899 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CClockSet 01900 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01901 FlushQueue(); 01902 Array.Clear(IOBuf, 0, IOBuf.Length); 01903 reportID(); 01904 IOBuf[1] = 5; // case (5): //I2C clock rate (number of counts to overflow) -- see F3xx_USB0_ReportHandler.c void OUT_REPORT_HANDLER(int internalCall) 01905 IOBuf[2] = 0; // case (0): // write 01906 IOBuf[3] = ReloadTH1; 01907 // 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 01908 // TR1 = 0; 01909 // Timer1_Init(); 01910 writeHID(); 01911 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01912 } 01913 01914 /// <summary> 01915 /// <para>Firmware command code 5 IN = I2C clock rate (number of counts to overflow) </para> 01916 /// <para>SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</para> 01917 /// </summary> 01918 /// <param name="TimerClockMHz">SMBus timer's clock frequency (in MHz); expect constant 8</param> 01919 /// <param name="ReloadTH1">SMBus timer's count value: SCL_kHz = TimerClockMHz * 1000 / ReloadTH1</param> 01920 public void I2CClockGet(out byte TimerClockMHz, out byte ReloadTH1) 01921 { 01922 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers I2CClockGet(out byte TimerClockMHz, out byte ReloadTH1) 01923 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CClockGet 01924 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 01925 FlushQueue(); 01926 Array.Clear(IOBuf, 0, IOBuf.Length); 01927 reportID(); 01928 IOBuf[1] = 5; // case (5): //I2C clock rate (number of counts to overflow) -- see F3xx_USB0_ReportHandler.c void OUT_REPORT_HANDLER(int internalCall) 01929 IOBuf[2] = 1; // case (1): // read 01930 writeReadHID(); 01931 // case (1): // read -- myHID.I2CClockGet(out TimerClockMHz, out ReloadTH1) 01932 // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; 01933 // IO_BUFFER.Ptr[0+gOffset] = 0; // error status 01934 // IO_BUFFER.Ptr[1+gOffset] = gTimer1ClkFreq / 1000000 / 3; //return the SMBus timer's clock frequency (in MHz) 01935 // 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 01936 // SendPacket(); // no need to check for internal call since only the GUI will request a read through this function 01937 // break; 01938 TimerClockMHz = IOBuf[2]; 01939 ReloadTH1 = IOBuf[3]; 01940 // todo: OS24EVK-24 how determine SCL from TimerClockMHZ? Observed I2CClockGet() TimerClockMHz = 8 when SCL = 400kHz. 01941 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 01942 } 01943 01944 /// <summary> 01945 /// <para>Firmware command code 6 OUT = I2C transaction </para> 01946 /// 01947 /// </summary> 01948 /// <param name="deviceAddress">I2C device address, 8-bit left-justified (LSB=R/w bit)</param> 01949 /// <param name="numDataBytes">I2C burst write register data count, in bytes</param> 01950 /// <param name="numRegBytes">I2C device register address length, normally 1 byte. Can be 0 for SMBusQuick protocol.</param> 01951 /// <param name="data">byte array containing the register data to transmit</param> 01952 /// <param name="reg">byte array containing the device register address</param> 01953 /// <param name="ignoreNACK"></param> 01954 public void I2CWrite(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] data, byte[] reg, bool ignoreNACK = false) 01955 { 01956 // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers 01957 // alias of existing function 01958 // IOBuf[1] = 6; // case (6): // I2C transaction -- HID.cs void writeI2C() readI2C() -- see F3xx_USB0_ReportHandler.c void OUT_REPORT_HANDLER(int internalCall) 01959 writeI2C(deviceAddress, numDataBytes, numRegBytes, data, reg, ignoreNACK); 01960 } 01961 01962 /// <summary> 01963 /// <para>Firmware command code 6 IN = I2C transaction </para> 01964 /// 01965 /// </summary> 01966 /// <param name="deviceAddress">I2C device address, 8-bit left-justified (LSB=R/w bit)</param> 01967 /// <param name="numDataBytes">I2C burst read register data count, in bytes</param> 01968 /// <param name="numRegBytes">I2C device register address length, normally 1 byte. Can be 0 for SMBusQuick protocol.</param> 01969 /// <param name="readData">byte array which receives the register data</param> 01970 /// <param name="reg">byte array containing the device register address</param> 01971 /// <param name="ignoreNACK"></param> 01972 /// <returns>status value; may be HID.I2C_NACK_ERROR if ignoreNACK parameter is true</returns> 01973 public int I2CRead(byte deviceAddress, byte numDataBytes, byte numRegBytes, byte[] readData, byte[] reg, bool ignoreNACK = false) 01974 { 01975 // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers 01976 // alias of existing function 01977 // IOBuf[1] = 6; // case (6): // I2C transaction -- HID.cs void writeI2C() readI2C() -- see F3xx_USB0_ReportHandler.c void OUT_REPORT_HANDLER(int internalCall) 01978 return readI2C(deviceAddress, numDataBytes, numRegBytes, readData, reg, ignoreNACK); 01979 } 01980 */ 01981 /// <summary> 01982 /// <para>Firmware command code 7 OUT = SPI config </para> 01983 /// ((SPI0CFG & 0x30) >> 4) + (SPI0CN & 4) 01984 /// </summary> 01985 /// <param name="config"></param> 01986 public void SPIConfigSet(byte config) 01987 { 01988 // todo: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers SPIConfigSet(byte config) 01989 // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. 01990 // 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) 01991 } 01992 01993 /// <summary> 01994 /// <para>Firmware command code 7 IN = SPI config </para> 01995 /// ((SPI0CFG & 0x30) >> 4) + (SPI0CN & 4) 01996 /// </summary> 01997 /// <param name="config"></param> 01998 public void SPIConfigGet(out byte config) 01999 { 02000 // todo: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers SPIConfigGet(out byte config) 02001 // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. 02002 // 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) 02003 config = 0; 02004 } 02005 02006 /// <summary> 02007 /// <para>Firmware command code 8 OUT = SPI clock rate </para> 02008 /// </summary> 02009 /// <param name="SPI0CKR"></param> 02010 public void SPIClockSet(byte SPI0CKR) 02011 { 02012 // todo: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers SPIClockSet(byte SPI0CKR) 02013 // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. 02014 // IOBuf[1] = 8; // case (8): // SPI clock rate -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 02015 } 02016 02017 /// <summary> 02018 /// <para>Firmware command code 8 IN = SPI clock rate </para> 02019 /// </summary> 02020 /// <param name="SPI0CKR"></param> 02021 public void SPIClockGet(out byte SPI0CKR) 02022 { 02023 // todo: https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers SPIClockGet(out byte SPI0CKR) 02024 // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. 02025 // IOBuf[1] = 8; // case (8): // SPI clock rate -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 02026 SPI0CKR = 0; 02027 } 02028 02029 /// <summary> 02030 /// <para>Firmware command code 9 = SPI transaction </para> 02031 /// </summary> 02032 /// <param name="mosiData">SPI MOSI (Master-Out, Slave-In) data to write into slave device</param> 02033 /// <param name="misoBuffer">SPI MISO (Master-In, Slave-Out) data buffer containing data bytes received from slave device 02034 /// (size will be allocated same size as mosiData)</param> 02035 public void SPITransfer(byte[] mosiData, out byte[] misoBuffer) 02036 { 02037 // verify: https://jira.maxim-ic.com/browse/OS24EVK-24 SPITransfer(byte[] mosiData, out byte[] misoBuffer) 02038 // Although the MAX30101EVKIT firmware will accept HID SPI commands, this firmware doesn't support SPI interface. 02039 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in I2CConfigSet 02040 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 02041 FlushQueue(); 02042 Array.Clear(IOBuf, 0, IOBuf.Length); 02043 reportID(); 02044 // assign default out values in case of failure 02045 int byteCount = mosiData.Length; 02046 byte num_bytes = (byte)(byteCount & 0xFF); 02047 misoBuffer = new byte[byteCount]; 02048 for (int byteIndex = 0; byteIndex < byteCount; byteIndex++) 02049 { 02050 // initial dummy data 02051 misoBuffer[byteIndex] = 0x55; 02052 } 02053 IOBuf[1] = 9; // case (9): // SPI transaction -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 02054 //IOBuf[8] = x; // IO_BUFFER.Ptr[7+gOffset] -- first byte of data starts on the (7 + offset) byte 02055 for (uint byteIndex = 0; byteIndex < num_bytes; byteIndex++) 02056 { 02057 IOBuf[8 + byteIndex] = (byte)(mosiData[byteIndex]); 02058 } 02059 //switch (SPImode) 02060 //{ 02061 // case 0: 02062 IOBuf[2] = 0; // IO_BUFFER.Ptr[1+gOffset] -- 0 for SPI_mode0: multi-byte SPI transfer. 02063 IOBuf[3] = 0; // IO_BUFFER.Ptr[2+gOffset] -- not used 02064 IOBuf[4] = 0; // IO_BUFFER.Ptr[3+gOffset] -- phase_change // !=0 enable changing the clock phase. some slaves change phase between write/read 02065 IOBuf[5] = 0; // IO_BUFFER.Ptr[4+gOffset] -- phase_change_byte // byte index where phase change should happen 02066 IOBuf[6] = num_bytes; // IO_BUFFER.Ptr[5+gOffset] -- num_bytes 02067 IOBuf[7] = 0; // IO_BUFFER.Ptr[6+gOffset] -- not used 02068 // IO_BUFFER.Ptr[7+gOffset] -- first byte of data starts on the (7 + offset) byte 02069 // SPI_mode0(IO_BUFFER.Ptr[3 + gOffset], IO_BUFFER.Ptr[4 + gOffset], IO_BUFFER.Ptr[5 + gOffset], IO_BUFFER.Ptr); 02070 // break; 02071 //case 1: 02072 // 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 02073 // IOBuf[3] = 0; // IO_BUFFER.Ptr[2+gOffset] -- read flag 02074 // // IO_BUFFER.Ptr[3+gOffset] -- not used 02075 // // IO_BUFFER.Ptr[4+gOffset] -- not used 02076 // // IO_BUFFER.Ptr[5+gOffset] -- not used; num_bytes = 2 02077 // // IO_BUFFER.Ptr[6+gOffset] -- not used 02078 // // IO_BUFFER.Ptr[7+gOffset] -- first byte of data starts on the (7 + offset) byte 02079 // // SPI_mode1(temp, IO_BUFFER.Ptr); 02080 // break; 02081 //case 2: 02082 // 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 02083 // IOBuf[3] = 0; // IO_BUFFER.Ptr[2+gOffset] -- read flag 02084 // // IO_BUFFER.Ptr[3+gOffset] -- not used 02085 // // IO_BUFFER.Ptr[4+gOffset] -- not used 02086 // // IO_BUFFER.Ptr[5+gOffset] -- not used; num_bytes = 2 02087 // // IO_BUFFER.Ptr[6+gOffset] -- not used 02088 // // IO_BUFFER.Ptr[7+gOffset] -- first byte of data starts on the (7 + offset) byte 02089 // // SPI_mode2(temp, IO_BUFFER.Ptr); 02090 // break; 02091 //} 02092 writeHID(); 02093 // IO_BUFFER.Ptr[0] = SHORT_REPORT_ID; 02094 // IO_BUFFER.Ptr[0+gOffset] = 0; // error status 02095 // IO_BUFFER.Ptr[1+gOffset] = gI2Cflags; 02096 // IO_BUFFER.Ptr[2+gOffset] = (SMB0CF & 0x10) >> 4; // EXTHOLD 02097 //gI2Cflags = IOBuf[2]; 02098 //EXTHOLD = IOBuf[3]; 02099 for (uint byteIndex = 0; byteIndex < byteCount; byteIndex++) 02100 { 02101 misoBuffer[byteIndex] = IOBuf[byteIndex + 2]; 02102 } 02103 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 02104 } 02105 #endregion 02106 02107 #region Interrupt Commands 02108 /// <summary> 02109 /// <para>Firmware command code 23 OUT = enable INT0 (or Mock HID FIFO data diagnostic) </para> 02110 /// <para> 02111 /// - INT0Enable(0) disabled (EX0=0) 02112 /// - INT0Enable(1) real hardware (EX0=1) 02113 /// - INT0Enable(2) Mock HID x1 channel 101, 102, 103, ... 02114 /// - INT0Enable(3) Mock HID x2 channels 101, 201, 102, 202, 103, 203, ... 02115 /// - INT0Enable(4) Mock HID x3 channels 101, 201, 301, 102, 202, 302, 103, 203, 303, ... 02116 /// - INT0Enable(5) Mock HID x4 channels 101, 201, 301, 401, 102, 202, 302, 402, 103, 203, 303, 403, ... 02117 /// </para> 02118 /// </summary> 02119 /// <param name="EX0"></param> 02120 public void INT0Enable(byte EX0) 02121 { 02122 // https://jira.maxim-ic.com/browse/OS24EVK-24 Refactor: HID report enum and wrappers 02123 // reset report counter in the HID and enable INT0 02124 // verify: https://jira.maxim-ic.com/browse/OS24EVK-57 mutex lock HID.IOBuf[] in INT0Enable 02125 mutexGuardIOBuf.WaitOne(); // Wait until it is safe to enter. 02126 FlushQueue(); 02127 Array.Clear(IOBuf, 0, IOBuf.Length); 02128 reportID(); 02129 IOBuf[1] = 23; // enable INT0 -- see usb_app.c int parseHIDReport(uint8_t *data_from_host, unsigned int len) 02130 IOBuf[2] = EX0; // reportTypeFlag; // 1; 02131 writeHID(); 02132 _firmwareINT0Enabled = EX0; 02133 mutexGuardIOBuf.ReleaseMutex(); // Release the Mutex. 02134 } 02135 private byte _firmwareINT0Enabled = 0; 02136 public byte FirmwareINT0Enabled { get { return _firmwareINT0Enabled; } } 02137 #endregion 02138 02139 #endregion 02140 02141 02142 } 02143 }
Generated on Thu Jul 28 2022 18:07:15 by
1.7.2