Darien Figueroa / Mbed 2 deprecated repo3

Dependencies:   mbed MAX14720 MAX30205 USBDevice

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HID.cs Source File

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] &amp; 1) ? (SMB0CF |= 0x10) : (SMB0CF &amp;= 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] &amp; 1) ? (SMB0CF |= 0x10) : (SMB0CF &amp;= 0xEF)
01351         /// </summary>
01352         /// <param name="gI2Cflags">bit0 == 1: repeated start</param>
01353         /// <param name="EXTHOLD">SMB0CF &amp; 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 &amp; 0x30) &gt;&gt; 4) + (SPI0CN &amp; 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 &amp; 0x30) &gt;&gt; 4) + (SPI0CN &amp; 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 }