├── .gitignore
├── HidDemoWPF.PNG
├── HidDemoConsole.PNG
├── HidDemoWindowsForms.PNG
├── WindowsForms
├── app.config
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── app.manifest
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── HidDemoWindowsForms.csproj.user
├── Program.cs
├── HidDemoWindowsForms.csproj
├── Form1.resx
├── Form1.cs
└── Form1.Designer.cs
├── WPF
├── App.config
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── App.xaml
├── HidDemoWpf.csproj.user
├── MainWindow.xaml.cs
├── HidDemoWpf.csproj
├── MainWindow.xaml
└── App.xaml.cs
├── Console
├── App.config
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ └── AssemblyInfo.cs
├── HidDemoConsole.csproj.user
├── HidDemoConsole.csproj
└── Program.cs
├── HidUtilityDll
├── Properties
│ └── AssemblyInfo.cs
└── HidUtilityDll.csproj
├── HidUtilityNuget
├── HidUtilityNuget.csproj
└── hid.cs
├── HidUtilityDemo.sln
└── README.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | */bin/*
2 |
3 | */obj/*
4 | Backup/*
5 | .git/*
6 | .vs/*
7 | *.db
--------------------------------------------------------------------------------
/HidDemoWPF.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soldernerd/HID_Utility/HEAD/HidDemoWPF.PNG
--------------------------------------------------------------------------------
/HidDemoConsole.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soldernerd/HID_Utility/HEAD/HidDemoConsole.PNG
--------------------------------------------------------------------------------
/HidDemoWindowsForms.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/soldernerd/HID_Utility/HEAD/HidDemoWindowsForms.PNG
--------------------------------------------------------------------------------
/WindowsForms/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/WPF/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Console/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/WPF/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Console/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/WindowsForms/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/WPF/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/WPF/HidDemoWpf.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | publish\
5 |
6 |
7 |
8 |
9 |
10 | en-US
11 | false
12 |
13 |
--------------------------------------------------------------------------------
/Console/HidDemoConsole.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | publish\
5 |
6 |
7 |
8 |
9 |
10 | en-US
11 | false
12 |
13 |
--------------------------------------------------------------------------------
/WindowsForms/HidDemoWindowsForms.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | publish\
5 |
6 |
7 |
8 |
9 |
10 | en-US
11 | false
12 |
13 |
--------------------------------------------------------------------------------
/WindowsForms/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Forms;
4 |
5 | namespace HidDemoWindowsForms
6 | {
7 | static class Program
8 | {
9 | ///
10 | /// The main entry point for the application.
11 | ///
12 | [STAThread]
13 | static void Main()
14 | {
15 | Application.EnableVisualStyles();
16 | Application.SetCompatibleTextRenderingDefault(false);
17 | Application.Run(new Form1());
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/WPF/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace HidDemoWpf.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Console/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace HidDemoConsole.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/WindowsForms/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace HidDemoWindowsForms.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/WindowsForms/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HidDemoWindowsForms")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Soldernerd.com")]
12 | [assembly: AssemblyProduct("HidDemoWindowsForms")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("63f053db-de5b-4715-af73-ed2baaa1b5a8")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | [assembly: AssemblyVersion("1.0.0.0")]
32 | [assembly: AssemblyFileVersion("1.0.0.0")]
33 |
--------------------------------------------------------------------------------
/Console/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HidDemoConsole")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Soldernerd.com")]
12 | [assembly: AssemblyProduct("HidDemoConsole")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("42e80ef3-1acf-413e-9ac0-1d1daed560fa")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/HidUtilityDll/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HidUtilityDll")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Bank Vontobel AG")]
12 | [assembly: AssemblyProduct("HidUtilityDll")]
13 | [assembly: AssemblyCopyright("Copyright © Bank Vontobel AG 2017")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("2a94bc3c-369a-41b2-855e-3fcfca016c88")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HidUtilityNuget/HidUtilityNuget.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net46
5 | true
6 | Lukas Fässler
7 | soldernerd.com
8 | HidUtility
9 | A NuGet that allows a .NET application to communicate with a USB HID device in a simple and straight forward way without having to worry about all the COM objects and technical details. It's written in C# and mainly targets that language. It provides a main object, HidUtility, that one can use to subscribe to events such as when a package is received over USB or when a USB device is attached or detached.
10 | GNU GPLv3
11 | https://www.gnu.org/licenses/gpl-3.0.en.html
12 | https://soldernerd.com/2017/02/14/c-usb-hid-utility/
13 | https://github.com/soldernerd/HID_Utility
14 |
15 | Library
16 |
17 | Release
18 | AnyCPU;x86
19 | en
20 |
21 |
22 |
23 | true
24 | x86
25 |
26 |
27 |
28 | true
29 | x86
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/HidUtilityDemo.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26730.16
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HidDemoWindowsForms", "WindowsForms\HidDemoWindowsForms.csproj", "{16F6C5BD-2B6A-46A1-96E6-7BEB4E0AB5E7}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HidDemoWpf", "WPF\HidDemoWpf.csproj", "{4D03A54E-0AC7-4B7B-8BC2-33254C454980}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HidDemoConsole", "Console\HidDemoConsole.csproj", "{42E80EF3-1ACF-413E-9AC0-1D1DAED560FA}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HidUtilityNuget", "HidUtilityNuget\HidUtilityNuget.csproj", "{65306590-5C1D-4FCE-BC43-E58B6DD32B8E}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Release|x86 = Release|x86
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {16F6C5BD-2B6A-46A1-96E6-7BEB4E0AB5E7}.Release|x86.ActiveCfg = Release|x86
20 | {16F6C5BD-2B6A-46A1-96E6-7BEB4E0AB5E7}.Release|x86.Build.0 = Release|x86
21 | {4D03A54E-0AC7-4B7B-8BC2-33254C454980}.Release|x86.ActiveCfg = Release|x86
22 | {4D03A54E-0AC7-4B7B-8BC2-33254C454980}.Release|x86.Build.0 = Release|x86
23 | {42E80EF3-1ACF-413E-9AC0-1D1DAED560FA}.Release|x86.ActiveCfg = Release|x86
24 | {42E80EF3-1ACF-413E-9AC0-1D1DAED560FA}.Release|x86.Build.0 = Release|x86
25 | {65306590-5C1D-4FCE-BC43-E58B6DD32B8E}.Release|x86.ActiveCfg = Release|x86
26 | {65306590-5C1D-4FCE-BC43-E58B6DD32B8E}.Release|x86.Build.0 = Release|x86
27 | EndGlobalSection
28 | GlobalSection(SolutionProperties) = preSolution
29 | HideSolutionNode = FALSE
30 | EndGlobalSection
31 | GlobalSection(ExtensibilityGlobals) = postSolution
32 | SolutionGuid = {B38E5B7C-10A9-45B8-AE8E-ACFB11590AB9}
33 | EndGlobalSection
34 | EndGlobal
35 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | This open source (GNU GPLv3) project is aimed at simplifying the development of C# applications that communicate with USB HID (Human Interface Device) devices.
2 |
3 | There used to be a Microchip HID PnP Demo application that demonstrated how to connect to a HID device from C#.
4 | The demo is designed to work with their USB demo boards such as the "PIC18F46J50 FS USB Demo Board" (see http://www.microchip.com/Developmenttools/ProductDetails.aspx?PartNO=MA180024)
5 | However, that particular application was based on VisualStudio 2010 and .NET framework 2.0 and no longer gets maintained it seems.
6 |
7 | This VisualStudio solution was created on VisualStudio Community 2015 (which is free) and .NET framework 4.6. Please be aware that all projects must be compiled with "x86" setting even on a 64bit platform.
8 | There are 3 projects in this solution:
9 |
10 | - A WindowsForm application named HidDemoWindowsForms
11 | - A WPF application named HidDemoWpf
12 | - A Console application named HidDemoConsole
13 |
14 | All 3 projects offer very similar functionality. They connect to suitably programmed HID device, read an ADC value and pushbutton state and let you toggle an LED. They also list all available HID devices and notify you when a device is attached or detached.
15 |
16 | All the heavy lifting is done in a common file named hid.cs. It can be included in any C# project, no matter if it is based on WPF, WindowsForms or just a console application. It's full of DLL imports, Marshalling and COM API calls. In other words, it's not pretty and it doesn't look much like C# even though it is. You should not need to edit this file or know anything about it.
17 |
18 | hid.cs offers a nice, truely C# interface that lets you communicate to HID devices. Basically all you need to do is to create an instance of HidUtility and subscribe to the events you're interested in. The 3 applications should give you a good starting point.
19 |
20 | More information is available on https://soldernerd.com/2017/02/14/c-usb-hid-utility/
21 |
22 | Lukas Fässler
23 | soldernerd.com
24 | 2017-02-13
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/WPF/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 | using System.Runtime.InteropServices;
16 | using System.Windows.Interop;
17 | using System.Management;
18 | using System.Text.RegularExpressions;
19 |
20 | namespace HidDemoWpf
21 | {
22 |
23 | ///
24 | /// Interaction logic for MainWindow.xaml
25 | ///
26 | public partial class MainWindow : Window
27 | {
28 | public MainWindow()
29 | {
30 | InitializeComponent();
31 | }
32 |
33 | // Update when focus is lost
34 | public void FocusLostHandler(object sender, EventArgs e)
35 | {
36 | try
37 | {
38 | TextBox tb = (TextBox)sender;
39 | tb.GetBindingExpression(TextBox.TextProperty).UpdateSource();
40 | }
41 | catch
42 | {
43 | //nothin to do
44 | }
45 | }
46 |
47 | // Update if ENTER key has been pressed
48 | public void KeyUpHander(object sender, KeyEventArgs e)
49 | {
50 | try
51 | {
52 | TextBox tb = (TextBox)sender;
53 | if (e.Key == Key.Enter)
54 | {
55 | tb.GetBindingExpression(TextBox.TextProperty).UpdateSource();
56 | }
57 | }
58 | catch
59 | {
60 | //nothin to do
61 | }
62 | }
63 |
64 | //Scroll to bottom when text is changed
65 | public void ActivityLogTextChangedHandler(object sender, EventArgs e)
66 | {
67 | ActivityLogScrollViewer.ScrollToBottom();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/WindowsForms/Properties/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/WPF/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("HidUtilityDemo")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("Soldernerd.com")]
14 | [assembly: AssemblyProduct("HidUtilityDemo")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 |
18 | // Setting ComVisible to false makes the types in this assembly not visible
19 | // to COM components. If you need to access a type in this assembly from
20 | // COM, set the ComVisible attribute to true on that type.
21 | [assembly: ComVisible(false)]
22 |
23 | //In order to begin building localizable applications, set
24 | //CultureYouAreCodingWith in your .csproj file
25 | //inside a . For example, if you are using US english
26 | //in your source files, set the to en-US. Then uncomment
27 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
28 | //the line below to match the UICulture setting in the project file.
29 |
30 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
31 |
32 |
33 | [assembly: ThemeInfo(
34 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
35 | //(used if a resource is not found in the page,
36 | // or application resource dictionaries)
37 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
38 | //(used if a resource is not found in the page,
39 | // app, or any theme specific resource dictionaries)
40 | )]
41 |
42 |
43 | // Version information for an assembly consists of the following four values:
44 | //
45 | // Major Version
46 | // Minor Version
47 | // Build Number
48 | // Revision
49 | //
50 | // You can specify all the values or you can default the Build and Revision Numbers
51 | // by using the '*' as shown below:
52 | // [assembly: AssemblyVersion("1.0.*")]
53 | [assembly: AssemblyVersion("1.0.0.0")]
54 | [assembly: AssemblyFileVersion("1.0.0.0")]
55 |
--------------------------------------------------------------------------------
/HidUtilityDll/HidUtilityDll.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {2A94BC3C-369A-41B2-855E-3FCFCA016C88}
8 | Library
9 | Properties
10 | HidUtilityDll
11 | HidUtilityDll
12 | v4.6
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | x86
25 | true
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 | x86
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | hid.cs
53 |
54 |
55 |
56 |
57 |
64 |
--------------------------------------------------------------------------------
/WPF/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace HidDemoWpf.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HidDemoWpf.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/WindowsForms/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace HidDemoWindowsForms.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HidDemoWindowsForms.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Console/HidDemoConsole.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {42E80EF3-1ACF-413E-9AC0-1D1DAED560FA}
8 | Exe
9 | Properties
10 | HidDemoConsole
11 | HidDemoConsole
12 | v4.6
13 | 512
14 | true
15 |
16 |
17 |
18 |
19 |
20 |
21 | true
22 | bin\x86\Debug\
23 | DEBUG;TRACE
24 | true
25 | true
26 | full
27 | x86
28 | prompt
29 | MinimumRecommendedRules.ruleset
30 | true
31 |
32 |
33 | bin\x86\Release\
34 | TRACE
35 | true
36 | true
37 | pdbonly
38 | x86
39 | prompt
40 | MinimumRecommendedRules.ruleset
41 | true
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | hid.cs
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
67 |
--------------------------------------------------------------------------------
/WPF/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/WindowsForms/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/WPF/HidDemoWpf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {4D03A54E-0AC7-4B7B-8BC2-33254C454980}
8 | WinExe
9 | Properties
10 | HidDemoWpf
11 | HidDemoWpf
12 | v4.6
13 | 512
14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 4
16 | true
17 |
18 | publish\
19 | true
20 | Disk
21 | false
22 | Foreground
23 | 7
24 | Days
25 | false
26 | false
27 | true
28 | 0
29 | 1.0.0.%2a
30 | false
31 | false
32 | true
33 |
34 |
35 | true
36 | bin\x86\Debug\
37 | DEBUG;TRACE
38 | true
39 | full
40 | x86
41 | prompt
42 | MinimumRecommendedRules.ruleset
43 | true
44 |
45 |
46 | bin\x86\Release\
47 | TRACE
48 | true
49 | true
50 | pdbonly
51 | x86
52 | prompt
53 | MinimumRecommendedRules.ruleset
54 | true
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | 4.0
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | MSBuild:Compile
77 | Designer
78 |
79 |
80 | MSBuild:Compile
81 | Designer
82 |
83 |
84 | hid.cs
85 |
86 |
87 | App.xaml
88 | Code
89 |
90 |
91 | MainWindow.xaml
92 | Code
93 |
94 |
95 |
96 |
97 | Code
98 |
99 |
100 | True
101 | True
102 | Resources.resx
103 |
104 |
105 | True
106 | Settings.settings
107 | True
108 |
109 |
110 | ResXFileCodeGenerator
111 | Resources.Designer.cs
112 |
113 |
114 | SettingsSingleFileGenerator
115 | Settings.Designer.cs
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 | False
125 | Microsoft .NET Framework 4.6 %28x86 and x64%29
126 | true
127 |
128 |
129 | False
130 | .NET Framework 3.5 SP1
131 | false
132 |
133 |
134 |
135 |
142 |
--------------------------------------------------------------------------------
/WindowsForms/HidDemoWindowsForms.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.50727
7 | 2.0
8 | {16F6C5BD-2B6A-46A1-96E6-7BEB4E0AB5E7}
9 | WinExe
10 | Properties
11 | HidDemoWindowsForms
12 | HidDemoWindowsForms
13 | Custom
14 | false
15 |
16 |
17 | v4.6
18 |
19 |
20 |
21 |
22 | 2.0
23 | false
24 |
25 | publish\
26 | true
27 | Disk
28 | false
29 | Foreground
30 | 7
31 | Days
32 | false
33 | false
34 | true
35 | 0
36 | 1.0.0.%2a
37 | false
38 | true
39 |
40 |
41 | true
42 | full
43 | false
44 | bin\Debug\
45 | TRACE;DEBUG
46 | prompt
47 | 4
48 | true
49 | true
50 | 512
51 | false
52 |
53 |
54 | pdbonly
55 | true
56 | bin\Release\
57 | TRACE
58 | prompt
59 | 4
60 | true
61 | true
62 | 512
63 | false
64 |
65 |
66 | x86
67 | bin\x86\Debug\
68 | TRACE;DEBUG
69 | true
70 | false
71 |
72 |
73 | x86
74 | bin\x86\Release\
75 | true
76 | 512
77 | pdbonly
78 | true
79 | TRACE
80 | true
81 | true
82 | false
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | hid.cs
97 |
98 |
99 | Form
100 |
101 |
102 | Form1.cs
103 |
104 |
105 |
106 |
107 | Designer
108 | Form1.cs
109 |
110 |
111 | ResXFileCodeGenerator
112 | Resources.Designer.cs
113 | Designer
114 |
115 |
116 | True
117 | Resources.resx
118 | True
119 |
120 |
121 |
122 |
123 | SettingsSingleFileGenerator
124 | Settings.Designer.cs
125 |
126 |
127 | True
128 | Settings.settings
129 | True
130 |
131 |
132 |
133 |
134 | False
135 | .NET Framework 3.5 SP1
136 | true
137 |
138 |
139 |
140 |
147 |
--------------------------------------------------------------------------------
/WindowsForms/Form1.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | 134, 8
122 |
123 |
124 | 270, 9
125 |
126 |
127 | -694, 83
128 |
129 |
130 | -552, 83
131 |
132 |
133 | -384, 83
134 |
135 |
136 | -292, 83
137 |
138 |
139 | 60
140 |
141 |
--------------------------------------------------------------------------------
/WPF/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
72 |
75 |
76 |
77 |
80 |
83 |
86 |
89 |
90 |
91 |
94 |
97 |
98 |
99 |
102 |
106 |
107 |
108 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/Console/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Text.RegularExpressions;
6 | using System.Threading.Tasks;
7 | using HidUtilityNuget;
8 |
9 | namespace HidDemoConsole
10 | {
11 |
12 |
13 | class Program
14 | {
15 | [STAThread]
16 | static void Main(string[] args)
17 | {
18 | HidDemo demo = new HidDemo(0x04D8, 0x0054);
19 | demo.Run();
20 | }
21 | }
22 |
23 | public class HidDemo
24 | {
25 | private HidUtility HidUtil;
26 | private ushort Vid;
27 | private ushort Pid;
28 |
29 | private byte LastCommand = 0x81;
30 | private bool WaitingForDevice = false;
31 | private bool PushbuttonPressed = false;
32 | private bool ToggleLedPending = false;
33 | private uint AdcValue = 0;
34 | private DateTime ConnectedTimestamp = DateTime.Now;
35 | private uint TxCount = 0;
36 | private uint RxCount = 0;
37 |
38 | public HidDemo(ushort Vid, ushort Pid)
39 | {
40 | // Display startup message
41 | Console.WriteLine("Welcome to HID Console Demo");
42 |
43 | // Initialize class variables
44 | HidUtil = new HidUtility();
45 | this.Vid = Vid;
46 | this.Pid = Pid;
47 |
48 | // Set device to connect to
49 | HidUtil.SelectDevice(new Device(Vid, Pid));
50 |
51 | // Subscribe to events
52 | HidUtil.RaiseDeviceRemovedEvent += DeviceRemovedHandler;
53 | HidUtil.RaiseDeviceAddedEvent += DeviceAddedHandler;
54 | HidUtil.RaiseConnectionStatusChangedEvent += ConnectionStatusChangedHandler;
55 | HidUtil.RaiseSendPacketEvent += SendPacketHandler;
56 | HidUtil.RaisePacketSentEvent += PacketSentHandler;
57 | HidUtil.RaiseReceivePacketEvent += ReceivePacketHandler;
58 | HidUtil.RaisePacketReceivedEvent += PacketReceivedHandler;
59 |
60 | // Initialization is completed
61 | Console.WriteLine(string.Format(" Device: Vid=0x{0:X4}, Pid=0x{1:X4}", Vid, Pid));
62 | Console.WriteLine(string.Format(" Connection status: {0}", HidUtil.ConnectionStatus.ToString()));
63 |
64 | // Print available commands
65 | Console.WriteLine("Available Commands (all commands are case-insensitive):");
66 | Console.WriteLine(" v, vid : Change vendor ID");
67 | Console.WriteLine(" p, pid : Change product ID");
68 | Console.WriteLine(" d, devices: List available devices");
69 | Console.WriteLine(" s, status: Print status information");
70 | Console.WriteLine(" r, read: Read ADC value and pushbutton status");
71 | Console.WriteLine(" t, toggle: Toggle LED");
72 | Console.WriteLine(" q, quit: Exit the application");
73 | }
74 |
75 | // A USB device has been removed
76 | // Update the event log and device list
77 | void DeviceRemovedHandler(object sender, Device dev)
78 | {
79 | Console.WriteLine(string.Format("Device removed: {0}", dev.ToString()));
80 | }
81 |
82 | // A USB device has been added
83 | // Update the event log and device list
84 | void DeviceAddedHandler(object sender, Device dev)
85 | {
86 | Console.WriteLine(string.Format("Device added: {0}", dev.ToString()));
87 | }
88 |
89 | // Connection status of our selected device has changed
90 | // Reset variables
91 | void ConnectionStatusChangedHandler(object sender, HidUtility.ConnectionStatusEventArgs e)
92 | {
93 | Console.WriteLine(string.Format("Connection status changed to: {0}", e.ConnectionStatus.ToString()));
94 | LastCommand = 0x81;
95 | WaitingForDevice = false;
96 | PushbuttonPressed = false;
97 | ToggleLedPending = false;
98 | AdcValue = 0;
99 | ConnectedTimestamp = DateTime.Now;
100 | TxCount = 0;
101 | RxCount = 0;
102 | }
103 |
104 | // HidUtility asks if a packet should be sent to the device
105 | // Prepare the buffer and request a transfer
106 | public void SendPacketHandler(object sender, UsbBuffer OutBuffer)
107 | {
108 | // Fill entire buffer with 0xFF
109 | OutBuffer.clear();
110 | if (ToggleLedPending == true)
111 | {
112 | // The first byte is the "Report ID" and does not get sent over the USB bus. Always set = 0.
113 | OutBuffer.buffer[0] = 0;
114 | // 0x80 is the "Toggle LED" command in the firmware
115 | OutBuffer.buffer[1] = 0x80;
116 | ToggleLedPending = false;
117 | LastCommand = 0x80;
118 | }
119 | else if (LastCommand == 0x81)
120 | {
121 | // The first byte is the "Report ID" and does not get sent over the USB bus. Always set = 0.
122 | OutBuffer.buffer[0] = 0x00;
123 | // READ_POT command (see the firmware source code), gets 10-bit ADC Value
124 | OutBuffer.buffer[1] = 0x37;
125 | LastCommand = 0x37;
126 | }
127 | else
128 | {
129 | // The first byte is the "Report ID" and does not get sent over the USB bus. Always set = 0.
130 | OutBuffer.buffer[0] = 0x00;
131 | // 0x81 is the "Get Pushbutton State" command in the firmware
132 | OutBuffer.buffer[1] = 0x81;
133 | LastCommand = 0x81;
134 | }
135 | // Request that this buffer be sent
136 | OutBuffer.RequestTransfer = true;
137 | }
138 |
139 | // HidUtility informs us if the requested transfer was successful
140 | // Schedule to request a packet if the transfer was successful
141 | public void PacketSentHandler(object sender, UsbBuffer OutBuffer)
142 | {
143 | if (LastCommand == 0x80)
144 | {
145 | WaitingForDevice = false;
146 | }
147 | else
148 | {
149 | WaitingForDevice = OutBuffer.TransferSuccessful;
150 | }
151 | ++TxCount;
152 | }
153 |
154 | // HidUtility asks if a packet should be requested from the device
155 | // Request a packet if a packet has been successfully sent to the device before
156 | public void ReceivePacketHandler(object sender, UsbBuffer InBuffer)
157 | {
158 | InBuffer.RequestTransfer = WaitingForDevice;
159 |
160 | }
161 |
162 | // HidUtility informs us if the requested transfer was successful and provides us with the received packet
163 | public void PacketReceivedHandler(object sender, UsbBuffer InBuffer)
164 | {
165 | WaitingForDevice = false;
166 | if (InBuffer.buffer[1] == 0x37)
167 | {
168 | AdcValue = (uint)(InBuffer.buffer[3] << 8) + InBuffer.buffer[2];
169 | }
170 | if (InBuffer.buffer[1] == 0x81)
171 | {
172 | if (InBuffer.buffer[2] == 0x01)
173 | {
174 | PushbuttonPressed = false;
175 | }
176 | if (InBuffer.buffer[2] == 0x00)
177 | {
178 | PushbuttonPressed = true;
179 | }
180 | }
181 | ++RxCount;
182 | }
183 |
184 | public void Run()
185 | {
186 | while (true)
187 | {
188 | // Read command line input
189 | Console.Write(">> ");
190 | string consoleInput = Console.ReadLine();
191 | consoleInput = consoleInput.Trim();
192 | //Convert to lower case to ease future comparison
193 | consoleInput = consoleInput.ToLower();
194 | // Skip any blank commands
195 | if (string.IsNullOrWhiteSpace(consoleInput))
196 | {
197 | continue;
198 | }
199 | // Quit if command equals q or quit
200 | if(consoleInput=="q" || consoleInput=="quit")
201 | {
202 | break;
203 | }
204 | // Try to execute the command
205 | try
206 | {
207 | // Execute the command
208 | Execute(consoleInput);
209 | }
210 | catch (Exception ex)
211 | {
212 | // Something went wrong - Write out the problem
213 | Console.WriteLine(ex.Message);
214 | }
215 | }
216 | }
217 |
218 | private void Execute(string consoleInput)
219 | {
220 | //Divide console input into command and parameter(s) (if any)
221 | string[] input = consoleInput.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
222 | string command = input[0];
223 | List parameters = input.ToList();
224 | parameters.RemoveAt(0);
225 | // Decide what function to call
226 | switch(command)
227 | {
228 | case "v":
229 | case "vid":
230 | CommandVid(parameters);
231 | break;
232 | case "p":
233 | case "pid":
234 | CommandPid(parameters);
235 | break;
236 | case "d":
237 | case "devices":
238 | CommandDevices();
239 | break;
240 | case "s":
241 | case "status":
242 | CommandStatus();
243 | break;
244 | case "r":
245 | case "read":
246 | CommandRead();
247 | break;
248 | case "t":
249 | case "toggle":
250 | CommandToggle();
251 | break;
252 | default:
253 | Console.WriteLine("Invalid command");
254 | break;
255 | }
256 | }
257 |
258 | //Change Vendor ID
259 | private void CommandVid(List parameters)
260 | {
261 | ushort vid = ParseHex(parameters.ElementAt(0));
262 | if (vid != Vid)
263 | {
264 | Vid = vid;
265 | Console.WriteLine(string.Format("New device: Vid=0x{0:X4}, Pid=0x{1:X4}", Vid, Pid));
266 | HidUtil.SelectDevice(new Device(Vid, Pid));
267 | }
268 | else
269 | {
270 | Console.WriteLine("New VID matches current VID");
271 | }
272 | }
273 |
274 | //Change Product ID
275 | private void CommandPid(List parameters)
276 | {
277 | ushort pid = ParseHex(parameters.ElementAt(0));
278 | if(pid!=Pid)
279 | {
280 | Pid = pid;
281 | Console.WriteLine(string.Format("New device: Vid=0x{0:X4}, Pid=0x{1:X4}", Vid, Pid));
282 | HidUtil.SelectDevice(new Device(Vid, Pid));
283 | }
284 | else
285 | {
286 | Console.WriteLine("New PID matches current PID");
287 | }
288 | }
289 |
290 | //List available devices
291 | private void CommandDevices()
292 | {
293 | Console.WriteLine(string.Format("{0} devices available:", HidUtil.DeviceList.Count.ToString()));
294 | foreach(Device dev in HidUtil.DeviceList)
295 | {
296 | Console.WriteLine(dev.ToString());
297 | }
298 | }
299 |
300 | //Print current connection status
301 | private void CommandStatus()
302 | {
303 | Console.WriteLine(string.Format("Connection status: {0}", HidUtil.ConnectionStatus.ToString()));
304 | }
305 |
306 | //Read ADC value and
307 | private void CommandRead()
308 | {
309 | if (HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
310 | {
311 | if (PushbuttonPressed)
312 | {
313 | Console.WriteLine(string.Format("ADC value: {0}, pushbutton pressed", AdcValue.ToString()));
314 | }
315 | else
316 | {
317 | Console.WriteLine(string.Format("ADC value: {0}, pushbutton not pressed", AdcValue.ToString()));
318 | }
319 | }
320 | else
321 | {
322 | Console.WriteLine("Command not valid when not connected");
323 | }
324 | }
325 |
326 | //Toggle LED
327 | private void CommandToggle()
328 | {
329 | if (HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
330 | {
331 | if (ToggleLedPending)
332 | {
333 | Console.WriteLine("Operation already in progress");
334 | }
335 | else
336 | {
337 | ToggleLedPending = true;
338 | Console.WriteLine("LED toggle requested");
339 | }
340 | }
341 | else
342 | {
343 | Console.WriteLine("Command not valid when not connected");
344 | }
345 | }
346 |
347 | // Try to convert a (hexadecimal) string to an unsigned 16-bit integer
348 | // Return 0 if the conversion fails
349 | private ushort ParseHex(string input)
350 | {
351 | input = input.ToLower();
352 | if (input.Length >= 2)
353 | {
354 | if (input.Substring(0, 2) == "0x")
355 | {
356 | input = input.Substring(2);
357 | }
358 | }
359 | try
360 | {
361 | ushort value = ushort.Parse(input, System.Globalization.NumberStyles.HexNumber);
362 | return value;
363 | }
364 | catch
365 | {
366 | return 0;
367 | }
368 | }
369 | }
370 | }
--------------------------------------------------------------------------------
/WindowsForms/Form1.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Windows.Forms;
6 | using HidUtilityNuget;
7 |
8 | namespace HidDemoWindowsForms
9 | {
10 | public partial class Form1 : Form
11 | {
12 | // An instance of HidUtility that will do all the heavy lifting
13 | HidUtility HidUtil;
14 |
15 | // The device we are currently connected to
16 | Device ConnectedDevice = null;
17 |
18 |
19 | // Vendor and Product ID of the device we want to connect to
20 | ushort VID = 0x04D8;
21 | ushort PID = 0x0054;
22 |
23 | // Global variables used by the form / application
24 | byte LastCommand = 0x81;
25 | bool WaitingForDevice = false;
26 | bool PushbuttonPressed = false;
27 | bool ToggleLedPending = false;
28 | uint AdcValue = 0;
29 | DateTime ConnectedTimestamp = DateTime.Now;
30 | uint TxCount = 0;
31 | uint TxFailedCount = 0;
32 | uint RxCount = 0;
33 | uint RxFailedCount = 0;
34 |
35 | /*
36 | * Local function definitions
37 | */
38 |
39 | // Populate the device list
40 | // This function is called when the program is started and every time a device is connected or disconnected
41 | private void RefreshDeviceList()
42 | {
43 | string txt = "";
44 | foreach (Device dev in HidUtil.DeviceList)
45 | {
46 | string devString = string.Format("VID=0x{0:X4} PID=0x{1:X4}: {2} ({3})", dev.Vid, dev.Pid, dev.Caption, dev.Manufacturer);
47 | txt += devString + Environment.NewLine;
48 | }
49 | DevicesTextBox.Text = txt.TrimEnd('\n');
50 | }
51 |
52 | private void UpdateStatistics()
53 | {
54 | if(HidUtil.ConnectionStatus== HidUtility.UsbConnectionStatus.Connected)
55 | {
56 | //Save time elapsed since the device was connected
57 | TimeSpan uptime = DateTime.Now - ConnectedTimestamp;
58 | //Update uptime
59 | string tmp = string.Format("Uptime: {0}", uptime.ToString(@"hh\:mm\:ss\.f"));
60 | if (this.UptimeText.Text != tmp)
61 | {
62 | this.UptimeText.Text = tmp;
63 | }
64 | //Update TX statistics
65 | tmp = string.Format("Packets sent (failed): {0} ({1})", TxCount, TxFailedCount);
66 | if(TxCountText.Text!=tmp)
67 | {
68 | TxCountText.Text = tmp;
69 | }
70 | if (TxCount != 0)
71 | {
72 |
73 | tmp = string.Format("TX Speed: {0:0.00} packets per second", TxCount/uptime.TotalSeconds);
74 | if (TxSpeedText.Text != tmp)
75 | {
76 | TxSpeedText.Text = tmp;
77 | }
78 | }
79 | //Update RX statistics
80 | tmp = string.Format("Packets received (failed): {0} ({1})", RxCount, RxFailedCount);
81 | if (RxCountText.Text != tmp)
82 | {
83 | RxCountText.Text = tmp;
84 | }
85 | if (RxCount != 0)
86 | {
87 |
88 | tmp = string.Format("RX Speed: {0:0.00} packets per second", RxCount / uptime.TotalSeconds);
89 | if (RxSpeedText.Text != tmp)
90 | {
91 | RxSpeedText.Text = tmp;
92 | }
93 | }
94 | }
95 | else
96 | {
97 | UptimeText.Text = "Uptime: -";
98 | TxCountText.Text = "Packets sent (failed): -";
99 | TxSpeedText.Text = "Rx Speed: n/a";
100 | RxCountText.Text = "Packets received (failed): -";
101 | RxSpeedText.Text = "RX Speed: n/a";
102 | }
103 | }
104 |
105 | // Update Pushbutton status
106 | private void UpdatePushbutton()
107 | {
108 | string tmp;
109 | if (PushbuttonPressed)
110 | {
111 | tmp = "Pushbuttton State: Pressed";
112 | }
113 | else
114 | {
115 | tmp = "Pushbuttton State: Pressed";
116 | }
117 | // Only update if value has changed. Otherwise the text will flicker
118 | if (PushbuttonText.Text != tmp)
119 | {
120 | PushbuttonText.Text = tmp;
121 | }
122 | }
123 |
124 | //Update ADC bar
125 | private void UpdateAdcBar()
126 | {
127 | // Ui operations are relatively costly so only update if the value has changed
128 | if (AnalogBar.Value != (int)AdcValue)
129 | {
130 | AnalogBar.Value = (int)AdcValue;
131 | }
132 | }
133 |
134 | //Enable or disable controls
135 | private void SetUserInterfaceStatus(bool enabled)
136 | {
137 | this.ToggleLedButton.Enabled = enabled;
138 | this.AnalogLabel.Enabled = enabled;
139 | this.AnalogBar.Enabled = enabled;
140 | this.PushbuttonText.Enabled = enabled;
141 | this.TxCountText.Enabled = enabled;
142 | this.RxCountText.Enabled = enabled;
143 | this.UptimeText.Enabled = enabled;
144 | this.RxSpeedText.Enabled = enabled;
145 | this.TxSpeedText.Enabled = enabled;
146 | if(!enabled)
147 | {
148 | TxCount = 0;
149 | TxFailedCount = 0;
150 | RxCount = 0;
151 | RxFailedCount = 0;
152 | }
153 | }
154 |
155 | // Add a line to the activity log text box
156 | void WriteLog(string message, bool clear)
157 | {
158 | // Replace content
159 | if(clear)
160 | {
161 | LogTextBox.Text = string.Format("{0}: {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), message);
162 | }
163 | // Add new line
164 | else
165 | {
166 | LogTextBox.Text += Environment.NewLine + string.Format("{0}: {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), message);
167 | }
168 | // Scroll to bottom
169 | LogTextBox.SelectionStart = LogTextBox.Text.Length;
170 | LogTextBox.ScrollToCaret();
171 | }
172 |
173 | // Try to convert a (hexadecimal) string to an unsigned 16-bit integer
174 | // Return 0 if the conversion fails
175 | // This function is used to parse the PID and VID text boxes
176 | private ushort ParseHex(string input)
177 | {
178 | input = input.ToLower();
179 | if (input.Length >= 2)
180 | {
181 | if (input.Substring(0, 2) == "0x")
182 | {
183 | input = input.Substring(2);
184 | }
185 | }
186 | try
187 | {
188 | ushort value = ushort.Parse(input, System.Globalization.NumberStyles.HexNumber);
189 | return value;
190 | }
191 | catch
192 | {
193 | return 0;
194 | }
195 | }
196 |
197 |
198 | /*
199 | * Form callback functions
200 | */
201 |
202 | // Check if the ENTER key has been pressed inside the VID text box
203 | // Parse the string if that is the case
204 | private void VidTextBox_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
205 | {
206 | if (e.KeyCode == Keys.Enter)
207 | {
208 | VidTextBox_LostFocus(sender, e);
209 | }
210 | }
211 |
212 | // Parse the content of the VID text box when focus is lost
213 | private void VidTextBox_LostFocus(object sender, EventArgs e)
214 | {
215 | ushort vid = ParseHex(VidTextBox.Text);
216 | if (vid != VID)
217 | {
218 | // Save the new VID
219 | VID = vid;
220 | // Try to connect using the new PID
221 | WriteLog(string.Format("Attempt to connect with Vid=0x{0:X4}, Pid=0x{1:X4}", VID, PID), false);
222 | HidUtil.SelectDevice(new Device(VID, PID));
223 | }
224 | // Nicely format the string
225 | VidTextBox.Text = string.Format("0x{0:X4}", VID);
226 | }
227 |
228 | // Check if the ENTER key has been pressed inside the PID text box
229 | // Parse the string if that is the case
230 | private void PidTextBox_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
231 | {
232 | if (e.KeyCode == Keys.Enter)
233 | {
234 | PidTextBox_LostFocus(sender, e);
235 | }
236 | }
237 |
238 | // Parse the content of the PID text box when focus is lost
239 | private void PidTextBox_LostFocus(object sender, EventArgs e)
240 | {
241 | ushort pid = ParseHex(PidTextBox.Text);
242 | //Check if PID has changed
243 | if (pid != PID)
244 | {
245 | // Save the new PID
246 | PID = pid;
247 | // Try to connect using the new PID
248 | WriteLog(string.Format("Attempt to connect with Vid=0x{0:X4}, Pid=0x{1:X4}", VID, PID), false);
249 | HidUtil.SelectDevice(new Device(VID, PID));
250 | }
251 | // Nicely format the string
252 | PidTextBox.Text = string.Format("0x{0:X4}", pid);
253 | }
254 |
255 | // Schedule to toggle LED if the corresponding button has been clicked
256 | private void ToggleLedButton_Click(object sender, EventArgs e)
257 | {
258 | ToggleLedPending = true;
259 | }
260 |
261 |
262 | /*
263 | * HidUtility callback functions
264 | */
265 |
266 | // A USB device has been removed
267 | // Update the event log and device list
268 | void DeviceRemovedHandler(object sender, Device dev)
269 | {
270 | WriteLog("Device removed: " + dev.ToString(), false);
271 | RefreshDeviceList();
272 | }
273 |
274 | // A USB device has been added
275 | // Update the event log and device list
276 | void DeviceAddedHandler(object sender, Device dev)
277 | {
278 | WriteLog("Device added: " + dev.ToString(), false);
279 | RefreshDeviceList();
280 | }
281 |
282 | // Connection status of our selected device has changed
283 | // Update the user interface
284 | void ConnectionStatusChangedHandler(object sender, HidUtility.ConnectionStatusEventArgs e)
285 | {
286 | // Write log entry
287 | WriteLog("Connection status changed to: " + e.ToString(), false);
288 | // Update user interface
289 | switch (e.ConnectionStatus)
290 | {
291 | case HidUtility.UsbConnectionStatus.Connected:
292 | StatusText.Text = string.Format("Device Found (Connection status = {0})", e.ConnectionStatus.ToString());
293 | SetUserInterfaceStatus(true);
294 | ConnectedTimestamp = DateTime.Now;
295 | break;
296 | case HidUtility.UsbConnectionStatus.Disconnected:
297 | StatusText.Text = string.Format("Device Not Detected (Connection status = {0})", e.ConnectionStatus.ToString());
298 | AnalogBar.Value = 0;
299 | SetUserInterfaceStatus(false);
300 |
301 | break;
302 | case HidUtility.UsbConnectionStatus.NotWorking:
303 | StatusText.Text = string.Format("Device attached but not working (Connection status = {0})", e.ConnectionStatus.ToString());
304 | AnalogBar.Value = 0;
305 | SetUserInterfaceStatus(false);
306 | break;
307 | }
308 | UpdateStatistics();
309 | UpdatePushbutton();
310 | UpdateAdcBar();
311 | }
312 |
313 | // HidUtility asks if a packet should be sent to the device
314 | // Prepare the buffer and request a transfer
315 | public void SendPacketHandler(object sender, UsbBuffer OutBuffer)
316 | {
317 | // Fill entire buffer with 0xFF
318 | OutBuffer.clear();
319 | if (ToggleLedPending == true)
320 | {
321 | // The first byte is the "Report ID" and does not get sent over the USB bus. Always set = 0.
322 | OutBuffer.buffer[0] = 0;
323 | // 0x80 is the "Toggle LED" command in the firmware
324 | OutBuffer.buffer[1] = 0x80;
325 | ToggleLedPending = false;
326 | LastCommand = 0x80;
327 | }
328 | else if (LastCommand==0x81)
329 | {
330 | // The first byte is the "Report ID" and does not get sent over the USB bus. Always set = 0.
331 | OutBuffer.buffer[0] = 0x00;
332 | // READ_POT command (see the firmware source code), gets 10-bit ADC Value
333 | OutBuffer.buffer[1] = 0x37;
334 | LastCommand = 0x37;
335 | }
336 | else
337 | {
338 | // The first byte is the "Report ID" and does not get sent over the USB bus. Always set = 0.
339 | OutBuffer.buffer[0] = 0x00;
340 | // 0x81 is the "Get Pushbutton State" command in the firmware
341 | OutBuffer.buffer[1] = 0x81;
342 | LastCommand = 0x81;
343 | }
344 | // Request that this buffer be sent
345 | OutBuffer.RequestTransfer = true;
346 | }
347 |
348 | // HidUtility informs us if the requested transfer was successful
349 | // Schedule to request a packet if the transfer was successful
350 | public void PacketSentHandler(object sender, UsbBuffer OutBuffer)
351 | {
352 | if(LastCommand == 0x80)
353 | {
354 | WaitingForDevice = false;
355 | }
356 | else
357 | {
358 | WaitingForDevice = OutBuffer.TransferSuccessful;
359 | }
360 |
361 | if(OutBuffer.TransferSuccessful)
362 | {
363 | ++TxCount;
364 | }
365 | else
366 | {
367 | ++TxFailedCount;
368 | }
369 | }
370 |
371 | // HidUtility asks if a packet should be requested from the device
372 | // Request a packet if a packet has been successfully sent to the device before
373 | public void ReceivePacketHandler(object sender, UsbBuffer InBuffer)
374 | {
375 | InBuffer.RequestTransfer = WaitingForDevice;
376 | //WriteLog(string.Format("ReceivePacketHandler: {0}", WaitingForDevice), false);
377 |
378 | }
379 |
380 | // HidUtility informs us if the requested transfer was successful and provides us with the received packet
381 | public void PacketReceivedHandler(object sender, UsbBuffer InBuffer)
382 | {
383 | //WriteLog(string.Format("PacketReceivedHandler: {0:X2}", InBuffer.buffer[1]), false);
384 | WaitingForDevice = false;
385 | if (InBuffer.buffer[1] == 0x37)
386 | {
387 | //Need to reformat the data from two unsigned chars into one unsigned int.
388 | AdcValue = (uint)(InBuffer.buffer[3] << 8) + InBuffer.buffer[2];
389 | }
390 | if (InBuffer.buffer[1] == 0x81)
391 | {
392 | if (InBuffer.buffer[2] == 0x01)
393 | {
394 | PushbuttonPressed = false;
395 | }
396 | if (InBuffer.buffer[2] == 0x00)
397 | {
398 | PushbuttonPressed = true;
399 | }
400 | }
401 | if (InBuffer.TransferSuccessful)
402 | {
403 | ++RxCount;
404 | }
405 | else
406 | {
407 | ++RxFailedCount;
408 | }
409 | }
410 |
411 |
412 | public unsafe Form1()
413 | {
414 | InitializeComponent();
415 |
416 | // Get an instance of HidUtility
417 | HidUtil = new HidUtility();
418 |
419 | // Initialize user interface
420 | SetUserInterfaceStatus(false);
421 |
422 | // Register event handlers
423 | HidUtil.RaiseDeviceRemovedEvent += DeviceRemovedHandler;
424 | HidUtil.RaiseDeviceAddedEvent += DeviceAddedHandler;
425 | HidUtil.RaiseConnectionStatusChangedEvent += ConnectionStatusChangedHandler;
426 | HidUtil.RaiseSendPacketEvent += SendPacketHandler;
427 | HidUtil.RaisePacketSentEvent += PacketSentHandler;
428 | HidUtil.RaiseReceivePacketEvent += ReceivePacketHandler;
429 | HidUtil.RaisePacketReceivedEvent += PacketReceivedHandler;
430 |
431 | // Fill the PID and VID text boxes
432 | VidTextBox.Text = string.Format("0x{0:X4}", VID);
433 | PidTextBox.Text = string.Format("0x{0:X4}", PID);
434 |
435 | // Initialize tool tips, to provide pop up help when the mouse cursor is moved over objects on the form.
436 | ANxVoltageToolTip.SetToolTip(this.AnalogLabel, "If using a board/PIM without a potentiometer, apply an adjustable voltage to the I/O pin.");
437 | ANxVoltageToolTip.SetToolTip(this.AnalogBar, "If using a board/PIM without a potentiometer, apply an adjustable voltage to the I/O pin.");
438 | ToggleLEDToolTip.SetToolTip(this.ToggleLedButton, "Sends a packet of data to the USB device.");
439 | PushbuttonStateTooltip.SetToolTip(this.PushbuttonText, "Try pressing pushbuttons on the USB demo board.");
440 |
441 | // Populate device list TextBox
442 | RefreshDeviceList();
443 |
444 | // Initiate Log TextBox
445 | WriteLog("System started", true);
446 |
447 | // Initial attempt to connect
448 | HidUtil.SelectDevice(new HidUtilityNuget.Device(VID, PID));
449 | } //Form1()
450 |
451 |
452 | private void FormUpdateTimer_Tick(object sender, EventArgs e)
453 | {
454 | // Update user interface based on the attachment state of the USB device.
455 | switch (HidUtil.ConnectionStatus)
456 | {
457 | case HidUtility.UsbConnectionStatus.Connected:
458 | UpdateStatistics();
459 | UpdatePushbutton();
460 | UpdateAdcBar();
461 | break;
462 | case HidUtility.UsbConnectionStatus.Disconnected:
463 | // Nothing to do
464 | break;
465 | case HidUtility.UsbConnectionStatus.NotWorking:
466 | // Nothing to do
467 | break;
468 | }
469 | }
470 | } //public partial class Form1 : Form
471 | } //namespace HidDemoWindowsForms
--------------------------------------------------------------------------------
/WindowsForms/Form1.Designer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace HidDemoWindowsForms
3 | {
4 | partial class Form1
5 | {
6 | ///
7 | /// Required designer variable.
8 | ///
9 | private System.ComponentModel.IContainer components = null;
10 |
11 | ///
12 | /// Clean up any resources being used.
13 | ///
14 | /// true if managed resources should be disposed; otherwise, false.
15 | protected override void Dispose(bool disposing)
16 | {
17 | if (disposing && (components != null))
18 | {
19 | components.Dispose();
20 | }
21 | base.Dispose(disposing);
22 | }
23 |
24 | #region Windows Form Designer generated code
25 |
26 | ///
27 | /// Required method for Designer support - do not modify
28 | /// the contents of this method with the code editor.
29 | ///
30 | private void InitializeComponent()
31 | {
32 | this.components = new System.ComponentModel.Container();
33 | this.ToggleLedButton = new System.Windows.Forms.Button();
34 | this.AnalogLabel = new System.Windows.Forms.Label();
35 | this.StatusText = new System.Windows.Forms.Label();
36 | this.AnalogBar = new System.Windows.Forms.ProgressBar();
37 | this.FormUpdateTimer = new System.Windows.Forms.Timer(this.components);
38 | this.ANxVoltageToolTip = new System.Windows.Forms.ToolTip(this.components);
39 | this.ToggleLEDToolTip = new System.Windows.Forms.ToolTip(this.components);
40 | this.PushbuttonStateTooltip = new System.Windows.Forms.ToolTip(this.components);
41 | this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
42 | this.toolTip2 = new System.Windows.Forms.ToolTip(this.components);
43 | this.LogTextBox = new System.Windows.Forms.TextBox();
44 | this.LogLabel = new System.Windows.Forms.Label();
45 | this.VidLabel = new System.Windows.Forms.Label();
46 | this.VidTextBox = new System.Windows.Forms.TextBox();
47 | this.PidLabel = new System.Windows.Forms.Label();
48 | this.PidTextBox = new System.Windows.Forms.TextBox();
49 | this.DeviceLabel = new System.Windows.Forms.Label();
50 | this.PushbuttonText = new System.Windows.Forms.Label();
51 | this.DevicesLabel = new System.Windows.Forms.Label();
52 | this.DevicesTextBox = new System.Windows.Forms.TextBox();
53 | this.HorizontalBar1 = new System.Windows.Forms.Label();
54 | this.HorizontalBar2 = new System.Windows.Forms.Label();
55 | this.HorizontalBar3 = new System.Windows.Forms.Label();
56 | this.CommunicationLabel = new System.Windows.Forms.Label();
57 | this.TxCountText = new System.Windows.Forms.Label();
58 | this.RxCountText = new System.Windows.Forms.Label();
59 | this.UptimeText = new System.Windows.Forms.Label();
60 | this.RxSpeedText = new System.Windows.Forms.Label();
61 | this.TxSpeedText = new System.Windows.Forms.Label();
62 | this.SuspendLayout();
63 | //
64 | // ToggleLedButton
65 | //
66 | this.ToggleLedButton.Enabled = false;
67 | this.ToggleLedButton.Location = new System.Drawing.Point(15, 464);
68 | this.ToggleLedButton.Name = "ToggleLedButton";
69 | this.ToggleLedButton.Size = new System.Drawing.Size(96, 23);
70 | this.ToggleLedButton.TabIndex = 24;
71 | this.ToggleLedButton.Text = "Toggle LED";
72 | this.ToggleLedButton.UseVisualStyleBackColor = true;
73 | this.ToggleLedButton.Click += new System.EventHandler(this.ToggleLedButton_Click);
74 | //
75 | // AnalogLabel
76 | //
77 | this.AnalogLabel.AutoSize = true;
78 | this.AnalogLabel.Enabled = false;
79 | this.AnalogLabel.Location = new System.Drawing.Point(12, 506);
80 | this.AnalogLabel.Name = "AnalogLabel";
81 | this.AnalogLabel.Size = new System.Drawing.Size(107, 13);
82 | this.AnalogLabel.TabIndex = 23;
83 | this.AnalogLabel.Text = "Analog Measurement";
84 | //
85 | // StatusText
86 | //
87 | this.StatusText.AutoSize = true;
88 | this.StatusText.Location = new System.Drawing.Point(12, 337);
89 | this.StatusText.Name = "StatusText";
90 | this.StatusText.Size = new System.Drawing.Size(171, 13);
91 | this.StatusText.TabIndex = 22;
92 | this.StatusText.Text = "Connection Status: Not connected";
93 | //
94 | // AnalogBar
95 | //
96 | this.AnalogBar.BackColor = System.Drawing.Color.White;
97 | this.AnalogBar.ForeColor = System.Drawing.Color.Red;
98 | this.AnalogBar.Location = new System.Drawing.Point(12, 522);
99 | this.AnalogBar.Maximum = 1024;
100 | this.AnalogBar.Name = "AnalogBar";
101 | this.AnalogBar.Size = new System.Drawing.Size(298, 23);
102 | this.AnalogBar.Step = 1;
103 | this.AnalogBar.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
104 | this.AnalogBar.TabIndex = 20;
105 | //
106 | // FormUpdateTimer
107 | //
108 | this.FormUpdateTimer.Enabled = true;
109 | this.FormUpdateTimer.Interval = 6;
110 | this.FormUpdateTimer.Tick += new System.EventHandler(this.FormUpdateTimer_Tick);
111 | //
112 | // ANxVoltageToolTip
113 | //
114 | this.ANxVoltageToolTip.AutomaticDelay = 20;
115 | this.ANxVoltageToolTip.AutoPopDelay = 20000;
116 | this.ANxVoltageToolTip.InitialDelay = 15;
117 | this.ANxVoltageToolTip.ReshowDelay = 15;
118 | //
119 | // ToggleLEDToolTip
120 | //
121 | this.ToggleLEDToolTip.AutomaticDelay = 2000;
122 | this.ToggleLEDToolTip.AutoPopDelay = 20000;
123 | this.ToggleLEDToolTip.InitialDelay = 15;
124 | this.ToggleLEDToolTip.ReshowDelay = 15;
125 | //
126 | // PushbuttonStateTooltip
127 | //
128 | this.PushbuttonStateTooltip.AutomaticDelay = 20;
129 | this.PushbuttonStateTooltip.AutoPopDelay = 20000;
130 | this.PushbuttonStateTooltip.InitialDelay = 15;
131 | this.PushbuttonStateTooltip.ReshowDelay = 15;
132 | //
133 | // toolTip1
134 | //
135 | this.toolTip1.AutomaticDelay = 2000;
136 | this.toolTip1.AutoPopDelay = 20000;
137 | this.toolTip1.InitialDelay = 15;
138 | this.toolTip1.ReshowDelay = 15;
139 | //
140 | // toolTip2
141 | //
142 | this.toolTip2.AutomaticDelay = 20;
143 | this.toolTip2.AutoPopDelay = 20000;
144 | this.toolTip2.InitialDelay = 15;
145 | this.toolTip2.ReshowDelay = 15;
146 | //
147 | // LogTextBox
148 | //
149 | this.LogTextBox.BackColor = System.Drawing.SystemColors.Window;
150 | this.LogTextBox.Location = new System.Drawing.Point(15, 598);
151 | this.LogTextBox.Multiline = true;
152 | this.LogTextBox.Name = "LogTextBox";
153 | this.LogTextBox.ReadOnly = true;
154 | this.LogTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
155 | this.LogTextBox.Size = new System.Drawing.Size(710, 158);
156 | this.LogTextBox.TabIndex = 26;
157 | //
158 | // LogLabel
159 | //
160 | this.LogLabel.AutoSize = true;
161 | this.LogLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
162 | this.LogLabel.Location = new System.Drawing.Point(12, 579);
163 | this.LogLabel.Name = "LogLabel";
164 | this.LogLabel.Size = new System.Drawing.Size(70, 13);
165 | this.LogLabel.TabIndex = 27;
166 | this.LogLabel.Text = "ActivityLog";
167 | //
168 | // VidLabel
169 | //
170 | this.VidLabel.AutoSize = true;
171 | this.VidLabel.Location = new System.Drawing.Point(12, 29);
172 | this.VidLabel.Name = "VidLabel";
173 | this.VidLabel.Size = new System.Drawing.Size(55, 13);
174 | this.VidLabel.TabIndex = 29;
175 | this.VidLabel.Text = "Vendor ID";
176 | //
177 | // VidTextBox
178 | //
179 | this.VidTextBox.AcceptsReturn = true;
180 | this.VidTextBox.BackColor = System.Drawing.SystemColors.Window;
181 | this.VidTextBox.Location = new System.Drawing.Point(15, 45);
182 | this.VidTextBox.MaxLength = 6;
183 | this.VidTextBox.Name = "VidTextBox";
184 | this.VidTextBox.Size = new System.Drawing.Size(55, 20);
185 | this.VidTextBox.TabIndex = 28;
186 | this.VidTextBox.Text = "0x0000";
187 | this.VidTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.VidTextBox_KeyUp);
188 | this.VidTextBox.LostFocus += new System.EventHandler(this.VidTextBox_LostFocus);
189 | //
190 | // PidLabel
191 | //
192 | this.PidLabel.AutoSize = true;
193 | this.PidLabel.Location = new System.Drawing.Point(91, 29);
194 | this.PidLabel.Name = "PidLabel";
195 | this.PidLabel.Size = new System.Drawing.Size(55, 13);
196 | this.PidLabel.TabIndex = 31;
197 | this.PidLabel.Text = "Device ID";
198 | //
199 | // PidTextBox
200 | //
201 | this.PidTextBox.AcceptsReturn = true;
202 | this.PidTextBox.BackColor = System.Drawing.SystemColors.Window;
203 | this.PidTextBox.Location = new System.Drawing.Point(94, 45);
204 | this.PidTextBox.MaxLength = 6;
205 | this.PidTextBox.Name = "PidTextBox";
206 | this.PidTextBox.Size = new System.Drawing.Size(55, 20);
207 | this.PidTextBox.TabIndex = 30;
208 | this.PidTextBox.Text = "0x0000";
209 | this.PidTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.PidTextBox_KeyUp);
210 | this.PidTextBox.LostFocus += new System.EventHandler(this.PidTextBox_LostFocus);
211 | //
212 | // DeviceLabel
213 | //
214 | this.DeviceLabel.AutoSize = true;
215 | this.DeviceLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
216 | this.DeviceLabel.Location = new System.Drawing.Point(12, 9);
217 | this.DeviceLabel.Name = "DeviceLabel";
218 | this.DeviceLabel.Size = new System.Drawing.Size(212, 13);
219 | this.DeviceLabel.TabIndex = 32;
220 | this.DeviceLabel.Text = "Vendor ID and Device ID to look for";
221 | //
222 | // PushbuttonText
223 | //
224 | this.PushbuttonText.AutoSize = true;
225 | this.PushbuttonText.Location = new System.Drawing.Point(12, 432);
226 | this.PushbuttonText.Name = "PushbuttonText";
227 | this.PushbuttonText.Size = new System.Drawing.Size(141, 13);
228 | this.PushbuttonText.TabIndex = 33;
229 | this.PushbuttonText.Text = "Pushbutton State: Unknown";
230 | //
231 | // DevicesLabel
232 | //
233 | this.DevicesLabel.AutoSize = true;
234 | this.DevicesLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
235 | this.DevicesLabel.Location = new System.Drawing.Point(12, 94);
236 | this.DevicesLabel.Name = "DevicesLabel";
237 | this.DevicesLabel.Size = new System.Drawing.Size(108, 13);
238 | this.DevicesLabel.TabIndex = 34;
239 | this.DevicesLabel.Text = "Attached Devices";
240 | //
241 | // DevicesTextBox
242 | //
243 | this.DevicesTextBox.BackColor = System.Drawing.SystemColors.Window;
244 | this.DevicesTextBox.Location = new System.Drawing.Point(15, 116);
245 | this.DevicesTextBox.Multiline = true;
246 | this.DevicesTextBox.Name = "DevicesTextBox";
247 | this.DevicesTextBox.ReadOnly = true;
248 | this.DevicesTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
249 | this.DevicesTextBox.Size = new System.Drawing.Size(710, 162);
250 | this.DevicesTextBox.TabIndex = 35;
251 | //
252 | // HorizontalBar1
253 | //
254 | this.HorizontalBar1.AutoSize = true;
255 | this.HorizontalBar1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
256 | this.HorizontalBar1.Enabled = false;
257 | this.HorizontalBar1.Font = new System.Drawing.Font("Microsoft Sans Serif", 1F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
258 | this.HorizontalBar1.Location = new System.Drawing.Point(15, 78);
259 | this.HorizontalBar1.Margin = new System.Windows.Forms.Padding(0);
260 | this.HorizontalBar1.MinimumSize = new System.Drawing.Size(710, 1);
261 | this.HorizontalBar1.Name = "HorizontalBar1";
262 | this.HorizontalBar1.Size = new System.Drawing.Size(710, 4);
263 | this.HorizontalBar1.TabIndex = 36;
264 | //
265 | // HorizontalBar2
266 | //
267 | this.HorizontalBar2.AutoSize = true;
268 | this.HorizontalBar2.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
269 | this.HorizontalBar2.Enabled = false;
270 | this.HorizontalBar2.Font = new System.Drawing.Font("Microsoft Sans Serif", 1F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
271 | this.HorizontalBar2.Location = new System.Drawing.Point(15, 294);
272 | this.HorizontalBar2.Margin = new System.Windows.Forms.Padding(0);
273 | this.HorizontalBar2.MinimumSize = new System.Drawing.Size(710, 1);
274 | this.HorizontalBar2.Name = "HorizontalBar2";
275 | this.HorizontalBar2.Size = new System.Drawing.Size(710, 4);
276 | this.HorizontalBar2.TabIndex = 37;
277 | //
278 | // HorizontalBar3
279 | //
280 | this.HorizontalBar3.AutoSize = true;
281 | this.HorizontalBar3.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
282 | this.HorizontalBar3.Enabled = false;
283 | this.HorizontalBar3.Font = new System.Drawing.Font("Microsoft Sans Serif", 1F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
284 | this.HorizontalBar3.Location = new System.Drawing.Point(15, 563);
285 | this.HorizontalBar3.Margin = new System.Windows.Forms.Padding(0);
286 | this.HorizontalBar3.MinimumSize = new System.Drawing.Size(710, 1);
287 | this.HorizontalBar3.Name = "HorizontalBar3";
288 | this.HorizontalBar3.Size = new System.Drawing.Size(710, 4);
289 | this.HorizontalBar3.TabIndex = 38;
290 | //
291 | // CommunicationLabel
292 | //
293 | this.CommunicationLabel.AutoSize = true;
294 | this.CommunicationLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
295 | this.CommunicationLabel.Location = new System.Drawing.Point(12, 312);
296 | this.CommunicationLabel.Name = "CommunicationLabel";
297 | this.CommunicationLabel.Size = new System.Drawing.Size(92, 13);
298 | this.CommunicationLabel.TabIndex = 39;
299 | this.CommunicationLabel.Text = "Communication";
300 | //
301 | // TxCountText
302 | //
303 | this.TxCountText.AutoSize = true;
304 | this.TxCountText.Location = new System.Drawing.Point(12, 384);
305 | this.TxCountText.Name = "TxCountText";
306 | this.TxCountText.Size = new System.Drawing.Size(122, 13);
307 | this.TxCountText.TabIndex = 40;
308 | this.TxCountText.Text = "Packets sent/failed: 0/0";
309 | //
310 | // RxCountText
311 | //
312 | this.RxCountText.AutoSize = true;
313 | this.RxCountText.Location = new System.Drawing.Point(285, 384);
314 | this.RxCountText.Name = "RxCountText";
315 | this.RxCountText.Size = new System.Drawing.Size(143, 13);
316 | this.RxCountText.TabIndex = 41;
317 | this.RxCountText.Text = "Packets received/failed: 0/0";
318 | //
319 | // UptimeText
320 | //
321 | this.UptimeText.AutoSize = true;
322 | this.UptimeText.Location = new System.Drawing.Point(12, 360);
323 | this.UptimeText.Name = "UptimeText";
324 | this.UptimeText.Size = new System.Drawing.Size(52, 13);
325 | this.UptimeText.TabIndex = 42;
326 | this.UptimeText.Text = "Uptime: 0";
327 | //
328 | // RxSpeedText
329 | //
330 | this.RxSpeedText.AutoSize = true;
331 | this.RxSpeedText.Location = new System.Drawing.Point(285, 409);
332 | this.RxSpeedText.Name = "RxSpeedText";
333 | this.RxSpeedText.Size = new System.Drawing.Size(82, 13);
334 | this.RxSpeedText.TabIndex = 44;
335 | this.RxSpeedText.Text = "RX Speed: N/A";
336 | //
337 | // TxSpeedText
338 | //
339 | this.TxSpeedText.AutoSize = true;
340 | this.TxSpeedText.Location = new System.Drawing.Point(12, 409);
341 | this.TxSpeedText.Name = "TxSpeedText";
342 | this.TxSpeedText.Size = new System.Drawing.Size(81, 13);
343 | this.TxSpeedText.TabIndex = 43;
344 | this.TxSpeedText.Text = "TX Speed: N/A";
345 | //
346 | // Form1
347 | //
348 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
349 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
350 | this.ClientSize = new System.Drawing.Size(734, 768);
351 | this.Controls.Add(this.RxSpeedText);
352 | this.Controls.Add(this.TxSpeedText);
353 | this.Controls.Add(this.UptimeText);
354 | this.Controls.Add(this.RxCountText);
355 | this.Controls.Add(this.TxCountText);
356 | this.Controls.Add(this.CommunicationLabel);
357 | this.Controls.Add(this.HorizontalBar3);
358 | this.Controls.Add(this.HorizontalBar2);
359 | this.Controls.Add(this.HorizontalBar1);
360 | this.Controls.Add(this.DevicesTextBox);
361 | this.Controls.Add(this.DevicesLabel);
362 | this.Controls.Add(this.PushbuttonText);
363 | this.Controls.Add(this.DeviceLabel);
364 | this.Controls.Add(this.PidLabel);
365 | this.Controls.Add(this.PidTextBox);
366 | this.Controls.Add(this.VidLabel);
367 | this.Controls.Add(this.VidTextBox);
368 | this.Controls.Add(this.LogLabel);
369 | this.Controls.Add(this.LogTextBox);
370 | this.Controls.Add(this.ToggleLedButton);
371 | this.Controls.Add(this.AnalogLabel);
372 | this.Controls.Add(this.StatusText);
373 | this.Controls.Add(this.AnalogBar);
374 | this.Name = "Form1";
375 | this.Text = "HID Demo WindowsForms";
376 | this.ResumeLayout(false);
377 | this.PerformLayout();
378 |
379 | }
380 |
381 | #endregion
382 | private System.Windows.Forms.Button ToggleLedButton;
383 | private System.Windows.Forms.Label AnalogLabel;
384 | private System.Windows.Forms.Label StatusText;
385 | private System.Windows.Forms.ProgressBar AnalogBar;
386 | //private System.ComponentModel.BackgroundWorker ReadWriteThread;
387 | private System.Windows.Forms.Timer FormUpdateTimer;
388 | private System.Windows.Forms.ToolTip ANxVoltageToolTip;
389 | private System.Windows.Forms.ToolTip ToggleLEDToolTip;
390 | private System.Windows.Forms.ToolTip PushbuttonStateTooltip;
391 | private System.Windows.Forms.ToolTip toolTip1;
392 | private System.Windows.Forms.ToolTip toolTip2;
393 | private System.Windows.Forms.TextBox LogTextBox;
394 | private System.Windows.Forms.Label LogLabel;
395 | private System.Windows.Forms.Label VidLabel;
396 | private System.Windows.Forms.TextBox VidTextBox;
397 | private System.Windows.Forms.Label PidLabel;
398 | private System.Windows.Forms.TextBox PidTextBox;
399 | private System.Windows.Forms.Label DeviceLabel;
400 | private System.Windows.Forms.Label PushbuttonText;
401 | private System.Windows.Forms.Label DevicesLabel;
402 | private System.Windows.Forms.TextBox DevicesTextBox;
403 | private System.Windows.Forms.Label HorizontalBar1;
404 | private System.Windows.Forms.Label HorizontalBar2;
405 | private System.Windows.Forms.Label HorizontalBar3;
406 | private System.Windows.Forms.Label CommunicationLabel;
407 | private System.Windows.Forms.Label TxCountText;
408 | private System.Windows.Forms.Label RxCountText;
409 | private System.Windows.Forms.Label UptimeText;
410 | private System.Windows.Forms.Label RxSpeedText;
411 | private System.Windows.Forms.Label TxSpeedText;
412 | }
413 | }
414 |
415 |
--------------------------------------------------------------------------------
/WPF/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using System.Runtime.InteropServices;
9 | using System.Management;
10 | using System.IO;
11 | using System.Windows.Input;
12 | using System.ComponentModel;
13 | using System.Windows.Threading;
14 | using HidUtilityNuget;
15 |
16 |
17 |
18 |
19 | namespace HidDemoWpf
20 | {
21 |
22 | /*
23 | * The Model
24 | */
25 | public class Communicator
26 | {
27 | // Instance variables
28 | public HidUtility HidUtil { get; set; }
29 | private ushort _Vid;
30 | private ushort _Pid;
31 | public bool LedTogglePending { get; private set; }
32 | public bool WaitingForDevice { get; private set; }
33 | private byte LastCommand;
34 | public uint AdcValue { get; private set; }
35 | public bool PushbuttonPressed { get; private set; }
36 | public uint TxCount { get; private set; }
37 | public uint TxFailedCount { get; private set; }
38 | public uint RxCount { get; private set; }
39 | public uint RxFailedCount { get; private set; }
40 |
41 |
42 | public Communicator()
43 | {
44 | // Initialize variables
45 | _Vid = 0x04D8;
46 | _Pid = 0x0054;
47 | TxCount = 0;
48 | TxFailedCount = 0;
49 | RxCount = 0;
50 | RxFailedCount = 0;
51 | LedTogglePending = false;
52 | LastCommand = 0x81;
53 |
54 | // Obtain and initialize an instance of HidUtility
55 | HidUtil = new HidUtility();
56 | HidUtil.SelectDevice(new Device(_Vid, _Pid));
57 |
58 | // Subscribe to HidUtility events
59 | HidUtil.RaiseConnectionStatusChangedEvent += ConnectionStatusChangedHandler;
60 | HidUtil.RaiseSendPacketEvent += SendPacketHandler;
61 | HidUtil.RaisePacketSentEvent += PacketSentHandler;
62 | HidUtil.RaiseReceivePacketEvent += ReceivePacketHandler;
63 | HidUtil.RaisePacketReceivedEvent += PacketReceivedHandler;
64 | }
65 |
66 | // Accessor for _Vid
67 | // Only update selected device if the value has actually changed
68 | public ushort Vid
69 | {
70 | get
71 | {
72 | return _Vid;
73 | }
74 | set
75 | {
76 | if(value!=_Vid)
77 | {
78 | _Vid = value;
79 | HidUtil.SelectDevice(new Device(_Vid, _Pid));
80 | }
81 | }
82 | }
83 |
84 | // Accessor for _Pid
85 | // Only update selected device if the value has actually changed
86 | public ushort Pid
87 | {
88 | get
89 | {
90 | return _Pid;
91 | }
92 | set
93 | {
94 | if (value != _Pid)
95 | {
96 | _Pid = value;
97 | HidUtil.SelectDevice(new Device(_Vid, _Pid));
98 | }
99 | }
100 | }
101 |
102 | /*
103 | * HidUtility callback functions
104 | */
105 |
106 | public void ConnectionStatusChangedHandler(object sender, HidUtility.ConnectionStatusEventArgs e)
107 | {
108 | if (e.ConnectionStatus != HidUtility.UsbConnectionStatus.Connected)
109 | {
110 | // Reset variables
111 | TxCount = 0;
112 | TxFailedCount = 0;
113 | RxCount = 0;
114 | RxFailedCount = 0;
115 | LedTogglePending = false;
116 | LastCommand = 0x81;
117 | }
118 | }
119 |
120 | // HidUtility asks if a packet should be sent to the device
121 | // Prepare the buffer and request a transfer
122 | public void SendPacketHandler(object sender, UsbBuffer OutBuffer)
123 | {
124 | // Fill entire buffer with 0xFF
125 | OutBuffer.clear();
126 | if (LedTogglePending == true)
127 | {
128 | // The first byte is the "Report ID" and does not get sent over the USB bus. Always set = 0.
129 | OutBuffer.buffer[0] = 0;
130 | // 0x80 is the "Toggle LED" command in the firmware
131 | OutBuffer.buffer[1] = 0x80;
132 | LedTogglePending = false;
133 | LastCommand = 0x80;
134 | }
135 | else if (LastCommand == 0x81)
136 | {
137 | // The first byte is the "Report ID" and does not get sent over the USB bus. Always set = 0.
138 | OutBuffer.buffer[0] = 0x00;
139 | // READ_POT command (see the firmware source code), gets 10-bit ADC Value
140 | OutBuffer.buffer[1] = 0x37;
141 | LastCommand = 0x37;
142 | }
143 | else
144 | {
145 | // The first byte is the "Report ID" and does not get sent over the USB bus. Always set = 0.
146 | OutBuffer.buffer[0] = 0x00;
147 | // 0x81 is the "Get Pushbutton State" command in the firmware
148 | OutBuffer.buffer[1] = 0x81;
149 | LastCommand = 0x81;
150 | }
151 | // Request that this buffer be sent
152 | OutBuffer.RequestTransfer = true;
153 | }
154 |
155 | // HidUtility informs us if the requested transfer was successful
156 | // Schedule to request a packet if the transfer was successful
157 | public void PacketSentHandler(object sender, UsbBuffer OutBuffer)
158 | {
159 | if (LastCommand == 0x80)
160 | {
161 | WaitingForDevice = false;
162 | }
163 | else
164 | {
165 | WaitingForDevice = OutBuffer.TransferSuccessful;
166 | }
167 | if (OutBuffer.TransferSuccessful)
168 | {
169 | ++TxCount;
170 | }
171 | else
172 | {
173 | ++TxFailedCount;
174 | }
175 | }
176 |
177 | // HidUtility asks if a packet should be requested from the device
178 | // Request a packet if a packet has been successfully sent to the device before
179 | public void ReceivePacketHandler(object sender, UsbBuffer InBuffer)
180 | {
181 | InBuffer.RequestTransfer = WaitingForDevice;
182 | }
183 |
184 | // HidUtility informs us if the requested transfer was successful and provides us with the received packet
185 | public void PacketReceivedHandler(object sender, UsbBuffer InBuffer)
186 | {
187 | //WriteLog(string.Format("PacketReceivedHandler: {0:X2}", InBuffer.buffer[1]), false);
188 | WaitingForDevice = false;
189 | if (InBuffer.buffer[1] == 0x37)
190 | {
191 | //Need to reformat the data from two unsigned chars into one unsigned int.
192 | AdcValue = (uint)(InBuffer.buffer[3] << 8) + InBuffer.buffer[2];
193 | }
194 | if (InBuffer.buffer[1] == 0x81)
195 | {
196 | if (InBuffer.buffer[2] == 0x01)
197 | {
198 | PushbuttonPressed = false;
199 | }
200 | if (InBuffer.buffer[2] == 0x00)
201 | {
202 | PushbuttonPressed = true;
203 | }
204 | }
205 | if (InBuffer.TransferSuccessful)
206 | {
207 | ++RxCount;
208 | }
209 | else
210 | {
211 | ++RxFailedCount;
212 | }
213 | }
214 |
215 | public bool RequestLedToggleValid()
216 | {
217 | return !LedTogglePending;
218 | }
219 |
220 | public void RequestLedToggle()
221 | {
222 | LedTogglePending = true;
223 | }
224 | } // Communicator
225 |
226 | /*
227 | * The Command Class
228 | */
229 |
230 | public class UiCommand : ICommand
231 | {
232 | private Action _Execute;
233 | private Func _CanExecute;
234 | public event EventHandler CanExecuteChanged;
235 |
236 | public UiCommand(Action Execute, Func CanExecute)
237 | {
238 | _Execute = Execute;
239 | _CanExecute = CanExecute;
240 | }
241 | public bool CanExecute(object parameter)
242 | {
243 | return _CanExecute();
244 | }
245 | public void Execute(object parameter)
246 | {
247 | _Execute();
248 | }
249 | }
250 |
251 | /*
252 | * The ViewModel
253 | */
254 | public class CommunicatorViewModel : INotifyPropertyChanged
255 | {
256 | private Communicator communicator;
257 | DispatcherTimer timer;
258 | private UiCommand buttonCommand;
259 | private DateTime ConnectedTimestamp = DateTime.Now;
260 | public string ActivityLogTxt { get; private set; }
261 |
262 | public event PropertyChangedEventHandler PropertyChanged;
263 |
264 | public CommunicatorViewModel()
265 | {
266 | communicator = new Communicator();
267 | communicator.HidUtil.RaiseDeviceAddedEvent += DeviceAddedEventHandler;
268 | communicator.HidUtil.RaiseDeviceRemovedEvent += DeviceRemovedEventHandler;
269 | communicator.HidUtil.RaiseConnectionStatusChangedEvent += ConnectionStatusChangedHandler;
270 |
271 | buttonCommand = new UiCommand(this.RequestLedToggle, communicator.RequestLedToggleValid);
272 |
273 | WriteLog("Program started", true);
274 |
275 | //Configure and start timer
276 | timer = new DispatcherTimer();
277 | timer.Interval = TimeSpan.FromMilliseconds(50);
278 | timer.Tick += TimerTickHandler;
279 | timer.Start();
280 | }
281 |
282 | /*
283 | * Local function definitions
284 | */
285 |
286 | // Add a line to the activity log text box
287 | void WriteLog(string message, bool clear)
288 | {
289 | // Replace content
290 | if (clear)
291 | {
292 | ActivityLogTxt = string.Format("{0}: {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), message);
293 | }
294 | // Add new line
295 | else
296 | {
297 | ActivityLogTxt += Environment.NewLine + string.Format("{0}: {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), message);
298 | }
299 | }
300 |
301 | public void RequestLedToggle()
302 | {
303 | WriteLog("Toggle LED button clicked", false);
304 | communicator.RequestLedToggle();
305 | if (PropertyChanged != null)
306 | {
307 | PropertyChanged(this, new PropertyChangedEventArgs("LedToggleActive"));
308 | PropertyChanged(this, new PropertyChangedEventArgs("PushbuttonContentTxt"));
309 | PropertyChanged(this, new PropertyChangedEventArgs("LedTogglePendingTxt"));
310 | PropertyChanged(this, new PropertyChangedEventArgs("ActivityLogTxt"));
311 | }
312 | }
313 |
314 | public ICommand ToggleClick
315 | {
316 | get
317 | {
318 | return buttonCommand;
319 | }
320 | }
321 |
322 | public bool LedToggleActive
323 | {
324 | get
325 | {
326 | if(communicator.HidUtil.ConnectionStatus==HidUtility.UsbConnectionStatus.Connected)
327 | {
328 | return communicator.RequestLedToggleValid();
329 | }
330 | return false;
331 | }
332 | }
333 |
334 | public bool UserInterfaceActive
335 | {
336 | get
337 | {
338 | if (communicator.HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
339 | return true;
340 | else
341 | return false;
342 | }
343 | }
344 |
345 | public string UserInterfaceColor
346 | {
347 | get
348 | {
349 | if (communicator.HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
350 | return "Black";
351 | else
352 | return "Gray";
353 | }
354 | }
355 |
356 | public void TimerTickHandler(object sender, EventArgs e)
357 | {
358 |
359 | PropertyChanged(this, new PropertyChangedEventArgs("UptimeTxt"));
360 | PropertyChanged(this, new PropertyChangedEventArgs("LedToggleActive"));
361 | PropertyChanged(this, new PropertyChangedEventArgs("PushbuttonContentTxt"));
362 | PropertyChanged(this, new PropertyChangedEventArgs("PushbuttonStatusTxt"));
363 | PropertyChanged(this, new PropertyChangedEventArgs("AdcValue"));
364 | PropertyChanged(this, new PropertyChangedEventArgs("TxSuccessfulTxt"));
365 | PropertyChanged(this, new PropertyChangedEventArgs("TxFailedTxt"));
366 | PropertyChanged(this, new PropertyChangedEventArgs("RxSuccessfulTxt"));
367 | PropertyChanged(this, new PropertyChangedEventArgs("RxFailedTxt"));
368 | PropertyChanged(this, new PropertyChangedEventArgs("TxSpeedTxt"));
369 | PropertyChanged(this, new PropertyChangedEventArgs("RxSpeedTxt"));
370 |
371 | }
372 |
373 | public void DeviceAddedEventHandler(object sender, Device dev)
374 | {
375 | WriteLog("Device added: " + dev.ToString(), false);
376 | if (PropertyChanged != null)
377 | {
378 | PropertyChanged(this, new PropertyChangedEventArgs("DeviceListTxt"));
379 | PropertyChanged(this, new PropertyChangedEventArgs("ActivityLogTxt"));
380 | }
381 | }
382 |
383 | public void DeviceRemovedEventHandler(object sender, Device dev)
384 | {
385 | WriteLog("Device removed: " + dev.ToString(), false);
386 | if (PropertyChanged != null)
387 | {
388 | PropertyChanged(this, new PropertyChangedEventArgs("DeviceListTxt"));
389 | PropertyChanged(this, new PropertyChangedEventArgs("ActivityLogTxt"));
390 | }
391 |
392 | }
393 |
394 | public void ConnectionStatusChangedHandler(object sender, HidUtility.ConnectionStatusEventArgs e)
395 | {
396 | WriteLog("Connection status changed to: " + e.ToString(), false);
397 | switch (e.ConnectionStatus)
398 | {
399 | case HidUtility.UsbConnectionStatus.Connected:
400 | ConnectedTimestamp = DateTime.Now;
401 | break;
402 | case HidUtility.UsbConnectionStatus.Disconnected:
403 | break;
404 | case HidUtility.UsbConnectionStatus.NotWorking:
405 | break;
406 | }
407 | if (PropertyChanged != null)
408 | {
409 | PropertyChanged(this, new PropertyChangedEventArgs("ConnectionStatusTxt"));
410 | PropertyChanged(this, new PropertyChangedEventArgs("UptimeTxt"));
411 | PropertyChanged(this, new PropertyChangedEventArgs("ActivityLogTxt"));
412 | PropertyChanged(this, new PropertyChangedEventArgs("UserInterfaceActive"));
413 | PropertyChanged(this, new PropertyChangedEventArgs("UserInterfaceColor"));
414 | PropertyChanged(this, new PropertyChangedEventArgs("LedToggleActive"));
415 | PropertyChanged(this, new PropertyChangedEventArgs("PushbuttonContentTxt"));
416 | PropertyChanged(this, new PropertyChangedEventArgs("AdcValue"));
417 | }
418 | }
419 |
420 |
421 | public string LedTogglePendingTxt
422 | {
423 | get
424 | {
425 | if (communicator.LedTogglePending)
426 | return "Toggle pending";
427 | else
428 | return "No action pending";
429 | }
430 | }
431 |
432 | public string DeviceListTxt
433 | {
434 | get
435 | {
436 | string txt = "";
437 | foreach (Device dev in communicator.HidUtil.DeviceList)
438 | {
439 | string devString = string.Format("VID=0x{0:X4} PID=0x{1:X4}: {2} ({3})", dev.Vid, dev.Pid, dev.Caption, dev.Manufacturer);
440 | txt += devString + Environment.NewLine;
441 | }
442 | return txt.TrimEnd();
443 | }
444 | }
445 |
446 | public string PushbuttonStatusTxt
447 | {
448 | get
449 | {
450 | if (communicator.PushbuttonPressed)
451 | return "Pushbutton pressed";
452 | else
453 | return "Pushbutton not pressed";
454 | }
455 | }
456 |
457 | public string PushbuttonContentTxt
458 | {
459 | get
460 | {
461 | if (communicator.LedTogglePending)
462 | return "Toggle pending...";
463 | else
464 | return "Toggle LED";
465 | }
466 | }
467 |
468 | public uint AdcValue
469 | {
470 | get
471 | {
472 | return communicator.AdcValue;
473 | }
474 | }
475 |
476 | // Try to convert a (hexadecimal) string to an unsigned 16-bit integer
477 | // Return 0 if the conversion fails
478 | // This function is used to parse the PID and VID text boxes
479 | private ushort ParseHex(string input)
480 | {
481 | input = input.ToLower();
482 | if (input.Length >= 2)
483 | {
484 | if (input.Substring(0, 2) == "0x")
485 | {
486 | input = input.Substring(2);
487 | }
488 | }
489 | try
490 | {
491 | ushort value = ushort.Parse(input, System.Globalization.NumberStyles.HexNumber);
492 | return value;
493 | }
494 | catch
495 | {
496 | return 0;
497 | }
498 | }
499 |
500 | public string VidTxt
501 | {
502 | get
503 | {
504 | return string.Format("0x{0:X4}", communicator.Vid);
505 | }
506 | set
507 | {
508 | communicator.Vid = ParseHex(value);
509 | string log = string.Format("Trying to connect (VID=0x{0:X4} PID=0x{1:X4})", communicator.Vid, communicator.Pid);
510 | WriteLog(log, false);
511 | PropertyChanged(this, new PropertyChangedEventArgs("ActivityLogTxt"));
512 | }
513 | }
514 |
515 | public string PidTxt
516 | {
517 | get
518 | {
519 | return string.Format("0x{0:X4}", communicator.Pid);
520 | }
521 | set
522 | {
523 | communicator.Pid = ParseHex(value);
524 | string log = string.Format("Trying to connect (VID=0x{0:X4} PID=0x{1:X4})", communicator.Vid, communicator.Pid);
525 | WriteLog(log, false);
526 | PropertyChanged(this, new PropertyChangedEventArgs("ActivityLogTxt"));
527 | }
528 | }
529 |
530 | public string ConnectionStatusTxt
531 | {
532 | get
533 | {
534 | return string.Format("Connection Status: {0}", communicator.HidUtil.ConnectionStatus.ToString());
535 | }
536 |
537 | }
538 |
539 | public string UptimeTxt
540 | {
541 | get
542 | {
543 | if(communicator.HidUtil.ConnectionStatus==HidUtility.UsbConnectionStatus.Connected)
544 | {
545 | //Save time elapsed since the device was connected
546 | TimeSpan uptime = DateTime.Now - ConnectedTimestamp;
547 | //Return uptime as string
548 | return string.Format("Uptime: {0}", uptime.ToString(@"hh\:mm\:ss\.f"));
549 | }
550 | else
551 | {
552 | return "Uptime: -";
553 | }
554 | }
555 | }
556 |
557 | public string TxSuccessfulTxt
558 | {
559 | get
560 | {
561 | if (communicator.HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
562 | return string.Format("Sent: {0}", communicator.TxCount);
563 | else
564 | return "Sent: -";
565 | }
566 | }
567 |
568 |
569 |
570 | public string TxFailedTxt
571 | {
572 | get
573 | {
574 | if (communicator.HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
575 | return string.Format("Sending failed: {0}", communicator.TxFailedCount);
576 | else
577 | return "Sending failed: -";
578 | }
579 | }
580 |
581 | public string RxSuccessfulTxt
582 | {
583 | get
584 | {
585 | if (communicator.HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
586 | return string.Format("Received: {0}", communicator.RxCount);
587 | else
588 | return "Receied: -";
589 | }
590 | }
591 |
592 | public string RxFailedTxt
593 | {
594 | get
595 | {
596 | if (communicator.HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
597 | return string.Format("Reception failed: {0}", communicator.RxFailedCount);
598 | else
599 | return "Reception failed: -";
600 | }
601 | }
602 |
603 | public string TxSpeedTxt
604 | {
605 | get
606 | {
607 | if (communicator.HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
608 | {
609 | if (communicator.TxCount != 0)
610 | {
611 | return string.Format("TX Speed: {0:0.00} packets per second", communicator.TxCount / (DateTime.Now - ConnectedTimestamp).TotalSeconds);
612 | }
613 | }
614 | return "TX Speed: n/a";
615 | }
616 | }
617 |
618 | public string RxSpeedTxt
619 | {
620 | get
621 | {
622 | if (communicator.HidUtil.ConnectionStatus == HidUtility.UsbConnectionStatus.Connected)
623 | {
624 | if (communicator.TxCount != 0)
625 | {
626 | return string.Format("RX Speed: {0:0.00} packets per second", communicator.TxCount / (DateTime.Now - ConnectedTimestamp).TotalSeconds);
627 | }
628 | }
629 | return "RX Speed: n/a";
630 | }
631 | }
632 |
633 | }
634 |
635 | ///
636 | /// Interaction logic for App.xaml
637 | ///
638 | public partial class App : Application
639 | {
640 |
641 | }
642 | }
643 |
--------------------------------------------------------------------------------
/HidUtilityNuget/hid.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using Microsoft.Win32.SafeHandles;
6 | using System.Windows.Interop;
7 | using System.Runtime.InteropServices;
8 | using System.Threading;
9 | using System.Management;
10 | using System.Text.RegularExpressions;
11 | using System.Threading.Tasks;
12 |
13 | namespace HidUtilityNuget
14 | {
15 | internal static class UsbNotification
16 | {
17 | public const int DbtDevicearrival = 0x8000; // system detected a new device
18 | public const int DbtDeviceremovecomplete = 0x8004; // device is gone
19 | public const int WmDevicechange = 0x0219; // device change event
20 | private const int DbtDevtypDeviceinterface = 5;
21 | private static readonly Guid GuidDevinterfaceUSBDevice = new Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED"); // USB devices
22 | private static IntPtr notificationHandle;
23 |
24 | ///
25 | /// Registers a window to receive notifications when USB devices are plugged or unplugged.
26 | ///
27 | /// Handle to the window receiving notifications.
28 | public static void RegisterUsbDeviceNotification(IntPtr windowHandle)
29 | {
30 | DevBroadcastDeviceinterface dbi = new DevBroadcastDeviceinterface
31 | {
32 | DeviceType = DbtDevtypDeviceinterface,
33 | Reserved = 0,
34 | ClassGuid = GuidDevinterfaceUSBDevice,
35 | Name = 0
36 | };
37 |
38 | dbi.Size = Marshal.SizeOf(dbi);
39 | IntPtr buffer = Marshal.AllocHGlobal(dbi.Size);
40 | Marshal.StructureToPtr(dbi, buffer, true);
41 |
42 | notificationHandle = RegisterDeviceNotification(windowHandle, buffer, 0);
43 | }
44 |
45 | ///
46 | /// Unregisters the window for USB device notifications
47 | ///
48 | public static void UnregisterUsbDeviceNotification()
49 | {
50 | UnregisterDeviceNotification(notificationHandle);
51 | }
52 |
53 | [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
54 | private static extern IntPtr RegisterDeviceNotification(IntPtr recipient, IntPtr notificationFilter, int flags);
55 |
56 | [DllImport("user32.dll")]
57 | private static extern bool UnregisterDeviceNotification(IntPtr handle);
58 |
59 | [StructLayout(LayoutKind.Sequential)]
60 | private struct DevBroadcastDeviceinterface
61 | {
62 | internal int Size;
63 | internal int DeviceType;
64 | internal int Reserved;
65 | internal Guid ClassGuid;
66 | internal short Name;
67 | }
68 | }
69 |
70 | //A class representing a USB device
71 | public class Device : EventArgs
72 | {
73 | public ushort Vid { get; private set; }
74 | public ushort Pid { get; private set; }
75 | public string DeviceID { get; private set; }
76 | public string ClassGuid { get; private set; }
77 | public string Caption { get; private set; }
78 | public string Manufacturer { get; private set; }
79 |
80 | public Device()
81 | {
82 | this.Vid = 0x0000;
83 | this.Pid = 0x0000;
84 | this.DeviceID = "";
85 | this.ClassGuid = "";
86 | this.Caption = "";
87 | this.Manufacturer = "";
88 | }
89 |
90 | public Device(ushort Vid, ushort Pid)
91 | {
92 | this.Vid = Vid;
93 | this.Pid = Pid;
94 | this.DeviceID = "";
95 | this.ClassGuid = "";
96 | this.Caption = "";
97 | this.Manufacturer = "";
98 | }
99 |
100 | public Device(ManagementObject wmi_obj)
101 | {
102 | this.DeviceID = wmi_obj["DeviceID"].ToString().ToUpper();
103 | this.ClassGuid = wmi_obj["ClassGuid"].ToString();
104 | this.Caption = wmi_obj["Caption"].ToString();
105 | this.Manufacturer = wmi_obj["Manufacturer"].ToString();
106 | Match match = Regex.Match(this.DeviceID, "PID_(.{4})", RegexOptions.IgnoreCase);
107 | if (match.Success)
108 | {
109 | string pid_string = match.Groups[1].Value;
110 | Pid = ushort.Parse(pid_string, System.Globalization.NumberStyles.HexNumber);
111 | }
112 | match = Regex.Match(this.DeviceID, "VID_(.{4})", RegexOptions.IgnoreCase);
113 | if (match.Success)
114 | {
115 | string vid_string = match.Groups[1].Value;
116 | Vid = ushort.Parse(vid_string, System.Globalization.NumberStyles.HexNumber);
117 | }
118 | }
119 |
120 | public override string ToString()
121 | {
122 | return string.Format("{0} (VID=0x{1:X4} PID=0x{2:X4})", Caption, Vid, Pid);
123 | }
124 | }
125 |
126 |
127 | //A class representing a USB buffer
128 | public class UsbBuffer : EventArgs
129 | {
130 | public byte[] buffer
131 | {
132 | get;
133 | set;
134 | }
135 | public bool RequestTransfer
136 | {
137 | get;
138 | set;
139 | }
140 | public bool TransferSuccessful
141 | {
142 | get;
143 | set;
144 | }
145 |
146 | public UsbBuffer(byte[] buffer)
147 | {
148 | //buffer = new byte[65];
149 | this.buffer = buffer;
150 | RequestTransfer = false;
151 | TransferSuccessful = false;
152 | clear();
153 | }
154 |
155 | public void clear()
156 | {
157 | for (int i = 0; i < 65; ++i)
158 | {
159 | buffer[i] = 0xFF;
160 | }
161 | }
162 | }
163 |
164 |
165 | public class HidUtility
166 | {
167 | public delegate void DeviceAddedEventHandler(object sender, Device dev);
168 | public delegate void DeviceRemovedEventHandler(object sender, Device dev);
169 | public delegate void ConnectionStatusChangedEventHandler(object sender, ConnectionStatusEventArgs e);
170 | public delegate void SendPacketEventHandler(object sender, UsbBuffer OutBuffer);
171 | public delegate void PacketSentEventHandler(object sender, UsbBuffer OutBuffer);
172 | public delegate void ReceivePacketEventHandler(object sender, UsbBuffer InBuffer);
173 | public delegate void PacketReceivedEventHandler(object sender, UsbBuffer InBuffer);
174 |
175 | public event DeviceAddedEventHandler RaiseDeviceAddedEvent;
176 | public event DeviceRemovedEventHandler RaiseDeviceRemovedEvent;
177 | public event ConnectionStatusChangedEventHandler RaiseConnectionStatusChangedEvent;
178 | public event SendPacketEventHandler RaiseSendPacketEvent;
179 | public event PacketSentEventHandler RaisePacketSentEvent;
180 | public event ReceivePacketEventHandler RaiseReceivePacketEvent;
181 | public event PacketReceivedEventHandler RaisePacketReceivedEvent;
182 |
183 | private List DeviceIdList;
184 | public List DeviceList { get; private set; }
185 | private Device DeviceToConnectTo;
186 | SafeFileHandle WriteHandleToUSBDevice = null;
187 | SafeFileHandle ReadHandleToUSBDevice = null;
188 |
189 | private System.ComponentModel.BackgroundWorker UsbThread;
190 |
191 | public enum UsbConnectionStatus
192 | {
193 | Disconnected,
194 | Connected,
195 | NotWorking
196 | }
197 |
198 | public UsbConnectionStatus ConnectionStatus { get; private set; }
199 |
200 | //A class representing a USB device
201 | public class ConnectionStatusEventArgs : EventArgs
202 | {
203 | public UsbConnectionStatus ConnectionStatus { get; private set; }
204 |
205 | public ConnectionStatusEventArgs(UsbConnectionStatus status)
206 | {
207 | this.ConnectionStatus = status;
208 | }
209 |
210 | public override string ToString()
211 | {
212 | return ConnectionStatus.ToString();
213 | }
214 | }
215 |
216 |
217 | //Constant definitions from setupapi.h, which we aren't allowed to include directly since this is C#
218 | internal const uint DIGCF_PRESENT = 0x02;
219 | internal const uint DIGCF_DEVICEINTERFACE = 0x10;
220 | //Constants for CreateFile() and other file I/O functions
221 | internal const short FILE_ATTRIBUTE_NORMAL = 0x80;
222 | internal const short INVALID_HANDLE_VALUE = -1;
223 | internal const uint GENERIC_READ = 0x80000000;
224 | internal const uint GENERIC_WRITE = 0x40000000;
225 | internal const uint CREATE_NEW = 1;
226 | internal const uint CREATE_ALWAYS = 2;
227 | internal const uint OPEN_EXISTING = 3;
228 | internal const uint FILE_SHARE_READ = 0x00000001;
229 | internal const uint FILE_SHARE_WRITE = 0x00000002;
230 | //Constant definitions for certain WM_DEVICECHANGE messages
231 | internal const uint WM_DEVICECHANGE = 0x0219;
232 | internal const uint DBT_DEVICEARRIVAL = 0x8000;
233 | internal const uint DBT_DEVICEREMOVEPENDING = 0x8003;
234 | internal const uint DBT_DEVICEREMOVECOMPLETE = 0x8004;
235 | internal const uint DBT_CONFIGCHANGED = 0x0018;
236 | //Other constant definitions
237 | internal const uint DBT_DEVTYP_DEVICEINTERFACE = 0x05;
238 | internal const uint DEVICE_NOTIFY_WINDOW_HANDLE = 0x00;
239 | internal const uint ERROR_SUCCESS = 0x00;
240 | internal const uint ERROR_NO_MORE_ITEMS = 0x00000103;
241 | internal const uint SPDRP_HARDWAREID = 0x00000001;
242 |
243 | //Various structure definitions for structures that this code will be using
244 | internal struct SP_DEVICE_INTERFACE_DATA
245 | {
246 | internal uint cbSize; //DWORD
247 | internal Guid InterfaceClassGuid; //GUID
248 | internal uint Flags; //DWORD
249 | internal uint Reserved; //ULONG_PTR MSDN says ULONG_PTR is "typedef unsigned __int3264 ULONG_PTR;"
250 | }
251 |
252 | internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
253 | {
254 | internal uint cbSize; //DWORD
255 | internal char[] DevicePath; //TCHAR array of any size
256 | }
257 |
258 | internal struct SP_DEVINFO_DATA
259 | {
260 | internal uint cbSize; //DWORD
261 | internal Guid ClassGuid; //GUID
262 | internal uint DevInst; //DWORD
263 | internal uint Reserved; //ULONG_PTR MSDN says ULONG_PTR is "typedef unsigned __int3264 ULONG_PTR;"
264 | }
265 |
266 | internal struct DEV_BROADCAST_DEVICEINTERFACE
267 | {
268 | internal uint dbcc_size; //DWORD
269 | internal uint dbcc_devicetype; //DWORD
270 | internal uint dbcc_reserved; //DWORD
271 | internal Guid dbcc_classguid; //GUID
272 | internal char[] dbcc_name; //TCHAR array
273 | }
274 |
275 | //DLL Imports. Need these to access various C style unmanaged functions contained in their respective DLL files.
276 | //--------------------------------------------------------------------------------------------------------------
277 | //Returns a HDEVINFO type for a device information set. We will need the
278 | //HDEVINFO as in input parameter for calling many of the other SetupDixxx() functions.
279 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
280 | internal static extern IntPtr SetupDiGetClassDevs(
281 | ref Guid ClassGuid, //LPGUID Input: Need to supply the class GUID.
282 | IntPtr Enumerator, //PCTSTR Input: Use NULL here, not important for our purposes
283 | IntPtr hwndParent, //HWND Input: Use NULL here, not important for our purposes
284 | uint Flags); //DWORD Input: Flags describing what kind of filtering to use.
285 |
286 | //Gives us "PSP_DEVICE_INTERFACE_DATA" which contains the Interface specific GUID (different
287 | //from class GUID). We need the interface GUID to get the device path.
288 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
289 | internal static extern bool SetupDiEnumDeviceInterfaces(
290 | IntPtr DeviceInfoSet, //Input: Give it the HDEVINFO we got from SetupDiGetClassDevs()
291 | IntPtr DeviceInfoData, //Input (optional)
292 | ref Guid InterfaceClassGuid, //Input
293 | uint MemberIndex, //Input: "Index" of the device you are interested in getting the path for.
294 | ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); //Output: This function fills in an "SP_DEVICE_INTERFACE_DATA" structure.
295 |
296 | //SetupDiDestroyDeviceInfoList() frees up memory by destroying a DeviceInfoList
297 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
298 | internal static extern bool SetupDiDestroyDeviceInfoList(
299 | IntPtr DeviceInfoSet); //Input: Give it a handle to a device info list to deallocate from RAM.
300 |
301 | //SetupDiEnumDeviceInfo() fills in an "SP_DEVINFO_DATA" structure, which we need for SetupDiGetDeviceRegistryProperty()
302 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
303 | internal static extern bool SetupDiEnumDeviceInfo(
304 | IntPtr DeviceInfoSet,
305 | uint MemberIndex,
306 | ref SP_DEVINFO_DATA DeviceInterfaceData);
307 |
308 | //SetupDiGetDeviceRegistryProperty() gives us the hardware ID, which we use to check to see if it has matching VID/PID
309 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
310 | internal static extern bool SetupDiGetDeviceRegistryProperty(
311 | IntPtr DeviceInfoSet,
312 | ref SP_DEVINFO_DATA DeviceInfoData,
313 | uint Property,
314 | ref uint PropertyRegDataType,
315 | IntPtr PropertyBuffer,
316 | uint PropertyBufferSize,
317 | ref uint RequiredSize);
318 |
319 | //SetupDiGetDeviceInterfaceDetail() gives us a device path, which is needed before CreateFile() can be used.
320 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
321 | internal static extern bool SetupDiGetDeviceInterfaceDetail(
322 | IntPtr DeviceInfoSet, //Input: Wants HDEVINFO which can be obtained from SetupDiGetClassDevs()
323 | ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, //Input: Pointer to an structure which defines the device interface.
324 | IntPtr DeviceInterfaceDetailData, //Output: Pointer to a SP_DEVICE_INTERFACE_DETAIL_DATA structure, which will receive the device path.
325 | uint DeviceInterfaceDetailDataSize, //Input: Number of bytes to retrieve.
326 | ref uint RequiredSize, //Output (optional): The number of bytes needed to hold the entire struct
327 | IntPtr DeviceInfoData); //Output (optional): Pointer to a SP_DEVINFO_DATA structure
328 |
329 | //Overload for SetupDiGetDeviceInterfaceDetail(). Need this one since we can't pass NULL pointers directly in C#.
330 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
331 | internal static extern bool SetupDiGetDeviceInterfaceDetail(
332 | IntPtr DeviceInfoSet, //Input: Wants HDEVINFO which can be obtained from SetupDiGetClassDevs()
333 | ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, //Input: Pointer to an structure which defines the device interface.
334 | IntPtr DeviceInterfaceDetailData, //Output: Pointer to a SP_DEVICE_INTERFACE_DETAIL_DATA structure, which will contain the device path.
335 | uint DeviceInterfaceDetailDataSize, //Input: Number of bytes to retrieve.
336 | IntPtr RequiredSize, //Output (optional): Pointer to a DWORD to tell you the number of bytes needed to hold the entire struct
337 | IntPtr DeviceInfoData); //Output (optional): Pointer to a SP_DEVINFO_DATA structure
338 |
339 | //Need this function for receiving all of the WM_DEVICECHANGE messages. See MSDN documentation for
340 | //description of what this function does/how to use it. Note: name is remapped "RegisterDeviceNotificationUM" to
341 | //avoid possible build error conflicts.
342 | [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
343 | internal static extern IntPtr RegisterDeviceNotification(
344 | IntPtr hRecipient,
345 | IntPtr NotificationFilter,
346 | uint Flags);
347 |
348 | //Takes in a device path and opens a handle to the device.
349 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
350 | static extern SafeFileHandle CreateFile(
351 | string lpFileName,
352 | uint dwDesiredAccess,
353 | uint dwShareMode,
354 | IntPtr lpSecurityAttributes,
355 | uint dwCreationDisposition,
356 | uint dwFlagsAndAttributes,
357 | IntPtr hTemplateFile);
358 |
359 | //Uses a handle (created with CreateFile()), and lets us write USB data to the device.
360 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
361 | static extern bool WriteFile(
362 | SafeFileHandle hFile,
363 | byte[] lpBuffer,
364 | uint nNumberOfBytesToWrite,
365 | ref uint lpNumberOfBytesWritten,
366 | IntPtr lpOverlapped);
367 |
368 | //Uses a handle (created with CreateFile()), and lets us read USB data from the device.
369 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
370 | static extern bool ReadFile(
371 | SafeFileHandle hFile,
372 | IntPtr lpBuffer,
373 | uint nNumberOfBytesToRead,
374 | ref uint lpNumberOfBytesRead,
375 | IntPtr lpOverlapped);
376 |
377 | //--------------- Global Varibles Section ------------------
378 | //USB related variables that need to have wide scope.
379 | //bool AttachedState = false; //Need to keep track of the USB device attachment status for proper plug and play operation.
380 | //bool AttachedButBroken = false;
381 |
382 | //String DevicePath = null; //Need the find the proper device path before you can open file handles.
383 |
384 | //Globally Unique Identifier (GUID) for HID class devices. Windows uses GUIDs to identify things.
385 | Guid InterfaceClassGuid = new Guid(0x4d1e55b2, 0xf16f, 0x11cf, 0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);
386 |
387 | private readonly IntPtr sourceHandle;
388 | private const int WM_COPYDATA = 0x004A;
389 |
390 | async void OnDeviceRemoved()
391 | {
392 | //Return immediately and do all the work asynchronously
393 | await Task.Yield();
394 | //Get a list with the device IDs of all removed devices
395 | List NewDeviceIdList = getDeviceIdList();
396 | List RemovedDeviceIdList = new List();
397 | foreach(string devId in DeviceIdList)
398 | {
399 | if (!NewDeviceIdList.Contains(devId))
400 | {
401 | RemovedDeviceIdList.Add(devId);
402 | }
403 | }
404 | //Get removed devices
405 | List RemovedDeviceList = new List();
406 | foreach(Device dev in DeviceList)
407 | {
408 | if(RemovedDeviceIdList.Contains(dev.DeviceID))
409 | {
410 | RemovedDeviceList.Add(dev);
411 | }
412 | }
413 | //Loop through removed devices
414 | foreach(Device removedDevice in RemovedDeviceList)
415 | {
416 | //Remove removedDevice from DeviceList
417 | DeviceList.Remove(removedDevice);
418 | //Remove removedDevice's device ID from DeviceIdList
419 | DeviceIdList.Remove(removedDevice.DeviceID);
420 | //Raise event if there are any subscribers
421 | if (RaiseDeviceRemovedEvent != null)
422 | {
423 | RaiseDeviceRemovedEvent(this, removedDevice);
424 | }
425 | }
426 | // Check if our device has been disconnected
427 | if (ConnectionStatus != UsbConnectionStatus.Disconnected)
428 | {
429 | String DevicePath = GetDevicePath(this.DeviceToConnectTo);
430 | // Try to connect if a device path has been obtained
431 | if (DevicePath == null)
432 | {
433 | CloseDevice();
434 | }
435 | }
436 | }
437 |
438 | async void OnDeviceAdded()
439 | {
440 | // Return immediately and do all the work asynchronously
441 | await Task.Yield();
442 | // Loop through devices
443 | List NewDeviceList = getDeviceList();
444 | foreach(Device dev in NewDeviceList)
445 | {
446 | if(!(DeviceIdList.Contains(dev.DeviceID)))
447 | {
448 | DeviceIdList.Add(dev.DeviceID);
449 | DeviceList.Add(dev);
450 | // Raise event if there are any subscribers
451 | if (RaiseDeviceAddedEvent!=null)
452 | {
453 | RaiseDeviceAddedEvent(this, dev);
454 | }
455 | }
456 | }
457 | // Try to connect to the device if we are not already connected
458 | if(ConnectionStatus!=UsbConnectionStatus.Connected)
459 | {
460 | SelectDevice(DeviceToConnectTo);
461 | }
462 | }
463 |
464 | private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
465 | {
466 | if (msg == UsbNotification.WmDevicechange)
467 | {
468 | switch ((int)wparam)
469 | {
470 | case UsbNotification.DbtDeviceremovecomplete:
471 | OnDeviceRemoved();
472 | break;
473 | case UsbNotification.DbtDevicearrival:
474 | OnDeviceAdded();
475 | break;
476 | }
477 | }
478 | return IntPtr.Zero;
479 | }
480 |
481 | private IntPtr CreateMessageOnlyWindow()
482 | {
483 | IntPtr HWND_MESSAGE = new IntPtr(-3);
484 | HwndSourceParameters sourceParam = new HwndSourceParameters() { ParentWindow = HWND_MESSAGE };
485 | HwndSource source = new HwndSource(sourceParam);
486 | source.AddHook(WndProc);
487 | return source.Handle;
488 | }
489 |
490 | //--------------- End of Global Varibles ------------------
491 |
492 | //public HidUtility(sendPacket_delegate sendPacket_h, packetSent_delegate packetSent_h, receivePacket_delegate receivePacket_h, packetReceived_delegate packetReceived_h)
493 | public HidUtility()
494 | {
495 | DeviceToConnectTo = new Device();
496 | DeviceIdList = getDeviceIdList();
497 | DeviceList = getDeviceList();
498 |
499 | sourceHandle = this.CreateMessageOnlyWindow();
500 | UsbNotification.RegisterUsbDeviceNotification(sourceHandle);
501 |
502 | UsbThread = new System.ComponentModel.BackgroundWorker();
503 | UsbThread.DoWork += new System.ComponentModel.DoWorkEventHandler(UsbThread_DoWork);
504 | UsbThread.RunWorkerAsync();
505 | }
506 |
507 | public void SelectDevice(Device dev)
508 | {
509 | // Save the device for future use
510 | this.DeviceToConnectTo = dev;
511 | // Close any device already connected
512 | CloseDevice();
513 | // Try to obtain a device path
514 | String DevicePath = GetDevicePath(this.DeviceToConnectTo);
515 | // Try to connect if a device path has been obtained
516 | if(DevicePath!=null)
517 | {
518 | OpenDevice(DevicePath);
519 | }
520 | }
521 |
522 | // Returns a list with the device IDs of all HID devices
523 | // Filters may be removed if a complete list of USB devices is desired
524 | private List getDeviceIdList()
525 | {
526 | List deviceIDs = new List();
527 | ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_USBControllerDevice");
528 | ManagementObjectCollection objs = searcher.Get();
529 | foreach (ManagementObject wmi_HD in objs)
530 | {
531 | string dep = wmi_HD["Dependent"].ToString();
532 | Match match = Regex.Match(dep, "\"(.+VID.+PID.+)\"$", RegexOptions.IgnoreCase);
533 | if (match.Success)
534 | {
535 | string devId = match.Groups[1].Value;
536 | devId = devId.Replace(@"\\", @"\");
537 | devId = devId.ToUpper();
538 | if(devId.Substring(0,3)=="HID")
539 | {
540 | deviceIDs.Add(devId);
541 | }
542 | }
543 | }
544 | return deviceIDs;
545 | }
546 |
547 | // Returns a list of Device object representing all devices returned by getDeviceIdList()
548 | private List getDeviceList()
549 | {
550 | List devices = new List();
551 | List deviceIDs = getDeviceIdList();
552 | ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity");
553 | ManagementObjectCollection objs = searcher.Get();
554 |
555 | foreach (ManagementObject wmi_HD in objs)
556 | {
557 | string deviceId = wmi_HD["DeviceID"].ToString();
558 | if (deviceIDs.Contains(deviceId))
559 | {
560 | string caption = wmi_HD["Caption"].ToString();
561 | Device dev = new Device(wmi_HD);
562 | devices.Add(dev);
563 | }
564 | }
565 | return devices;
566 | }
567 |
568 | private String GetDevicePath(Device dev)
569 | {
570 | /*
571 | Before we can "connect" our application to our USB embedded device, we must first find the device.
572 | A USB bus can have many devices simultaneously connected, so somehow we have to find our device only.
573 | This is done with the Vendor ID (VID) and Product ID (PID). Each USB product line should have
574 | a unique combination of VID and PID.
575 |
576 | Microsoft has created a number of functions which are useful for finding plug and play devices. Documentation
577 | for each function used can be found in the MSDN library. We will be using the following functions (unmanaged C functions):
578 |
579 | SetupDiGetClassDevs() //provided by setupapi.dll, which comes with Windows
580 | SetupDiEnumDeviceInterfaces() //provided by setupapi.dll, which comes with Windows
581 | GetLastError() //provided by kernel32.dll, which comes with Windows
582 | SetupDiDestroyDeviceInfoList() //provided by setupapi.dll, which comes with Windows
583 | SetupDiGetDeviceInterfaceDetail() //provided by setupapi.dll, which comes with Windows
584 | SetupDiGetDeviceRegistryProperty() //provided by setupapi.dll, which comes with Windows
585 | CreateFile() //provided by kernel32.dll, which comes with Windows
586 |
587 | In order to call these unmanaged functions, the Marshal class is very useful.
588 |
589 | We will also be using the following unusual data types and structures. Documentation can also be found in
590 | the MSDN library:
591 |
592 | PSP_DEVICE_INTERFACE_DATA
593 | PSP_DEVICE_INTERFACE_DETAIL_DATA
594 | SP_DEVINFO_DATA
595 | HDEVINFO
596 | HANDLE
597 | GUID
598 |
599 | The ultimate objective of the following code is to get the device path, which will be used elsewhere for getting
600 | read and write handles to the USB device. Once the read/write handles are opened, only then can this
601 | PC application begin reading/writing to the USB device using the WriteFile() and ReadFile() functions.
602 |
603 | Getting the device path is a multi-step round about process, which requires calling several of the
604 | SetupDixxx() functions provided by setupapi.dll.
605 | */
606 |
607 | //Device path we are trying to get
608 | String devicePath;
609 | // The device ID from the registry should contain this string (when ignoring upper/lower case)
610 | string DeviceIdSubstring = string.Format("Vid_{0:X4}&Pid_{1:X4}", dev.Vid, dev.Pid);
611 | DeviceIdSubstring = DeviceIdSubstring.ToLowerInvariant();
612 | // The device path should contain this string (when ignoring upper/lower case)
613 | string DevicePathSubstring = dev.DeviceID.Replace(@"\", @"#");
614 | DevicePathSubstring = DevicePathSubstring.ToLowerInvariant();
615 |
616 | try
617 | {
618 | IntPtr DeviceInfoTable = IntPtr.Zero;
619 | SP_DEVICE_INTERFACE_DATA InterfaceDataStructure = new SP_DEVICE_INTERFACE_DATA();
620 | SP_DEVICE_INTERFACE_DETAIL_DATA DetailedInterfaceDataStructure = new SP_DEVICE_INTERFACE_DETAIL_DATA();
621 | SP_DEVINFO_DATA DevInfoData = new SP_DEVINFO_DATA();
622 |
623 | uint InterfaceIndex = 0;
624 | uint dwRegType = 0;
625 | uint dwRegSize = 0;
626 | uint dwRegSize2 = 0;
627 | uint StructureSize = 0;
628 | IntPtr PropertyValueBuffer = IntPtr.Zero;
629 | uint ErrorStatus;
630 | uint LoopCounter = 0;
631 |
632 | //First populate a list of plugged in devices (by specifying "DIGCF_PRESENT"), which are of the specified class GUID.
633 | DeviceInfoTable = SetupDiGetClassDevs(ref InterfaceClassGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
634 |
635 | if (DeviceInfoTable != IntPtr.Zero)
636 | {
637 | //Now look through the list we just populated. We are trying to see if any of them match our device.
638 | while (true)
639 | {
640 | InterfaceDataStructure.cbSize = (uint)Marshal.SizeOf(InterfaceDataStructure);
641 | if (SetupDiEnumDeviceInterfaces(DeviceInfoTable, IntPtr.Zero, ref InterfaceClassGuid, InterfaceIndex, ref InterfaceDataStructure))
642 | {
643 | ErrorStatus = (uint)Marshal.GetLastWin32Error();
644 | if (ErrorStatus == ERROR_NO_MORE_ITEMS) //Did we reach the end of the list of matching devices in the DeviceInfoTable?
645 | { //Cound not find the device. Must not have been attached.
646 | SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
647 | return null;
648 | }
649 | }
650 | else //Else some other kind of unknown error ocurred...
651 | {
652 | ErrorStatus = (uint)Marshal.GetLastWin32Error();
653 | SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
654 | return null;
655 | }
656 |
657 | //Now retrieve the hardware ID from the registry. The hardware ID contains the VID and PID, which we will then
658 | //check to see if it is the correct device or not.
659 |
660 | //Initialize an appropriate SP_DEVINFO_DATA structure. We need this structure for SetupDiGetDeviceRegistryProperty().
661 | DevInfoData.cbSize = (uint)Marshal.SizeOf(DevInfoData);
662 | SetupDiEnumDeviceInfo(DeviceInfoTable, InterfaceIndex, ref DevInfoData);
663 |
664 | //First query for the size of the hardware ID, so we can know how big a buffer to allocate for the data.
665 | SetupDiGetDeviceRegistryProperty(DeviceInfoTable, ref DevInfoData, SPDRP_HARDWAREID, ref dwRegType, IntPtr.Zero, 0, ref dwRegSize);
666 |
667 | //Allocate a buffer for the hardware ID.
668 | //Should normally work, but could throw exception "OutOfMemoryException" if not enough resources available.
669 | PropertyValueBuffer = Marshal.AllocHGlobal((int)dwRegSize);
670 |
671 | //Retrieve the hardware IDs for the current device we are looking at. PropertyValueBuffer gets filled with a
672 | //REG_MULTI_SZ (array of null terminated strings). To find a device, we only care about the very first string in the
673 | //buffer, which will be the "device ID". The device ID is a string which contains the VID and PID, in the example
674 | //format "Vid_04d8&Pid_003f".
675 | SetupDiGetDeviceRegistryProperty(DeviceInfoTable, ref DevInfoData, SPDRP_HARDWAREID, ref dwRegType, PropertyValueBuffer, dwRegSize, ref dwRegSize2);
676 |
677 | //Now check if the first string in the hardware ID matches the device ID of the USB device we are trying to find.
678 | String DeviceIDFromRegistry = Marshal.PtrToStringUni(PropertyValueBuffer); //Make a new string, fill it with the contents from the PropertyValueBuffer
679 |
680 | Marshal.FreeHGlobal(PropertyValueBuffer); //No longer need the PropertyValueBuffer, free the memory to prevent potential memory leaks
681 |
682 | //Now check if the hardware ID we are looking at contains the correct VID/PID (ignore upper/lower case)
683 | if (DeviceIDFromRegistry.ToLowerInvariant().Contains(DeviceIdSubstring))
684 | {
685 | //Device must have been found. In order to open I/O file handle(s), we will need the actual device path first.
686 | //We can get the path by calling SetupDiGetDeviceInterfaceDetail(), however, we have to call this function twice: The first
687 | //time to get the size of the required structure/buffer to hold the detailed interface data, then a second time to actually
688 | //get the structure (after we have allocated enough memory for the structure.)
689 | DetailedInterfaceDataStructure.cbSize = (uint)Marshal.SizeOf(DetailedInterfaceDataStructure);
690 | //First call populates "StructureSize" with the correct value
691 | SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, ref InterfaceDataStructure, IntPtr.Zero, 0, ref StructureSize, IntPtr.Zero);
692 | //Need to call SetupDiGetDeviceInterfaceDetail() again, this time specifying a pointer to a SP_DEVICE_INTERFACE_DETAIL_DATA buffer with the correct size of RAM allocated.
693 | //First need to allocate the unmanaged buffer and get a pointer to it.
694 | IntPtr pUnmanagedDetailedInterfaceDataStructure = IntPtr.Zero; //Declare a pointer.
695 | pUnmanagedDetailedInterfaceDataStructure = Marshal.AllocHGlobal((int)StructureSize); //Reserve some unmanaged memory for the structure.
696 | DetailedInterfaceDataStructure.cbSize = 6; //Initialize the cbSize parameter (4 bytes for DWORD + 2 bytes for unicode null terminator)
697 | Marshal.StructureToPtr(DetailedInterfaceDataStructure, pUnmanagedDetailedInterfaceDataStructure, false); //Copy managed structure contents into the unmanaged memory buffer.
698 |
699 | //Now call SetupDiGetDeviceInterfaceDetail() a second time to receive the device path in the structure at pUnmanagedDetailedInterfaceDataStructure.
700 | if (SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, ref InterfaceDataStructure, pUnmanagedDetailedInterfaceDataStructure, StructureSize, IntPtr.Zero, IntPtr.Zero))
701 | {
702 | //Need to extract the path information from the unmanaged "structure". The path starts at (pUnmanagedDetailedInterfaceDataStructure + sizeof(DWORD)).
703 | IntPtr pToDevicePath = new IntPtr((uint)pUnmanagedDetailedInterfaceDataStructure.ToInt32() + 4); //Add 4 to the pointer (to get the pointer to point to the path, instead of the DWORD cbSize parameter)
704 | devicePath = Marshal.PtrToStringUni(pToDevicePath); //Now copy the path information into the globally defined DevicePath String.
705 |
706 | //Now check if the device path we are looking at contains the substring (ignore upper/lower case)
707 | if(devicePath.ToLowerInvariant().Contains(DevicePathSubstring))
708 | {
709 | //We now have the proper device path, and we can finally use the path to open I/O handle(s) to the device.
710 | SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure we no longer need.
711 | Marshal.FreeHGlobal(pUnmanagedDetailedInterfaceDataStructure); //No longer need this unmanaged SP_DEVICE_INTERFACE_DETAIL_DATA buffer. We already extracted the path information.
712 | return devicePath; //Returning the device path
713 | }
714 | }
715 | else //Some unknown failure occurred
716 | {
717 | uint ErrorCode = (uint)Marshal.GetLastWin32Error();
718 | SetupDiDestroyDeviceInfoList(DeviceInfoTable); //Clean up the old structure.
719 | Marshal.FreeHGlobal(pUnmanagedDetailedInterfaceDataStructure); //No longer need this unmanaged SP_DEVICE_INTERFACE_DETAIL_DATA buffer. We already extracted the path information.
720 | return null;
721 | }
722 | }
723 |
724 | InterfaceIndex++;
725 | //Keep looping until we either find a device with matching VID and PID, or until we run out of devices to check.
726 | //However, just in case some unexpected error occurs, keep track of the number of loops executed.
727 | //If the number of loops exceeds a very large number, exit anyway, to prevent inadvertent infinite looping.
728 | LoopCounter++;
729 | if (LoopCounter == 10000) //Surely there aren't more than 10'000 devices attached to any forseeable PC...
730 | {
731 | return null;
732 | }
733 | }//end of while(true)
734 | }
735 | return null;
736 | }//end of try
737 | catch
738 | {
739 | //Something went wrong if PC gets here. Maybe a Marshal.AllocHGlobal() failed due to insufficient resources or something.
740 | return null;
741 | }
742 | } //findDevice
743 |
744 |
745 | public void UsbThread_DoWork(object sender, DoWorkEventArgs e)
746 | {
747 | byte[] OutBufferArray = new byte[65];
748 | byte[] InBufferArray = new byte[65];
749 | UsbBuffer OutBuffer = new UsbBuffer(OutBufferArray);
750 | UsbBuffer InBuffer = new UsbBuffer(InBufferArray);
751 | uint BytesWritten = 0;
752 | uint BytesRead = 0;
753 |
754 | while (true)
755 | {
756 | //Do not try to use the read/write handles unless the USB device is attached and ready
757 | if (ConnectionStatus == UsbConnectionStatus.Connected)
758 | {
759 |
760 | // Raise SendPacket event if there are any subscribers
761 | if (RaiseSendPacketEvent != null)
762 | {
763 | //Ask the application if a packet should be sent and let it prepare the data to be sent
764 | RaiseSendPacketEvent(this, OutBuffer);
765 | }
766 |
767 | //Send packet if the application requested so
768 | if(OutBuffer.RequestTransfer)
769 | {
770 | try
771 | {
772 | /*
773 | byte[] buf = new byte[65];
774 | buf[0] = OutBuffer.buffer[0];
775 | buf[1] = OutBuffer.buffer[1];
776 | buf[2] = OutBuffer.buffer[2];
777 | */
778 | OutBuffer.TransferSuccessful = WriteFile(WriteHandleToUSBDevice, OutBufferArray, 65, ref BytesWritten, IntPtr.Zero);
779 | }
780 | catch
781 | {
782 | OutBuffer.TransferSuccessful = false;
783 | }
784 |
785 | // A packet has been sent (or the transfer has failed)
786 | // Inform the application by raising a PacketSent event if there are any subscribers
787 | if (RaisePacketSentEvent != null)
788 | {
789 | RaisePacketSentEvent(this, OutBuffer);
790 | }
791 | }
792 |
793 | // Raise ReceivePacket event if there are any subscribers
794 | if (RaiseReceivePacketEvent != null)
795 | {
796 | // Ask the application if a packet should be requested
797 | RaiseReceivePacketEvent(this, InBuffer);
798 | }
799 |
800 | // Receive packet if the application requested so
801 | if (InBuffer.RequestTransfer)
802 | {
803 | try
804 | {
805 | InBuffer.TransferSuccessful = ReadFileManagedBuffer(ReadHandleToUSBDevice, InBufferArray, 65, ref BytesRead, IntPtr.Zero);
806 | }
807 | catch
808 | {
809 | InBuffer.TransferSuccessful = false;
810 | }
811 |
812 | // A packet has been received (or the transfer has failed)
813 | // Inform the application by raising a PacketReceived event if there are any subscribers
814 | if (RaisePacketReceivedEvent != null)
815 | {
816 | RaisePacketReceivedEvent(this, InBuffer);
817 | }
818 | }
819 |
820 |
821 | } // end of: if(AttachedState == true)
822 | else
823 | {
824 | Thread.Sleep(5); // Add a small delay to avoid unnecessary CPU utilization
825 | }
826 | } // end of while(true) loop
827 | } // end of ReadWriteThread_DoWork
828 |
829 |
830 | //--------------------------------------------------------------------------------------------------------------------------
831 | //FUNCTION: ReadFileManagedBuffer()
832 | //PURPOSE: Wrapper function to call ReadFile()
833 | //
834 | //INPUT: Uses managed versions of the same input parameters as ReadFile() uses.
835 | //
836 | //OUTPUT: Returns boolean indicating if the function call was successful or not.
837 | // Also returns data in the byte[] INBuffer, and the number of bytes read.
838 | //
839 | //Notes: Wrapper function used to call the ReadFile() function. ReadFile() takes a pointer to an unmanaged buffer and deposits
840 | // the bytes read into the buffer. However, can't pass a pointer to a managed buffer directly to ReadFile().
841 | // This ReadFileManagedBuffer() is a wrapper function to make it so application code can call ReadFile() easier
842 | // by specifying a managed buffer.
843 | //--------------------------------------------------------------------------------------------------------------------------
844 | public unsafe bool ReadFileManagedBuffer(SafeFileHandle hFile, byte[] INBuffer, uint nNumberOfBytesToRead, ref uint lpNumberOfBytesRead, IntPtr lpOverlapped)
845 | {
846 | IntPtr pINBuffer = IntPtr.Zero;
847 |
848 | try
849 | {
850 | pINBuffer = Marshal.AllocHGlobal((int)nNumberOfBytesToRead); //Allocate some unmanged RAM for the receive data buffer.
851 |
852 | if (ReadFile(hFile, pINBuffer, nNumberOfBytesToRead, ref lpNumberOfBytesRead, lpOverlapped))
853 | {
854 | Marshal.Copy(pINBuffer, INBuffer, 0, (int)lpNumberOfBytesRead); //Copy over the data from unmanged memory into the managed byte[] INBuffer
855 | Marshal.FreeHGlobal(pINBuffer);
856 | return true;
857 | }
858 | else
859 | {
860 | Marshal.FreeHGlobal(pINBuffer);
861 | return false;
862 | }
863 |
864 | }
865 | catch
866 | {
867 | if (pINBuffer != IntPtr.Zero)
868 | {
869 | Marshal.FreeHGlobal(pINBuffer);
870 | }
871 | return false;
872 | }
873 | }
874 |
875 |
876 |
877 | public void OpenDevice(String DevicePath)
878 | {
879 | uint ErrorStatusWrite;
880 | uint ErrorStatusRead;
881 | // Close device first
882 | CloseDevice();
883 | // Open WriteHandle
884 | WriteHandleToUSBDevice = CreateFile(DevicePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
885 | ErrorStatusWrite = (uint)Marshal.GetLastWin32Error();
886 | // Open ReadHandle
887 | ReadHandleToUSBDevice = CreateFile(DevicePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
888 | ErrorStatusRead = (uint)Marshal.GetLastWin32Error();
889 | // Check if both handles were opened successfully
890 | if ((ErrorStatusWrite == ERROR_SUCCESS) && (ErrorStatusRead == ERROR_SUCCESS))
891 | {
892 | ConnectionStatus = UsbConnectionStatus.Connected;
893 | }
894 | else // For some reason the device was physically plugged in, but one or both of the read/write handles didn't open successfully
895 | {
896 | ConnectionStatus = UsbConnectionStatus.NotWorking;
897 | if (ErrorStatusWrite == ERROR_SUCCESS)
898 | {
899 | WriteHandleToUSBDevice.Close();
900 | }
901 |
902 | if (ErrorStatusRead == ERROR_SUCCESS)
903 | {
904 | ReadHandleToUSBDevice.Close();
905 | }
906 | }
907 | // Raise event if there are any subscribers
908 | if (RaiseConnectionStatusChangedEvent != null)
909 | {
910 | RaiseConnectionStatusChangedEvent(this, new ConnectionStatusEventArgs(ConnectionStatus));
911 | }
912 | // Start async thread if connection has been established
913 | if (ConnectionStatus == UsbConnectionStatus.Connected)
914 | {
915 | //UsbThread.RunWorkerAsync();
916 | }
917 | }
918 |
919 | // Close connection to the USB device
920 | public void CloseDevice()
921 | {
922 | // Save current status
923 | UsbConnectionStatus previousStatus = ConnectionStatus;
924 | // Close write and read handles if a device is connected
925 | if (ConnectionStatus==UsbConnectionStatus.Connected)
926 | {
927 | WriteHandleToUSBDevice.Close();
928 | ReadHandleToUSBDevice.Close();
929 | }
930 | // Set status to disconnected
931 | ConnectionStatus = UsbConnectionStatus.Disconnected;
932 | // Stop async thread if connection has been established
933 | //UsbThread.CancelAsync();
934 | // Raise event if the status has changed and if there are any subscribers
935 | if (ConnectionStatus!=previousStatus)
936 | {
937 | if (RaiseConnectionStatusChangedEvent != null)
938 | {
939 | RaiseConnectionStatusChangedEvent(this, new ConnectionStatusEventArgs(ConnectionStatus));
940 | }
941 | }
942 | }
943 |
944 |
945 | }//hid_utility
946 |
947 | } //namespace hid
--------------------------------------------------------------------------------