├── CH340BConfigure
├── CH340BConfigure.ico
├── output
│ └── CH340BConfigure.exe
├── App.config
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── CH340BConfigure.sln
├── CH340BConfigurationData.cs
├── Program.cs
├── CH340BConfigure.csproj
├── UiForm.Designer.cs
├── UiForm.cs
├── NativeAccess.cs
├── UiForm.resx
└── CH340BDeviceAccess.cs
├── README.md
├── LICENSE
├── .github
└── workflows
│ └── dotnet-desktop.yml
└── .gitignore
/CH340BConfigure/CH340BConfigure.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/senthilnathant/tools-ch340b-configuration/HEAD/CH340BConfigure/CH340BConfigure.ico
--------------------------------------------------------------------------------
/CH340BConfigure/output/CH340BConfigure.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/senthilnathant/tools-ch340b-configuration/HEAD/CH340BConfigure/output/CH340BConfigure.exe
--------------------------------------------------------------------------------
/CH340BConfigure/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CH340BConfigure/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tools-ch340b-configuration
2 |
3 | This CH340B Configuration Utility is a .Net Framework WinForms Application - a configuration utility built especially for WCH (WinChipHead) USB-UART Bridge chip - CH340B. The CH340B is a USB to UART Bridge that can be used to provide the Virtual Serial Port interface through USB.
4 |
5 | With this application you can read and update the configuration data of CH340B.
6 |
7 | The configuration data such as Vendor ID, Product ID, Product Name, Serial Number can be read / modified and written to the CH340B chip. This application requires .Net Framework 4.7.2 or above.
8 |
9 | The source code can be compiled on Microsoft Visual Studio 2019 or above with C# .Net Framework 4.7.2 or above.
10 |
11 | This is a free and open source software provided under MIT License.
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/CH340BConfigure/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 |
12 | namespace CH340BConfigure.Properties
13 | {
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
17 | {
18 |
19 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
20 |
21 | public static Settings Default
22 | {
23 | get
24 | {
25 | return defaultInstance;
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/CH340BConfigure/CH340BConfigure.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31911.196
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH340BConfigure", "CH340BConfigure.csproj", "{4CA137FF-16E2-44CA-A27C-81672E1067B1}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {4CA137FF-16E2-44CA-A27C-81672E1067B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {4CA137FF-16E2-44CA-A27C-81672E1067B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {4CA137FF-16E2-44CA-A27C-81672E1067B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {4CA137FF-16E2-44CA-A27C-81672E1067B1}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {D6A6FB74-9ADA-4EEB-AFDF-8987C55BC35B}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/CH340BConfigure/CH340BConfigurationData.cs:
--------------------------------------------------------------------------------
1 | // *********************************************************************************************************
2 | //
3 | // Project : WCH CH340B Configuration Utility
4 | // FileName : CH340BConfigurationData.cs
5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER
6 | // Co-Author(s) :
7 | // Created : 02 January, 2022
8 | //
9 | // *********************************************************************************************************
10 | //
11 | // Module Description
12 | //
13 | // This class declares the Configuration data such as VID, PID, Product String and Serial number of CH340B
14 | // *********************************************************************************************************
15 | //
16 | // History
17 | //
18 | // Date Version Author Changes
19 | //
20 | // 02 January, 2022 1.0.0 SENTHILNATHAN THANGAVEL Initial version
21 | //
22 | // *********************************************************************************************************
23 | namespace CH340BConfigure
24 | {
25 | public class CH340BConfigurationData
26 | {
27 | public ushort ushVID;
28 | public ushort ushPID;
29 | public string szProductString;
30 | public string szSerialNumber;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CH340BConfigure/Program.cs:
--------------------------------------------------------------------------------
1 | // *********************************************************************************************************
2 | //
3 | // Project : WCH CH340B Configuration Utility
4 | // FileName : Program.cs
5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER
6 | // Co-Author(s) :
7 | // Created : 20 December, 2021
8 | //
9 | // *********************************************************************************************************
10 | //
11 | // Module Description
12 | //
13 | // IDE generated code - main entry point of the application
14 | // *********************************************************************************************************
15 | //
16 | // History
17 | //
18 | // Date Version Author Changes
19 | //
20 | // 20 December, 2021 1.0.0 SENTHILNATHAN THANGAVEL Initial version
21 | //
22 | // *********************************************************************************************************
23 | using System;
24 | using System.Windows.Forms;
25 |
26 | namespace CH340BConfigure
27 | {
28 | static class Program
29 | {
30 | ///
31 | /// The main entry point for the application.
32 | ///
33 | [STAThread]
34 | static void Main()
35 | {
36 | Application.EnableVisualStyles();
37 | Application.SetCompatibleTextRenderingDefault(false);
38 | Application.Run(new UiForm());
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/CH340BConfigure/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("CH340B Configuration Utility")]
9 | [assembly: AssemblyDescription("CH340B Configuration Utility")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER")]
12 | [assembly: AssemblyProduct("CH340B Configuration Utility")]
13 | [assembly: AssemblyCopyright("Copyright © 2021, SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER")]
14 | [assembly: AssemblyTrademark("SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER")]
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("4ca137ff-16e2-44ca-a27c-81672e1067b1")]
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("0.1.0.0")]
36 | [assembly: AssemblyFileVersion("0.1.0.0")]
37 |
--------------------------------------------------------------------------------
/CH340BConfigure/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 |
12 | namespace CH340BConfigure.Properties
13 | {
14 | ///
15 | /// A strongly-typed resource class, for looking up localized strings, etc.
16 | ///
17 | // This class was auto-generated by the StronglyTypedResourceBuilder
18 | // class via a tool like ResGen or Visual Studio.
19 | // To add or remove a member, edit your .ResX file then rerun ResGen
20 | // with the /str option, or rebuild your VS project.
21 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
22 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
23 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
24 | internal class Resources
25 | {
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 | ///
37 | /// Returns the cached ResourceManager instance used by this class.
38 | ///
39 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
40 | internal static global::System.Resources.ResourceManager ResourceManager
41 | {
42 | get
43 | {
44 | if ((resourceMan == null))
45 | {
46 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CH340BConfigure.Properties.Resources", typeof(Resources).Assembly);
47 | resourceMan = temp;
48 | }
49 | return resourceMan;
50 | }
51 | }
52 |
53 | ///
54 | /// Overrides the current thread's CurrentUICulture property for all
55 | /// resource lookups using this strongly typed resource class.
56 | ///
57 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
58 | internal static global::System.Globalization.CultureInfo Culture
59 | {
60 | get
61 | {
62 | return resourceCulture;
63 | }
64 | set
65 | {
66 | resourceCulture = value;
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/CH340BConfigure/CH340BConfigure.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {4CA137FF-16E2-44CA-A27C-81672E1067B1}
8 | WinExe
9 | CH340BConfigure
10 | CH340BConfigure
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | CH340BConfigure.ico
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | Form
56 |
57 |
58 | UiForm.cs
59 |
60 |
61 |
62 |
63 |
64 | UiForm.cs
65 |
66 |
67 | ResXFileCodeGenerator
68 | Resources.Designer.cs
69 | Designer
70 |
71 |
72 | True
73 | Resources.resx
74 |
75 |
76 | SettingsSingleFileGenerator
77 | Settings.Designer.cs
78 |
79 |
80 | True
81 | Settings.settings
82 | True
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-desktop.yml:
--------------------------------------------------------------------------------
1 | # This workflow uses actions that are not certified by GitHub.
2 | # They are provided by a third-party and are governed by
3 | # separate terms of service, privacy policy, and support
4 | # documentation.
5 |
6 | # This workflow will build, test, sign and package a WPF or Windows Forms desktop application
7 | # built on .NET Core.
8 | # To learn how to migrate your existing application to .NET Core,
9 | # refer to https://docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework
10 | #
11 | # To configure this workflow:
12 | #
13 | # 1. Configure environment variables
14 | # GitHub sets default environment variables for every workflow run.
15 | # Replace the variables relative to your project in the "env" section below.
16 | #
17 | # 2. Signing
18 | # Generate a signing certificate in the Windows Application
19 | # Packaging Project or add an existing signing certificate to the project.
20 | # Next, use PowerShell to encode the .pfx file using Base64 encoding
21 | # by running the following Powershell script to generate the output string:
22 | #
23 | # $pfx_cert = Get-Content '.\SigningCertificate.pfx' -Encoding Byte
24 | # [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt'
25 | #
26 | # Open the output file, SigningCertificate_Encoded.txt, and copy the
27 | # string inside. Then, add the string to the repo as a GitHub secret
28 | # and name it "Base64_Encoded_Pfx."
29 | # For more information on how to configure your signing certificate for
30 | # this workflow, refer to https://github.com/microsoft/github-actions-for-desktop-apps#signing
31 | #
32 | # Finally, add the signing certificate password to the repo as a secret and name it "Pfx_Key".
33 | # See "Build the Windows Application Packaging project" below to see how the secret is used.
34 | #
35 | # For more information on GitHub Actions, refer to https://github.com/features/actions
36 | # For a complete CI/CD sample to get started with GitHub Action workflows for Desktop Applications,
37 | # refer to https://github.com/microsoft/github-actions-for-desktop-apps
38 |
39 | name: .NET Core Desktop
40 |
41 | on:
42 | push:
43 | branches: [ "main" ]
44 | pull_request:
45 | branches: [ "main" ]
46 |
47 | jobs:
48 |
49 | build:
50 |
51 | strategy:
52 | matrix:
53 | configuration: [Debug, Release]
54 |
55 | runs-on: windows-latest # For a list of available runner types, refer to
56 | # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
57 |
58 | env:
59 | Solution_Name: your-solution-name # Replace with your solution name, i.e. MyWpfApp.sln.
60 | Test_Project_Path: your-test-project-path # Replace with the path to your test project, i.e. MyWpfApp.Tests\MyWpfApp.Tests.csproj.
61 | Wap_Project_Directory: your-wap-project-directory-name # Replace with the Wap project directory relative to the solution, i.e. MyWpfApp.Package.
62 | Wap_Project_Path: your-wap-project-path # Replace with the path to your Wap project, i.e. MyWpf.App.Package\MyWpfApp.Package.wapproj.
63 |
64 | steps:
65 | - name: Checkout
66 | uses: actions/checkout@v3
67 | with:
68 | fetch-depth: 0
69 |
70 | # Install the .NET Core workload
71 | - name: Install .NET Core
72 | uses: actions/setup-dotnet@v3
73 | with:
74 | dotnet-version: 6.0.x
75 |
76 | # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
77 | - name: Setup MSBuild.exe
78 | uses: microsoft/setup-msbuild@v1.0.2
79 |
80 | # Execute all unit tests in the solution
81 | - name: Execute unit tests
82 | run: dotnet test
83 |
84 | # Restore the application to populate the obj folder with RuntimeIdentifiers
85 | - name: Restore the application
86 | run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration
87 | env:
88 | Configuration: ${{ matrix.configuration }}
89 |
90 | # Decode the base 64 encoded pfx and save the Signing_Certificate
91 | - name: Decode the pfx
92 | run: |
93 | $pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.Base64_Encoded_Pfx }}")
94 | $certificatePath = Join-Path -Path $env:Wap_Project_Directory -ChildPath GitHubActionsWorkflow.pfx
95 | [IO.File]::WriteAllBytes("$certificatePath", $pfx_cert_byte)
96 |
97 | # Create the app package by building and packaging the Windows Application Packaging project
98 | - name: Create the app package
99 | run: msbuild $env:Wap_Project_Path /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:Appx_Package_Build_Mode /p:AppxBundle=$env:Appx_Bundle /p:PackageCertificateKeyFile=GitHubActionsWorkflow.pfx /p:PackageCertificatePassword=${{ secrets.Pfx_Key }}
100 | env:
101 | Appx_Bundle: Always
102 | Appx_Bundle_Platforms: x86|x64
103 | Appx_Package_Build_Mode: StoreUpload
104 | Configuration: ${{ matrix.configuration }}
105 |
106 | # Remove the pfx
107 | - name: Remove the pfx
108 | run: Remove-Item -path $env:Wap_Project_Directory\GitHubActionsWorkflow.pfx
109 |
110 | # Upload the MSIX package: https://github.com/marketplace/actions/upload-a-build-artifact
111 | - name: Upload build artifacts
112 | uses: actions/upload-artifact@v3
113 | with:
114 | name: MSIX Package
115 | path: ${{ env.Wap_Project_Directory }}\AppPackages
116 |
--------------------------------------------------------------------------------
/CH340BConfigure/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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 |
--------------------------------------------------------------------------------
/CH340BConfigure/UiForm.Designer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace CH340BConfigure
3 | {
4 | partial class UiForm
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 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UiForm));
33 | this.groupBox2 = new System.Windows.Forms.GroupBox();
34 | this.buttonUpdateDevList = new System.Windows.Forms.Button();
35 | this.comboBoxDeviceList = new System.Windows.Forms.ComboBox();
36 | this.groupBoxConfigControls = new System.Windows.Forms.GroupBox();
37 | this.labelStatus = new System.Windows.Forms.Label();
38 | this.buttonWrite = new System.Windows.Forms.Button();
39 | this.buttonRead = new System.Windows.Forms.Button();
40 | this.textBoxSerialNumber = new System.Windows.Forms.TextBox();
41 | this.label3 = new System.Windows.Forms.Label();
42 | this.textBoxProductString = new System.Windows.Forms.TextBox();
43 | this.label4 = new System.Windows.Forms.Label();
44 | this.textBoxPid = new System.Windows.Forms.TextBox();
45 | this.label2 = new System.Windows.Forms.Label();
46 | this.textBoxVid = new System.Windows.Forms.TextBox();
47 | this.label1 = new System.Windows.Forms.Label();
48 | this.groupBox2.SuspendLayout();
49 | this.groupBoxConfigControls.SuspendLayout();
50 | this.SuspendLayout();
51 | //
52 | // groupBox2
53 | //
54 | this.groupBox2.Controls.Add(this.buttonUpdateDevList);
55 | this.groupBox2.Controls.Add(this.comboBoxDeviceList);
56 | this.groupBox2.Location = new System.Drawing.Point(12, 12);
57 | this.groupBox2.Name = "groupBox2";
58 | this.groupBox2.Size = new System.Drawing.Size(367, 55);
59 | this.groupBox2.TabIndex = 22;
60 | this.groupBox2.TabStop = false;
61 | this.groupBox2.Text = "CH340B Devices";
62 | //
63 | // buttonUpdateDevList
64 | //
65 | this.buttonUpdateDevList.Location = new System.Drawing.Point(270, 19);
66 | this.buttonUpdateDevList.Name = "buttonUpdateDevList";
67 | this.buttonUpdateDevList.Size = new System.Drawing.Size(85, 23);
68 | this.buttonUpdateDevList.TabIndex = 1;
69 | this.buttonUpdateDevList.Text = "Update";
70 | this.buttonUpdateDevList.UseVisualStyleBackColor = true;
71 | this.buttonUpdateDevList.Click += new System.EventHandler(this.buttonUpdateDevList_Click);
72 | //
73 | // comboBoxDeviceList
74 | //
75 | this.comboBoxDeviceList.AllowDrop = true;
76 | this.comboBoxDeviceList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
77 | this.comboBoxDeviceList.FormattingEnabled = true;
78 | this.comboBoxDeviceList.Location = new System.Drawing.Point(12, 20);
79 | this.comboBoxDeviceList.Name = "comboBoxDeviceList";
80 | this.comboBoxDeviceList.Size = new System.Drawing.Size(249, 21);
81 | this.comboBoxDeviceList.TabIndex = 0;
82 | this.comboBoxDeviceList.SelectedIndexChanged += new System.EventHandler(this.comboBoxDeviceList_SelectedIndexChanged);
83 | //
84 | // groupBoxConfigControls
85 | //
86 | this.groupBoxConfigControls.Controls.Add(this.labelStatus);
87 | this.groupBoxConfigControls.Controls.Add(this.buttonWrite);
88 | this.groupBoxConfigControls.Controls.Add(this.buttonRead);
89 | this.groupBoxConfigControls.Controls.Add(this.textBoxSerialNumber);
90 | this.groupBoxConfigControls.Controls.Add(this.label3);
91 | this.groupBoxConfigControls.Controls.Add(this.textBoxProductString);
92 | this.groupBoxConfigControls.Controls.Add(this.label4);
93 | this.groupBoxConfigControls.Controls.Add(this.textBoxPid);
94 | this.groupBoxConfigControls.Controls.Add(this.label2);
95 | this.groupBoxConfigControls.Controls.Add(this.textBoxVid);
96 | this.groupBoxConfigControls.Controls.Add(this.label1);
97 | this.groupBoxConfigControls.Location = new System.Drawing.Point(12, 76);
98 | this.groupBoxConfigControls.Name = "groupBoxConfigControls";
99 | this.groupBoxConfigControls.Size = new System.Drawing.Size(367, 203);
100 | this.groupBoxConfigControls.TabIndex = 23;
101 | this.groupBoxConfigControls.TabStop = false;
102 | this.groupBoxConfigControls.Text = "Configure CH340B";
103 | //
104 | // labelStatus
105 | //
106 | this.labelStatus.AutoSize = true;
107 | this.labelStatus.Location = new System.Drawing.Point(9, 170);
108 | this.labelStatus.Name = "labelStatus";
109 | this.labelStatus.Size = new System.Drawing.Size(40, 13);
110 | this.labelStatus.TabIndex = 10;
111 | this.labelStatus.Text = "Status:";
112 | //
113 | // buttonWrite
114 | //
115 | this.buttonWrite.Location = new System.Drawing.Point(270, 165);
116 | this.buttonWrite.Name = "buttonWrite";
117 | this.buttonWrite.Size = new System.Drawing.Size(85, 23);
118 | this.buttonWrite.TabIndex = 9;
119 | this.buttonWrite.Text = "Write";
120 | this.buttonWrite.UseVisualStyleBackColor = true;
121 | this.buttonWrite.Click += new System.EventHandler(this.buttonWrite_Click);
122 | //
123 | // buttonRead
124 | //
125 | this.buttonRead.Location = new System.Drawing.Point(176, 165);
126 | this.buttonRead.Name = "buttonRead";
127 | this.buttonRead.Size = new System.Drawing.Size(85, 23);
128 | this.buttonRead.TabIndex = 8;
129 | this.buttonRead.Text = "Read";
130 | this.buttonRead.UseVisualStyleBackColor = true;
131 | this.buttonRead.Click += new System.EventHandler(this.buttonRead_Click);
132 | //
133 | // textBoxSerialNumber
134 | //
135 | this.textBoxSerialNumber.Location = new System.Drawing.Point(139, 130);
136 | this.textBoxSerialNumber.MaxLength = 8;
137 | this.textBoxSerialNumber.Name = "textBoxSerialNumber";
138 | this.textBoxSerialNumber.Size = new System.Drawing.Size(216, 20);
139 | this.textBoxSerialNumber.TabIndex = 7;
140 | //
141 | // label3
142 | //
143 | this.label3.AutoSize = true;
144 | this.label3.Location = new System.Drawing.Point(9, 133);
145 | this.label3.Name = "label3";
146 | this.label3.Size = new System.Drawing.Size(117, 13);
147 | this.label3.TabIndex = 6;
148 | this.label3.Text = "Serial Number (8 chars)";
149 | //
150 | // textBoxProductString
151 | //
152 | this.textBoxProductString.Location = new System.Drawing.Point(139, 95);
153 | this.textBoxProductString.MaxLength = 18;
154 | this.textBoxProductString.Name = "textBoxProductString";
155 | this.textBoxProductString.Size = new System.Drawing.Size(216, 20);
156 | this.textBoxProductString.TabIndex = 5;
157 | //
158 | // label4
159 | //
160 | this.label4.AutoSize = true;
161 | this.label4.Location = new System.Drawing.Point(9, 98);
162 | this.label4.Name = "label4";
163 | this.label4.Size = new System.Drawing.Size(124, 13);
164 | this.label4.TabIndex = 4;
165 | this.label4.Text = "Product String (18 chars)";
166 | //
167 | // textBoxPid
168 | //
169 | this.textBoxPid.Location = new System.Drawing.Point(139, 60);
170 | this.textBoxPid.Name = "textBoxPid";
171 | this.textBoxPid.Size = new System.Drawing.Size(216, 20);
172 | this.textBoxPid.TabIndex = 3;
173 | //
174 | // label2
175 | //
176 | this.label2.AutoSize = true;
177 | this.label2.Location = new System.Drawing.Point(9, 63);
178 | this.label2.Name = "label2";
179 | this.label2.Size = new System.Drawing.Size(99, 13);
180 | this.label2.TabIndex = 2;
181 | this.label2.Text = "Product ID (PID) 0x";
182 | //
183 | // textBoxVid
184 | //
185 | this.textBoxVid.Location = new System.Drawing.Point(139, 25);
186 | this.textBoxVid.Name = "textBoxVid";
187 | this.textBoxVid.Size = new System.Drawing.Size(216, 20);
188 | this.textBoxVid.TabIndex = 1;
189 | //
190 | // label1
191 | //
192 | this.label1.AutoSize = true;
193 | this.label1.Location = new System.Drawing.Point(9, 28);
194 | this.label1.Name = "label1";
195 | this.label1.Size = new System.Drawing.Size(96, 13);
196 | this.label1.TabIndex = 0;
197 | this.label1.Text = "Vendor ID (VID) 0x";
198 | //
199 | // Form1
200 | //
201 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
202 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
203 | this.ClientSize = new System.Drawing.Size(392, 291);
204 | this.Controls.Add(this.groupBoxConfigControls);
205 | this.Controls.Add(this.groupBox2);
206 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
207 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
208 | this.MaximizeBox = false;
209 | this.Name = "Form1";
210 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
211 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
212 | this.Text = "CH340B Configuration Utility";
213 | this.groupBox2.ResumeLayout(false);
214 | this.groupBoxConfigControls.ResumeLayout(false);
215 | this.groupBoxConfigControls.PerformLayout();
216 | this.ResumeLayout(false);
217 |
218 | }
219 |
220 | #endregion
221 |
222 | private System.Windows.Forms.GroupBox groupBox2;
223 | private System.Windows.Forms.Button buttonUpdateDevList;
224 | private System.Windows.Forms.ComboBox comboBoxDeviceList;
225 | private System.Windows.Forms.GroupBox groupBoxConfigControls;
226 | private System.Windows.Forms.TextBox textBoxVid;
227 | private System.Windows.Forms.Label label1;
228 | private System.Windows.Forms.Button buttonWrite;
229 | private System.Windows.Forms.Button buttonRead;
230 | private System.Windows.Forms.TextBox textBoxSerialNumber;
231 | private System.Windows.Forms.Label label3;
232 | private System.Windows.Forms.TextBox textBoxProductString;
233 | private System.Windows.Forms.Label label4;
234 | private System.Windows.Forms.TextBox textBoxPid;
235 | private System.Windows.Forms.Label label2;
236 | private System.Windows.Forms.Label labelStatus;
237 | }
238 | }
239 |
240 |
--------------------------------------------------------------------------------
/CH340BConfigure/UiForm.cs:
--------------------------------------------------------------------------------
1 | // *********************************************************************************************************
2 | //
3 | // Project : WCH CH340B Configuration Utility
4 | // FileName : UiForm.cs
5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER
6 | // Co-Author(s) :
7 | // Created : 20 December, 2021
8 | //
9 | // *********************************************************************************************************
10 | //
11 | // Module Description
12 | //
13 | // This is the main user interface form which is displayed when the
14 | // executble is run. This has the ui button controls and event handlers, input / output text box controls.
15 | // This module will detect the CH340B devices connected to the PC and list the detected devices on its ui
16 | // combo box control. Based on the Read/Write function selected this module would send the Read / Write
17 | // request to the selected device in the device list.
18 | // *********************************************************************************************************
19 | //
20 | // History
21 | //
22 | // Date Version Author Changes
23 | //
24 | // 20 December, 2021 1.0.0 SENTHILNATHAN THANGAVEL Initial version
25 | // 02 January, 2022 1.0.1 SENTHILNATHAN THANGAVEL Code restructured to provide good modularity
26 | //
27 | // *********************************************************************************************************
28 | using System;
29 | using System.Text;
30 | using System.Windows.Forms;
31 |
32 | namespace CH340BConfigure
33 | {
34 | public partial class UiForm : Form
35 | {
36 | // Number of CH340B devices connected to the PC
37 | private int nNumberOfDevices = 0;
38 | // Device index tracking when a new device is selected in the device list combo box
39 | private int nSelectedDeviceIndex = 0;
40 | // CH340BDeviceAccess object - this will have the device information, device detection function,
41 | // configuration data read/write functions
42 | private CH340BDeviceAccess oCH340BDeviceAccess = new CH340BDeviceAccess();
43 |
44 | public UiForm()
45 | {
46 | // IDE generated
47 | InitializeComponent();
48 | // This closing handler does nothing now
49 | this.FormClosing += Form1_FormClosing;
50 | // Call the SearchAndListCh340BDevices - i.e look for devices and list them
51 | buttonUpdateDevList_Click(null, null);
52 | }
53 |
54 | private void Form1_FormClosing(object sender, FormClosingEventArgs e)
55 | {
56 |
57 | }
58 |
59 | /*
60 | * Function Name: buttonUpdateDevList_Click
61 | * Description: UpdateDevList button click event handler
62 | */
63 | private void buttonUpdateDevList_Click(object sender, EventArgs e)
64 | {
65 | // Init the ui contorls state
66 | buttonUpdateDevList.Enabled = false;
67 | groupBoxConfigControls.Enabled = false;
68 | // Look for the CH340B devices and list them on the device list combo box
69 | SearchAndListCh340BDevices();
70 | buttonUpdateDevList.Enabled = true;
71 | if (nNumberOfDevices > 0)
72 | {
73 | groupBoxConfigControls.Enabled = true;
74 | }
75 | else
76 | {
77 | groupBoxConfigControls.Enabled = false;
78 | }
79 | labelStatus.Text = "";
80 | }
81 |
82 | /*
83 | * Function Name: SearchAndListCh340BDevices
84 | * Description: This function detects the CH340B devices and list them on the combo boxes
85 | */
86 | private void SearchAndListCh340BDevices()
87 | {
88 | // If there is already a list of devices, free the list of device and resources allocated
89 | comboBoxDeviceList.Items.Clear();
90 | // Look for the CH340B devices connected to the System
91 | nNumberOfDevices = oCH340BDeviceAccess.FindDevices();
92 | if (nNumberOfDevices > 0)
93 | {
94 | // Add the CH340B devices detected to the combobox
95 | for (int i = 0; i < nNumberOfDevices; i++)
96 | {
97 | comboBoxDeviceList.Items.Insert(i, oCH340BDeviceAccess.aoDevInfo[i].szDeviceName);
98 | }
99 | comboBoxDeviceList.SelectedIndex = 0;
100 | nSelectedDeviceIndex = 0;
101 | }
102 | }
103 |
104 | /*
105 | * Function Name: comboBoxDeviceList_SelectedIndexChanged
106 | * Description: This function is the Combobox Device List index changed handler
107 | */
108 | private void comboBoxDeviceList_SelectedIndexChanged(object sender, EventArgs e)
109 | {
110 | // Store the selected index to the device index variable
111 | nSelectedDeviceIndex = comboBoxDeviceList.SelectedIndex;
112 | }
113 |
114 | /*
115 | * Function Name: buttonRead_Click
116 | * Description: This function is buttonRead click event handler
117 | */
118 | private void buttonRead_Click(object sender, EventArgs e)
119 | {
120 | bool bResult = false;
121 | buttonRead.Enabled = false;
122 | textBoxVid.Text = "";
123 | textBoxPid.Text = "";
124 | textBoxProductString.Text = "";
125 | textBoxSerialNumber.Text = "";
126 |
127 | buttonRead.Enabled = false;
128 |
129 | try
130 | {
131 | labelStatus.Text = "";
132 | CH340BConfigurationData oCH340BConfigurationData = new CH340BConfigurationData();
133 | bResult = oCH340BDeviceAccess.ReadConfigurationData(nSelectedDeviceIndex, ref oCH340BConfigurationData);
134 | // Display the configuration data to the UI
135 | if (bResult)
136 | {
137 | textBoxVid.Text = oCH340BConfigurationData.ushVID.ToString("X4");
138 | textBoxPid.Text = oCH340BConfigurationData.ushPID.ToString("X4");
139 | textBoxProductString.Text = oCH340BConfigurationData.szProductString;
140 | textBoxSerialNumber.Text = oCH340BConfigurationData.szSerialNumber;
141 | // Update the Read status
142 | labelStatus.Text = "Status: Read Success";
143 | }
144 | else
145 | {
146 | // Update the Read status
147 | labelStatus.Text = "Status: Read Failed";
148 | }
149 | }
150 | catch (Exception ex)
151 | {
152 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK,
153 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
154 | }
155 |
156 | buttonRead.Enabled = true;
157 | }
158 |
159 | /*
160 | * Function Name: buttonWrite_Click
161 | * Description: This function is buttonWrite click event handler
162 | */
163 | private void buttonWrite_Click(object sender, EventArgs e)
164 | {
165 | ushort ushVID = 0x0000;
166 | ushort ushPID = 0x0000;
167 | string szProductString = "";
168 | string szSerialNumber = "";
169 | bool bResult = false;
170 | labelStatus.Text = "";
171 | buttonWrite.Enabled = false;
172 |
173 | do
174 | {
175 | // Validate VID
176 | try
177 | {
178 | string szVID = textBoxVid.Text;
179 | ushVID = Convert.ToUInt16(szVID, 16);
180 | }
181 | catch (Exception)
182 | {
183 | MessageBox.Show("Enter valid value for Vendor ID in hex.", "CH340B Configuration Utlity", MessageBoxButtons.OK,
184 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
185 | break;
186 | }
187 |
188 | // Validate PID
189 | try
190 | {
191 | string szPID = textBoxPid.Text;
192 | ushPID = Convert.ToUInt16(szPID, 16);
193 | }
194 | catch (Exception)
195 | {
196 | MessageBox.Show("Enter valid value for Product ID in hex.", "CH340B Configuration Utlity", MessageBoxButtons.OK,
197 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
198 | break;
199 | }
200 |
201 | // Validate Product string
202 | try
203 | {
204 | szProductString = textBoxProductString.Text;
205 | if (string.IsNullOrEmpty(szProductString))
206 | {
207 | MessageBox.Show("Enter valid string value for Product String.", "CH340B Configuration Utlity", MessageBoxButtons.OK,
208 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
209 | break;
210 | }
211 | }
212 | catch (Exception)
213 | {
214 | MessageBox.Show("Enter valid string value for Product String.", "CH340B Configuration Utlity", MessageBoxButtons.OK,
215 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
216 | break;
217 | }
218 |
219 | // Validate Serial Number
220 | try
221 | {
222 | szSerialNumber = textBoxSerialNumber.Text;
223 | if (string.IsNullOrEmpty(szSerialNumber) == false)
224 | {
225 | byte[] abySerialNumber = Encoding.ASCII.GetBytes(szSerialNumber);
226 |
227 | for (int i = 0; i < abySerialNumber.Length; i++)
228 | {
229 | if ((abySerialNumber[i] >= 0x30 && abySerialNumber[i] <= 0x39) || (abySerialNumber[i] >= 0x41 && abySerialNumber[i] <= 0x5A) ||
230 | (abySerialNumber[i] >= 0x61 && abySerialNumber[i] <= 0x7A))
231 | {
232 | // Valid serial number string
233 | }
234 | else
235 | {
236 | MessageBox.Show("Enter valid string value for Serial Number.", "CH340B Configuration Utlity", MessageBoxButtons.OK,
237 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
238 | break;
239 | }
240 | }
241 | }
242 | }
243 | catch (Exception)
244 | {
245 | MessageBox.Show("Enter valid string value for Product String.", "CH340B Configuration Utlity", MessageBoxButtons.OK,
246 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
247 | break;
248 | }
249 |
250 | // Write the configuration data to CH340B
251 | CH340BConfigurationData oCH340BConfigurationData = new CH340BConfigurationData();
252 | oCH340BConfigurationData.ushVID = ushVID;
253 | oCH340BConfigurationData.ushPID = ushPID;
254 | oCH340BConfigurationData.szProductString = szProductString;
255 | oCH340BConfigurationData.szSerialNumber = szSerialNumber;
256 | bResult = oCH340BDeviceAccess.WriteConfigurationData(nSelectedDeviceIndex, oCH340BConfigurationData);
257 |
258 | // Update the Write status
259 | if (bResult)
260 | {
261 | labelStatus.Text = "Status: Write Success";
262 | }
263 | else
264 | {
265 | labelStatus.Text = "Status: Write Failed";
266 | }
267 | } while (false);
268 |
269 | buttonWrite.Enabled = true;
270 | }
271 | }
272 | }
273 |
--------------------------------------------------------------------------------
/CH340BConfigure/NativeAccess.cs:
--------------------------------------------------------------------------------
1 | // *********************************************************************************************************
2 | //
3 | // Project : WCH CH340B Configuration Utility
4 | // FileName : NativeAccess.cs
5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER
6 | // Co-Author(s) :
7 | // Created : 02 January, 2022
8 | //
9 | // *********************************************************************************************************
10 | //
11 | // Module Description
12 | //
13 | // This module has classes that contain managed version of Win32 native structs, constants, native methods
14 | // Here C# .Net Framework's Platform Invoke (P/Invoke) interoperability service is used to call the
15 | // native unmanaged Win32 APIs.
16 | // *********************************************************************************************************
17 | //
18 | // History
19 | //
20 | // Date Version Author Changes
21 | //
22 | // 02 January, 2022 1.0.0 SENTHILNATHAN THANGAVEL Initial version
23 | //
24 | // *********************************************************************************************************
25 | using System;
26 | using System.Runtime.InteropServices;
27 |
28 | namespace CH340BConfigure
29 | {
30 | public class NativeAccess
31 | {
32 | internal class NativeStructs
33 | {
34 | [StructLayout(LayoutKind.Sequential)]
35 | internal class SP_DEVINFO_DATA
36 | {
37 | public Int32 cbSize;
38 | public Guid ClassGuid;
39 | public Int32 DevInst;
40 | public IntPtr Reserved;
41 | }
42 |
43 | [StructLayout(LayoutKind.Sequential)]
44 | internal class SP_DEVICE_INTERFACE_DETAIL_DATA
45 | {
46 | public Int32 cbSize;
47 |
48 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)]
49 | public byte[] DevicePath;
50 | }
51 |
52 | [StructLayout(LayoutKind.Sequential)]
53 | internal class SP_DEVICE_INTERFACE_DATA
54 | {
55 | public Int32 cbSize;
56 | public System.Guid InterfaceClassGuid;
57 | public Int32 Flags;
58 | public UIntPtr Reserved;
59 | }
60 |
61 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
62 | internal class OVERLAPPED
63 | {
64 | public IntPtr InternalLow;
65 | public IntPtr InternalHigh;
66 | public long Offset;
67 | public IntPtr hEvent;
68 | }
69 |
70 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
71 | internal class SERIAL_COMMPROP
72 | {
73 | public UInt16 PacketLength;
74 | public UInt16 PacketVersion;
75 | public UInt32 ServiceMask;
76 | public UInt32 Reserved1;
77 | public UInt32 MaxTxQueue;
78 | public UInt32 MaxRxQueue;
79 | public UInt32 MaxBaud;
80 | public UInt32 ProvSubType;
81 | public UInt32 ProvCapabilities;
82 | public UInt32 SettableParams;
83 | public UInt32 SettableBaud;
84 | public UInt16 SettableData;
85 | public UInt16 SettableStopParity;
86 | public UInt32 CurrentTxQueue;
87 | public UInt32 CurrentRxQueue;
88 | public UInt32 ProvSpec1;
89 | public UInt32 ProvSpec2;
90 | public IntPtr ProvChar;
91 | }
92 |
93 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
94 | internal class SERIAL_QUEUE_SIZE
95 | {
96 | public UInt32 InSize;
97 | public UInt32 OutSize;
98 | }
99 |
100 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
101 | internal class SERIAL_TIMEOUTS
102 | {
103 | public UInt32 ReadIntervalTimeout;
104 | public UInt32 ReadTotalTimeoutMultiplier;
105 | public UInt32 ReadTotalTimeoutConstant;
106 | public UInt32 WriteTotalTimeoutMultiplier;
107 | public UInt32 WriteTotalTimeoutConstant;
108 | }
109 |
110 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
111 | internal class SERIAL_BAUD_RATE
112 | {
113 | public UInt32 BaudRate;
114 | }
115 |
116 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
117 | internal class SERIAL_LINE_CONTROL
118 | {
119 | public Byte StopBits;
120 | public Byte Parity;
121 | public Byte WordLength;
122 | }
123 |
124 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
125 | internal class SERIAL_CHARS
126 | {
127 | public Byte EofChar;
128 | public Byte ErrorChar;
129 | public Byte BreakChar;
130 | public Byte EventChar;
131 | public Byte XonChar;
132 | public Byte XoffChar;
133 | }
134 |
135 | [StructLayout(LayoutKind.Sequential, Pack = 8)]
136 | internal class SERIAL_HANDFLOW
137 | {
138 | public UInt32 ControlHandShake;
139 | public UInt32 FlowReplace;
140 | public Int32 XonLimit;
141 | public Int32 XoffLimit;
142 | }
143 | }
144 |
145 | internal class Constants
146 | {
147 | // Define constants
148 | // internal const uint INVALID_HANDLE_VALUE = 0xFFFFFFFF;
149 | internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
150 |
151 | internal const uint ERROR_INVALID_HANDLE = 0x00000006;
152 | internal const uint ERROR_INSUFFICIENT_BUFFER = 122;
153 |
154 | internal const uint GENERIC_READ = 0x80000000;
155 | internal const uint GENERIC_WRITE = 0x40000000;
156 | internal const uint FILE_SHARE_READ = 0x00000001;
157 | internal const uint FILE_SHARE_WRITE = 0x00000002;
158 |
159 | internal const uint FILE_FLAG_OVERLAPPED = 0x40000000;
160 | internal const uint OPEN_EXISTING = 0x00000003;
161 |
162 | internal const uint NO_ERROR = 0x00000000;
163 | internal const uint STATUS_SUCCESS = 0x00000000;
164 |
165 | internal const uint DIGCF_DEFAULT = 0x00000001;
166 | internal const uint DIGCF_PRESENT = 0x00000002;
167 | internal const uint DIGCF_ALLCLASSES = 0x00000004;
168 | internal const uint DIGCF_PROFILE = 0x00000008;
169 | internal const uint DIGCF_DEVICEINTERFACE = 0x00000010;
170 |
171 | internal const UInt32 ERROR_IO_PENDING = 997;
172 | internal const UInt32 INFINITE = 0xFFFFFFFF;
173 | internal const UInt32 WAIT_ABANDONED = 0x00000080;
174 | internal const UInt32 WAIT_OBJECT_0 = 0x00000000;
175 | internal const UInt32 WAIT_TIMEOUT = 0x00000102;
176 |
177 | internal const UInt32 IOCTL_SERIAL_GET_PROPERTIES = 0x1b0074;
178 | internal const UInt32 IOCTL_SERIAL_SET_QUEUE_SIZE = 0x1b0008;
179 | internal const UInt32 IOCTL_SERIAL_GET_TIMEOUTS = 0x1b0020;
180 | internal const UInt32 IOCTL_SERIAL_SET_TIMEOUTS = 0x1b001c;
181 | internal const UInt32 IOCTL_SERIAL_PURGE = 0x1b004c;
182 | internal const UInt32 IOCTL_SERIAL_GET_BAUD_RATE = 0x1b0050;
183 | internal const UInt32 IOCTL_SERIAL_GET_LINE_CONTROL = 0x1b0054;
184 | internal const UInt32 IOCTL_SERIAL_GET_CHARS = 0x1b0058;
185 | internal const UInt32 IOCTL_SERIAL_GET_HANDFLOW = 0x1b0060;
186 | internal const UInt32 IOCTL_SERIAL_SET_BAUD_RATE = 0x1b0004;
187 | internal const UInt32 IOCTL_SERIAL_SET_RTS = 0x1b0030;
188 | internal const UInt32 IOCTL_SERIAL_SET_DTR = 0x1b0024;
189 | internal const UInt32 IOCTL_SERIAL_SET_LINE_CONTROL = 0x1b000c;
190 | internal const UInt32 IOCTL_SERIAL_SET_CHARS = 0x1b005c;
191 | internal const UInt32 IOCTL_SERIAL_SET_HANDFLOW = 0x1b0064;
192 |
193 | internal enum SPDRP
194 | {
195 | SPDRP_DEVICEDESC = 0,
196 | SPDRP_HARDWAREID = 0x1,
197 | SPDRP_COMPATIBLEIDS = 0x2,
198 | SPDRP_UNUSED0 = 0x3,
199 | SPDRP_SERVICE = 0x4,
200 | SPDRP_UNUSED1 = 0x5,
201 | SPDRP_UNUSED2 = 0x6,
202 | SPDRP_CLASS = 0x7,
203 | SPDRP_CLASSGUID = 0x8,
204 | SPDRP_DRIVER = 0x9,
205 | SPDRP_CONFIGFLAGS = 0xa,
206 | SPDRP_MFG = 0xb,
207 | SPDRP_FRIENDLYNAME = 0xc,
208 | SPDRP_LOCATION_INFORMATION = 0xd,
209 | SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0xe,
210 | SPDRP_CAPABILITIES = 0xf,
211 | SPDRP_UI_NUMBER = 0x10,
212 | SPDRP_UPPERFILTERS = 0x11,
213 | SPDRP_LOWERFILTERS = 0x12,
214 | SPDRP_BUSTYPEGUID = 0x13,
215 | SPDRP_LEGACYBUSTYPE = 0x14,
216 | SPDRP_BUSNUMBER = 0x15,
217 | SPDRP_ENUMERATOR_NAME = 0x16,
218 | SPDRP_SECURITY = 0x17,
219 | SPDRP_SECURITY_SDS = 0x18,
220 | SPDRP_DEVTYPE = 0x19,
221 | SPDRP_EXCLUSIVE = 0x1a,
222 | SPDRP_CHARACTERISTICS = 0x1b,
223 | SPDRP_ADDRESS = 0x1c,
224 | SPDRP_UI_NUMBER_DESC_FORMAT = 0x1e,
225 | SPDRP_MAXIMUM_PROPERTY = 0x1f
226 |
227 | }
228 | }
229 |
230 | internal class NativeMethods
231 | {
232 | [DllImport("hid.dll", CharSet = CharSet.Unicode, SetLastError = true)]
233 | internal static extern void HidD_GetHidGuid(ref System.Guid HidGuid);
234 |
235 | [DllImport("hid.dll", CharSet = CharSet.Unicode, SetLastError = true)]
236 | internal static extern Boolean HidD_SetOutputReport(IntPtr HidDeviceObject, Byte[] lpReportBuffer,
237 | Int32 ReportBufferLength);
238 |
239 | [DllImport("hid.dll", CharSet = CharSet.Unicode, SetLastError = true)]
240 | internal static extern Boolean HidD_SetFeature(IntPtr HidDeviceObject, Byte[] lpReportBuffer,
241 | Int32 ReportBufferLength);
242 |
243 | [DllImport("hid.dll", CharSet = CharSet.Unicode, SetLastError = true)]
244 | internal static extern Boolean HidD_GetFeature(IntPtr HidDeviceObject, [Out] byte[] lpBuffer, Int32 ReportBufferLength);
245 |
246 | [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
247 | internal static extern IntPtr SetupDiGetClassDevs(ref System.Guid ClassGuid,
248 | IntPtr Enumerator, IntPtr hwndParent, UInt32 Flags);
249 |
250 | [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
251 | public static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
252 |
253 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
254 | internal static extern Boolean SetupDiEnumDeviceInfo(IntPtr hDevInfo,
255 | uint uintDeviceID, IntPtr psDeviceInfoData);
256 |
257 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
258 | internal static extern Boolean SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet,
259 | IntPtr psDeviceInfoData, uint Property, ref uint PropertyRegDataType, IntPtr pchBuffer,
260 | uint uintBufferSize, ref uint untBufferSize);
261 |
262 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
263 | internal static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet,
264 | IntPtr DeviceInfoData, ref System.Guid InterfaceClassGuid,
265 | uint MemberIndex, IntPtr psDeviceInterfaceData);
266 |
267 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
268 | internal static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo,
269 | IntPtr pspDeviceInterfaceData,
270 | IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize,
271 | IntPtr DeviceInfoData);
272 |
273 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
274 | internal static extern uint GetLastError();
275 |
276 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
277 | internal static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess,
278 | UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition,
279 | UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);
280 |
281 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
282 | internal static extern Boolean CloseHandle(IntPtr pHandle);
283 |
284 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
285 | internal static extern Boolean WriteFile(IntPtr pHandle, Byte[] lpReportBuffer,
286 | uint unReportBufferSize, ref UInt32 lpBytesReturned, IntPtr lpOverlapped);
287 |
288 | [DllImport("kernel32.dll", SetLastError = true)]
289 | internal static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, ref uint lpNumberOfBytesRead, IntPtr lpOverlapped);
290 |
291 | [DllImport("hid.dll", SetLastError = true)]
292 | internal static extern Boolean HidD_GetInputReport(IntPtr hFileHandle, byte[] reportBuffer, uint reportBufferLength);
293 |
294 | [DllImport("kernel32.dll")]
295 | internal static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
296 |
297 | [DllImport("kernel32.dll", SetLastError = true)]
298 | internal static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
299 |
300 | [DllImport("kernel32.dll")]
301 | internal static extern bool ResetEvent(IntPtr hEvent);
302 |
303 | [DllImport("kernel32.dll")]
304 | [return: MarshalAs(UnmanagedType.Bool)]
305 | internal static extern bool CancelIo(IntPtr hFile);
306 |
307 | [DllImport("kernel32.dll")]
308 | internal static extern bool SetEvent(IntPtr hEvent);
309 |
310 |
311 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
312 | internal static extern bool DeviceIoControl(IntPtr hDevice, uint ioControlCode,
313 | [MarshalAs(UnmanagedType.LPArray)][In] byte[] inBuffer, int ninBufferSize,
314 | [MarshalAs(UnmanagedType.LPArray)][Out] byte[] outBuffer, int noutBufferSize,
315 | out uint bytesReturned, [In] IntPtr overlapped);
316 |
317 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
318 | internal static extern bool DeviceIoControl(IntPtr hDevice, uint ioControlCode, IntPtr inBuffer, int ninBufferSize,
319 | IntPtr outBuffer, int noutBufferSize, out uint bytesReturned, [In] IntPtr overlapped);
320 |
321 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
322 | internal static extern bool DeviceIoControl(IntPtr hDevice, uint ioControlCode, byte[] inBuffer, int ninBufferSize,
323 | IntPtr outBuffer, int noutBufferSize, out uint bytesReturned, [In] IntPtr overlapped);
324 |
325 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
326 | internal static extern bool DeviceIoControl(IntPtr hDevice, uint ioControlCode, IntPtr inBuffer, int ninBufferSize,
327 | byte[] outBuffer, int noutBufferSize, out uint bytesReturned, [In] IntPtr overlapped);
328 |
329 | }
330 | }
331 | }
332 |
--------------------------------------------------------------------------------
/CH340BConfigure/UiForm.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 |
122 |
123 | AAABAAYAEBAQAAAAAAAoAQAAZgAAABAQAAAAAAAAaAUAAI4BAAAgIBAAAAAAAOgCAAD2BgAAICAAAAAA
124 | AACoCAAA3gkAADAwAAAAAAAAqA4AAIYSAAAwMBAAAAAAAGgGAAAuIQAAKAAAABAAAAAgAAAAAQAEAAAA
125 | AADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAAAAAIAAAICAAIAAgACAgIAAwMDAAAD/
126 | AAD/AAAA//8AAAAA/wAA//8A/wD/AP///wAAAAAHcAAAAAeAAP+NkAAAB4B3j4mIAAAHgHiICbsAAAeA
127 | eIsAiAAAB/B7i9+IAAAH8Ie73/iIgAfwiH3YB3eAB3CId3d3d4B/94h4iIiIcAd3eHIiIi9wAAf/ciIi
128 | L3AAAHdyIiIvcAAAAHKiIi9wAAAAcqqqr3AAAAB/////cIwfAACADwAAgAcAAIAHAACABwAAgAEAAIAA
129 | AACAAAAAgAAAAAAAAACAAAAA4AAAAPAAAAD8AAAA/AAAAPwAAAAoAAAAEAAAACAAAAABAAgAAAAAAEAB
130 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAgAAAgIAAAAAAgACAAIAAAICAAMDAwADA3MAApsrwAAQE
131 | BAAICAgADAwMABEREQAWFhYAHBwcACIiIgApKSkAVVVVAE1NTQBCQkIAOTk5AP98gAD/UFAA1gCTAMzs
132 | /wDv1sYA5+fWAK2pkAAzAAAAZgAAAJkAAADMAAAAADMAADMzAABmMwAAmTMAAMwzAAD/MwAAAGYAADNm
133 | AABmZgAAmWYAAMxmAAD/ZgAAAJkAADOZAABmmQAAmZkAAMyZAAD/mQAAAMwAADPMAABmzAAAmcwAAMzM
134 | AAD/zAAAZv8AAJn/AADM/wAAAAAzADMAMwBmADMAmQAzAMwAMwD/ADMAADMzADMzMwBmMzMAmTMzAMwz
135 | MwD/MzMAAGYzADNmMwBmZjMAmWYzAMxmMwD/ZjMAAJkzADOZMwBmmTMAmZkzAMyZMwD/mTMAAMwzADPM
136 | MwBmzDMAmcwzAMzMMwD/zDMAM/8zAGb/MwCZ/zMAzP8zAP//MwAAAGYAMwBmAGYAZgCZAGYAzABmAP8A
137 | ZgAAM2YAMzNmAGYzZgCZM2YAzDNmAP8zZgAAZmYAM2ZmAGZmZgCZZmYAzGZmAACZZgAzmWYAZplmAJmZ
138 | ZgDMmWYA/5lmAADMZgAzzGYAmcxmAMzMZgD/zGYAAP9mADP/ZgCZ/2YAzP9mAP8AzADMAP8AAJmZAJkz
139 | mQCZAJkAzACZAAAAmQAzM5kAZgCZAMwzmQD/AJkAAGaZADNmmQBmM5kAmWaZAMxmmQD/M5kAM5mZAGaZ
140 | mQCZmZkAzJmZAP+ZmQAAzJkAM8yZAGbMZgCZzJkAzMyZAP/MmQAA/5kAM/+ZAGbMmQCZ/5kAzP+ZAP//
141 | mQAAAMwAMwCZAGYAzACZAMwAzADMAAAzmQAzM8wAZjPMAJkzzADMM8wA/zPMAABmzAAzZswAZmaZAJlm
142 | zADMZswA/2aZAACZzAAzmcwAZpnMAJmZzADMmcwA/5nMAADMzAAzzMwAZszMAJnMzADMzMwA/8zMAAD/
143 | zAAz/8wAZv+ZAJn/zADM/8wA///MADMAzABmAP8AmQD/AAAzzAAzM/8AZjP/AJkz/wDMM/8A/zP/AABm
144 | /wAzZv8AZmbMAJlm/wDMZv8A/2bMAACZ/wAzmf8AZpn/AJmZ/wDMmf8A/5n/AADM/wAzzP8AZsz/AJnM
145 | /wDMzP8A/8z/ADP//wBm/8wAmf//AMz//wD/ZmYAZv9mAP//ZgBmZv8A/2b/AGb//wClACEAX19fAHd3
146 | dwCGhoYAlpaWAMvLywCysrIA19fXAN3d3QDj4+MA6urqAPHx8QD4+PgA//vwAKCgpACAgIAA/wAAAAD/
147 | AAD//wAAAAD/AP8A/wAA//8A////AAAAAAAAAAAAAAAAAAAAAAAA7AcAAOz//wf++gAAAAAAAOwHAOwH
148 | B/8H+gcHAAAAAADsBwDsBwcHAPr7+wAAAAAA7AcA7AcH+wAABwcAAAAAAOz/AOz7B/v+/wcHAAAAAADs
149 | /wAH7Pv7/v//AAcHBwAA7P8ABwcAAAAAAOzs7AcAAOzsAAcH7Ozs7Ozs7OwHAOz//+wHB+wHBwcHBwcH
150 | 7AAA7Ozs7Afsb3pSMU1M/+wAAAAA7P//7G/lelIxTf/sAAAAAADs7Oxv5eV6UjH/7AAAAAAAAADsb3rl
151 | 5XpS/+wAAAAAAAAA7G9MTExMTP/sAAAAAAAAAOzw8PDw8PDw7ACMHwAAgA8AAIAHAACABwAAgAcAAIAB
152 | AACAAAAAgAAAAIAAAAAAAAAAgAAAAOAAAADwAAAA/AAAAPwAAAD8AAAAKAAAACAAAABAAAAAAQAEAAAA
153 | AACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAAAAAIAAAICAAIAAgACAgIAAwMDAAAD/
154 | AAD/AAAA//8AAAAA/wAA//8A/wD/AP///wAAAAAAAAAAB3cAAAAAAAAAAAAAAAAAB3iN3ZAAAAAAAAB4
155 | +PAAAH+PiN2ZkAAAAAAAf4+AcAeH+P3ZmYgAAAAAAHj48IcHeH+I2ZiIAAAAAAB/j4B4d4eH+NmIi7AA
156 | AAAAePjwh3h4eHAJi7uwAAAAAH+PgHh3h4cAALu4gAAAAAB4+PCHeIi7AAB4eHAAAAAAf4+AeHi7ibAH
157 | h4eAAAAAAH//8Id7uJu9/3h4cAAAAAB///B4d4m7vfj3hwAAAAAAf//wh4ebu92Pj3gIiIgAAH//8IiI
158 | e73diPjwAACIcAB///CIiAd93YiAB3d3iHAAf//wiIgP93d3f/////9wAHd3cIiIB3d3d3d3d3d4cAB3
159 | d3CIiAAAAAAAAAAAAIAH///3CIgHiIiIiIiIiIcAd3d3d3CIB/////////+HAAAAB3d3CAfyIiIiIiIv
160 | hwAAAAB3d3AH8riDMzqqL4cAAAAAB///B/L7iDMzqi+HAAAAAAB3d3Dyv7iDMzovhwAAAAAAAAAH8vv7
161 | iDMzL4cAAAAAAAAAB/K/v7iDMy+HAAAAAAAAAAfyi/v7iDMvhwAAAAAAAAAH8oi/v7iDL4cAAAAAAAAA
162 | B/KIi/v7iC+HAAAAAAAAAAfyIiIiIiIvhwAAAAAAAAAH/////////4cAAAAAAAAAAHd3d3d3d3d3AP/+
163 | B//A+AH/wHAA/8AgAH/AAAB/wAAAP8AAAD/AAGA/wABgP8AAAD/AAAA/wAAAA8AAAAHAAAAAwAAAAMAA
164 | AADAAAAAwAAAAIAAAAEAAAAB+AAAAfwAAAH+AAAB/wAAAf/4AAH/+AAB//gAAf/4AAH/+AAB//gAAf/4
165 | AAH//AADKAAAACAAAABAAAAAAQAIAAAAAACABAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAIAAAICA
166 | AAAAAIAAgACAAACAgADAwMAAwNzAAKbK8AAEBAQACAgIAAwMDAAREREAFhYWABwcHAAiIiIAKSkpAFVV
167 | VQBNTU0AQkJCADk5OQD/fIAA/1BQANYAkwDM7P8A79bGAOfn1gCtqZAAMwAAAGYAAACZAAAAzAAAAAAz
168 | AAAzMwAAZjMAAJkzAADMMwAA/zMAAABmAAAzZgAAZmYAAJlmAADMZgAA/2YAAACZAAAzmQAAZpkAAJmZ
169 | AADMmQAA/5kAAADMAAAzzAAAZswAAJnMAADMzAAA/8wAAGb/AACZ/wAAzP8AAAAAMwAzADMAZgAzAJkA
170 | MwDMADMA/wAzAAAzMwAzMzMAZjMzAJkzMwDMMzMA/zMzAABmMwAzZjMAZmYzAJlmMwDMZjMA/2YzAACZ
171 | MwAzmTMAZpkzAJmZMwDMmTMA/5kzAADMMwAzzDMAZswzAJnMMwDMzDMA/8wzADP/MwBm/zMAmf8zAMz/
172 | MwD//zMAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYAADNmADMzZgBmM2YAmTNmAMwzZgD/M2YAAGZmADNm
173 | ZgBmZmYAmWZmAMxmZgAAmWYAM5lmAGaZZgCZmWYAzJlmAP+ZZgAAzGYAM8xmAJnMZgDMzGYA/8xmAAD/
174 | ZgAz/2YAmf9mAMz/ZgD/AMwAzAD/AACZmQCZM5kAmQCZAMwAmQAAAJkAMzOZAGYAmQDMM5kA/wCZAABm
175 | mQAzZpkAZjOZAJlmmQDMZpkA/zOZADOZmQBmmZkAmZmZAMyZmQD/mZkAAMyZADPMmQBmzGYAmcyZAMzM
176 | mQD/zJkAAP+ZADP/mQBmzJkAmf+ZAMz/mQD//5kAAADMADMAmQBmAMwAmQDMAMwAzAAAM5kAMzPMAGYz
177 | zACZM8wAzDPMAP8zzAAAZswAM2bMAGZmmQCZZswAzGbMAP9mmQAAmcwAM5nMAGaZzACZmcwAzJnMAP+Z
178 | zAAAzMwAM8zMAGbMzACZzMwAzMzMAP/MzAAA/8wAM//MAGb/mQCZ/8wAzP/MAP//zAAzAMwAZgD/AJkA
179 | /wAAM8wAMzP/AGYz/wCZM/8AzDP/AP8z/wAAZv8AM2b/AGZmzACZZv8AzGb/AP9mzAAAmf8AM5n/AGaZ
180 | /wCZmf8AzJn/AP+Z/wAAzP8AM8z/AGbM/wCZzP8AzMz/AP/M/wAz//8AZv/MAJn//wDM//8A/2ZmAGb/
181 | ZgD//2YAZmb/AP9m/wBm//8ApQAhAF9fXwB3d3cAhoaGAJaWlgDLy8sAsrKyANfX1wDd3d0A4+PjAOrq
182 | 6gDx8fEA+Pj4AP/78ACgoKQAgICAAP8AAAAA/wAA//8AAAAA/wD/AP8AAP//AP///wAAAAAAAAAAAAAA
183 | AAAAAADq6upDQ0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADq6ru74cJYMUNDAAAAAAAAAAAAAADsvP+8
184 | /wAAAAAA6gcHu7vhwlgxMJ9DAAAAAAAAAAAAAOz/vP+8AOwAAOrvBwcHu+FYMTCfn59DAAAAAAAAAAAA
185 | 7Lz/vP8A9+wA6+/vBwe74TEwn5/y8kMAAAAAAAAAAADs/7z/vADs9+rv7+/vB7u7MJ/y8vLy8kMAAAAA
186 | AAAAAOy8/7z/APfs6rzv7+/vBwAA8vLy7+/vQwAAAAAAAAAA7P+8/7wA7PfqvLy87+8AAAAA7Ozs7+9D
187 | AAAAAAAAAADsvP+8/wD37OqSkpKSkgAAAADw8Ozs7EMAAAAAAAAAAOz/vP+8AOz36vLyn59YWAAA7/f/
188 | 8O/vQwAAAAAAAAAA7P////8A9+zq8p9YWFJzc7rv9wf/8PBDAAAAAAAAAADs/////wDs9+zqWFhSc3jh
189 | uu/v9wf/QwAAAAAAAAAAAOz/////APfs9+pYUlJz4eG6uu/39wdDBwcHBwcAAAAA7P////8A9/f39+pS
190 | c3jhurq67+/3QwAAAAAH7+wAAADs/////wD39/f3AOvreOG6urrvQ0Ps7Ozs7AcH7AAAAOz/////APf3
191 | 9/cA///t7e3t6+v////////////sAAAA7Ozs7OwA9/f39wDs7Ozs7Ozs7Ozs7Ozs7Ozs7+wAAADq6urq
192 | 6gD39/f3AAAAAAAAAAAAAAAAAAAAAAAA7wsA7P//////6gD39/cA7AcHBwcHBwcHBwcHBwcHB+wAAOzs
193 | 7Ozs7Ozq6gD39wDs//////////////////8H7AAAAAAAAADs6urq6gD3AOz/AQEBAQEBAQEBAQEB/wfs
194 | AAAAAAAAAADs6urq6gAA7P8B+3p6MTExMU1NTQH/B+wAAAAAAAAAAADs/////wDs/wHDXnp6MTExMU1N
195 | Af8H7AAAAAAAAAAAAADs7Ozs7AD/AV7DXnp6MTExMU0B/wfsAAAAAAAAAAAAAAAAAAAA7P8Bw17DXnp6
196 | MTExMQH/B+wAAAAAAAAAAAAAAAAAAADs/wFew17DXnp6MTExAf8H7AAAAAAAAAAAAAAAAAAAAOz/AXpe
197 | w17DXnp6MTEB/wfsAAAAAAAAAAAAAAAAAAAA7P8Benpew17DXnp6MQH/B+wAAAAAAAAAAAAAAAAAAADs
198 | /wF6enpew17D+3p6Af8H7AAAAAAAAAAAAAAAAAAAAOz/AQEBAQEBAQEBAQEB/wfsAAAAAAAAAAAAAAAA
199 | AAAA7P//////////////////B+wAAAAAAAAAAAAAAAAAAAAA6+vr6+vr6+vr6+vr6+vr6wAA//4H/8D4
200 | Af/AcAD/wCAAf8AAAH/AAAA/wAAAP8AAYD/AAGA/wAAAP8AAAD/AAAADwAAAAcAAAADAAAAAwAAAAMAA
201 | AADAAAAAgAAAAQAAAAH4AAAB/AAAAf4AAAH/AAAB//gAAf/4AAH/+AAB//gAAf/4AAH/+AAB//gAAf/8
202 | AAMoAAAAMAAAAGAAAAABAAgAAAAAAIAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAgAAAgIAAAAAA
203 | gACAAIAAAICAAMDAwADA3MAApsrwAAQEBAAICAgADAwMABEREQAWFhYAHBwcACIiIgApKSkAVVVVAE1N
204 | TQBCQkIAOTk5AP98gAD/UFAA1gCTAMzs/wDv1sYA5+fWAK2pkAAzAAAAZgAAAJkAAADMAAAAADMAADMz
205 | AABmMwAAmTMAAMwzAAD/MwAAAGYAADNmAABmZgAAmWYAAMxmAAD/ZgAAAJkAADOZAABmmQAAmZkAAMyZ
206 | AAD/mQAAAMwAADPMAABmzAAAmcwAAMzMAAD/zAAAZv8AAJn/AADM/wAAAAAzADMAMwBmADMAmQAzAMwA
207 | MwD/ADMAADMzADMzMwBmMzMAmTMzAMwzMwD/MzMAAGYzADNmMwBmZjMAmWYzAMxmMwD/ZjMAAJkzADOZ
208 | MwBmmTMAmZkzAMyZMwD/mTMAAMwzADPMMwBmzDMAmcwzAMzMMwD/zDMAM/8zAGb/MwCZ/zMAzP8zAP//
209 | MwAAAGYAMwBmAGYAZgCZAGYAzABmAP8AZgAAM2YAMzNmAGYzZgCZM2YAzDNmAP8zZgAAZmYAM2ZmAGZm
210 | ZgCZZmYAzGZmAACZZgAzmWYAZplmAJmZZgDMmWYA/5lmAADMZgAzzGYAmcxmAMzMZgD/zGYAAP9mADP/
211 | ZgCZ/2YAzP9mAP8AzADMAP8AAJmZAJkzmQCZAJkAzACZAAAAmQAzM5kAZgCZAMwzmQD/AJkAAGaZADNm
212 | mQBmM5kAmWaZAMxmmQD/M5kAM5mZAGaZmQCZmZkAzJmZAP+ZmQAAzJkAM8yZAGbMZgCZzJkAzMyZAP/M
213 | mQAA/5kAM/+ZAGbMmQCZ/5kAzP+ZAP//mQAAAMwAMwCZAGYAzACZAMwAzADMAAAzmQAzM8wAZjPMAJkz
214 | zADMM8wA/zPMAABmzAAzZswAZmaZAJlmzADMZswA/2aZAACZzAAzmcwAZpnMAJmZzADMmcwA/5nMAADM
215 | zAAzzMwAZszMAJnMzADMzMwA/8zMAAD/zAAz/8wAZv+ZAJn/zADM/8wA///MADMAzABmAP8AmQD/AAAz
216 | zAAzM/8AZjP/AJkz/wDMM/8A/zP/AABm/wAzZv8AZmbMAJlm/wDMZv8A/2bMAACZ/wAzmf8AZpn/AJmZ
217 | /wDMmf8A/5n/AADM/wAzzP8AZsz/AJnM/wDMzP8A/8z/ADP//wBm/8wAmf//AMz//wD/ZmYAZv9mAP//
218 | ZgBmZv8A/2b/AGb//wClACEAX19fAHd3dwCGhoYAlpaWAMvLywCysrIA19fXAN3d3QDj4+MA6urqAPHx
219 | 8QD4+PgA//vwAKCgpACAgIAA/wAAAAD/AAD//wAAAAD/AP8A/wAA//8A////AAAAAAAAAAAAAAAAAAAA
220 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7wZ
221 | 4cEZ4rsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8HBwcJCcHh4cGZeQAAAAAA
222 | AAAAAAAAAAAAAAAAAOvw8PDw8PAAAAAAAAAAAAD3BwcHBwcI4cHh4QiYeFIxAAAAAAAAAAAAAAAAAAAA
223 | AOvw8PDw8PAA7QAAAAAAAO3t9wcHBwcI4cHh4ZiYV1JYeQAAAAAAAAAAAAAAAAAAAOvw8PDw8PAA7e0A
224 | AAAA9/ft7e8HBwcHGcHhwZh4UlJ5eXgAAAAAAAAAAAAAAAAAAOvw8PDw8PAA7e3tAAAAB+/3ku3vBwcI
225 | CcHhwZh4Unl5n58AAAAAAAAAAAAAAAAAAOvw8PDw8PAA7e3t7QDwvAfv95Lt77y84cHhwXhSWHmfn8LC
226 | AAAAAAAAAAAAAAAAAOvw8PDw8PAA7e3t7QD08LwH7+/3ku+84cHBUlJSeZ/CwsLCAAAAAAAAAAAAAAAA
227 | AOvw8PDw8PAA7e3tAPT/9PHwvAfv9+/vwcHBUlifn8LCG8IbCAAAAAAAAAAAAAAAAOvw8PDw8PAA7e3t
228 | APX19fLx8LwHB/fvAAAAc3kbG/EbG/Ly/wAAAAAAAAAAAAAAAOvw8PDw8PAA7e3tAPfvBwcHBwcH7+8A
229 | AAAAALy8vLy8vLy88AAAAAAAAAAAAAAAAOvw8PDw8PAA7e3tAJKS9/f39+8HBwcAAAAAAO2Skvf39/f3
230 | 7wAAAAAAAAAAAAAAAOvw8PDw8PAA7e3tAPfv7+/v7wifwngAAAAAAAcHkpKSkpKS9wAAAAAAAAAAAAAA
231 | AOvw8PDw8PAA7e3tAAe88PDwwp94UpidAAAAku+8B++SkpL3kgAAAAAAAAAAAAAAAOvw8PDw8PAA7e3t
232 | AAfywsLCn3lSeJjBu8G77+/v8PC8B/f3kgAAAAAAAAAAAAAAAOvx8fHx8fEA7+3t7QDCwp+fV1JSV8Hh
233 | wcG77/fvvPH0//KSAAAAAAAAAAAAAAAAAOvy8vLy8vIA7e/t7QCfn59YUlJXeMHh3MG77/fvB7zx9f//
234 | AAAAAAAAAAAAAAAAAOv09PT09PQA7+3v7e0AeFhYUlJ4mMHh4cG7u+/37wfw8v8ABwcHBwcHBwcAAAAA
235 | AOv19fX19fUA7+/t7+0AWFhSUnh4mMHhwcG7u+/v9++89PAABwcHBwcHBwfsAAAAAOv///////8A7+/v
236 | 7e/tAFJSUniYmMHh4cG7urvv7+8HBwAHBwcHBwcHBwfsAAAAAOv///////8A7+/v7+3v7QBSeHiYweHh
237 | 4cG7u7vv7+/3AAcHBwcHBwcHBwfsAAAAAOv///////8A7+/v7+/t7+0AAJiYweEJCcG7uru79wAABwcA
238 | AAAAAAAAB+/sAAAAAOv///////8A7+/v7+/v7e8A/wAAu+EZwcHhu5EAAAcHBwfs7Ozs7OzsBwfsAAAA
239 | AOv///////8A7+/v7+/v7+0A////AAAAAAAAAAD////////////////////sAAAAAOv///////8A7+/v
240 | 7+/v7+8A6+zs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O/sAAAAAOvr6+vr6+sA7+/v7+/v7+8AAAAAAAAA
241 | AAAAAAAAAAAAAAAAAAAAAAAAAADvCwAAABISEhISEhIA7+/v7+/v7+8A7AcHBwcHBwcHBwcHBwcHBwcH
242 | BwcHBwcHB+wAAAAA6/////////8SAO/v7+/v7+8A7P/19fX19fX19fX19fX19fX19fX19fX1B+wAAADr
243 | //////////8SEgDv7+/v7+8A7P////X19fX19fX19fX19fX19fX19f/1B+wAAOvr6+vr6+vr6+sSEhIA
244 | 7+/v7+8A7P//AQEBAQEBAQEBAQEBAQEBAQEBAf/1B+wAAAAAAAAAAADrEhISEhISAO/v7+8A7P//AXp6
245 | Xnp6ejExMTExMU1NTU1NAf/1B+wAAAAAAAAAAAAA6xISEhISEgDv7+8A7P//AcN6el56enoxMTExMTFN
246 | TU1NAf/1B+wAAAAAAAAAAAAAAOsSEhISEhIA7+8A7P//AV7Denpeenp6MTExMTExTU1NAfX1B+wAAAAA
247 | AAAAAAAAAADrEhISEhISAO8A7P//AcNew3p6Xnp6ejExMTExMU1NAfX1B+wAAAAAAAAAAAAAAAAA6xIS
248 | EhISEgAA7P//AV7DXsN6el56enoxMTExMTFNAfX1B+wAAAAAAAAAAAAAAAAAAOv///////8A7P//AV5e
249 | w17Denpeenp6MTExMTExAfX1B+wAAAAAAAAAAAAAAAAAAADr6+vr6+vrAP//AV5eXsNew3p6Xnp6ejEx
250 | MTExAfX1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P//AXpeXl7DXsN6el56enoxMTExAfX1B+wAAAAA
251 | AAAAAAAAAAAAAAAAAAAAAAAA7P//AXp6Xl5ew17Denpeenp6MTExAfX1B+wAAAAAAAAAAAAAAAAAAAAA
252 | AAAAAAAA7P//AXp6el5eXsNew3p6Xnp6ejExAfX1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P//AXp6
253 | enpeXl7DXsN6el56enoxAfX1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P//AXp6enp6Xl5ew17Denpe
254 | enp6AfX1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P//AXp6enp6el5eXsNew3p6Xnp6AfX1B+wAAAAA
255 | AAAAAAAAAAAAAAAAAAAAAAAA7P//AQEBAQEBAQEBAQEBAQEBAQEBAfX1B+wAAAAAAAAAAAAAAAAAAAAA
256 | AAAAAAAA7P////////////////////////////X1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P//////
257 | ///////////////////////17+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOvr6+vr6+vr6+vr6+vr6+vr
258 | 6+vr6+vr6wAAAP///gH//wAA///4AH//AADgH+AAH/8AAOAPwAAP/wAA4AeAAAf/AADgAwAAA/8AAOAB
259 | AAAD/wAA4AAAAAH/AADgAAAAAf8AAOAAAAAA/wAA4AAAAAD/AADgAAA4AP8AAOAAADgA/wAA4AAAOAD/
260 | AADgAAAAAP8AAOAAAAAA/wAA4AAAAAH/AADgAAAAAAMAAOAAAAAAAQAA4AAAAAAAAADgAAAAAAAAAOAA
261 | AAAAAAAA4AAAAAAAAADgAAAAAAAAAOAAAAAAAAAA4AAAAAAAAADgAAAAAAAAAOAAAAAAAQAAwAAAAAAB
262 | AACAAAAAAAEAAAAAAAAAAQAA/gAAAAABAAD/AAAAAAEAAP+AAAAAAQAA/8AAAAABAAD/4AAAAAEAAP/w
263 | AAAAAQAA//gAAAABAAD///AAAAEAAP//8AAAAQAA///wAAABAAD///AAAAEAAP//8AAAAQAA///wAAAB
264 | AAD///AAAAEAAP//8AAAAQAA///wAAABAAD///gAAAcAACgAAAAwAAAAYAAAAAEABAAAAAAAAAYAAAAA
265 | AAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACAgAAAAACAAACAgACAAIAAgICAAMDAwAAA/wAA/wAAAP//
266 | AAAAAP8AAP//AP8A/wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFj43fkAAA
267 | AAAAAAAAAAAAAAAAAAAAAAiFWI3YmIAAAAAAAAAAAAeIiIgAAAAACHiIWI3YmHMwAAAAAAAAAAeIiIgH
268 | AAAAd4eIVY3ZmDO4AAAAAAAAAAeIiIgHcAAHd3h4Vf3ZhzOJkAAAAAAAAAeIiIgHdwAHd3eHhV3ZhziZ
269 | gAAAAAAAAAeIiIgHd3CId3d4dV3Yc7mYjwAAAAAAAAeIiIgHd3D4+Hd3h13TM5mI+AAAAAAAAAeIiIgH
270 | dw//j4h3eF2TuZ+Pj4AAAAAAAAeIiIgHdw//+PiHdwAHj/j///AAAAAAAAeIiIgHdwiIiIiIcAAAiIiI
271 | iIAAAAAAAAeIiIgHdwd3d3d3gAAAd3iIiIAAAAAAAAeIiIgHdwiIiIiYcAAAiHd3d4AAAAAAAAeIiIgH
272 | dwiIiJl7gwAHiIh3d3AAAAAAAAf4+PgHdwj4iZizPZWHePiId3AAAAAAAAePj48Id3CJmbsz3ZWIeI//
273 | 9wAAAAAAAAf///8Hh3CZm7M33ZWId4+P/wAAAAAAAAf///8IeHcHuzN92ZWIh3j/8IiIiIgAAAf///8I
274 | h4cLszd9mVWIiHePgIiIiIhwAAf///8IiHhwMzfdmVVYiHeICIiIiIhwAAf///8IiIeHA3fdmVVYiIdw
275 | iIiIiIhwAAf///8IiIh4cA3ZlVVYiIAIgAAAAIhwAAf///8IiIiHgPAJlVVYcAiIh3d3d4hwAAf///8I
276 | iIiIcP/wAAAAD/////////9wAAf///8IiIiIgHd3d3d3d3d3d3d3d3hwAAd3d3cIiIiIgAAAAAAAAAAA
277 | AAAAAACAAAd3d3cIiIiIgHiIiIiIiIiIiIiIiIcAAH////9wiIiIgH///////////////4cAB/////93
278 | CIiIgH///////////////4cAd3d3d3d3cIiIgH/yIiIiIiIiIiIi/4cAAAAAB3d3dwiIgH/yqqqqqqqq
279 | qqqi/4cAAAAAAHd3d3CIgH/yqqqqqqqqIiKi/4cAAAAAAAd3d3cIgH/yqqqqqqqqqqKi/4cAAAAAAAB3
280 | d3dwgH/yqqqqqqqqqqKi/4cAAAAAAAAHd3d3AH/yqqqqqqqqqqKi/4cAAAAAAAAAf///8H/yqqqqqqqq
281 | qqqi/4cAAAAAAAAAB3d3dw/yqqqqqqqqqqqi/4cAAAAAAAAAAAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAA
282 | AAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAAAAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAAAAAAAH/yqvqqqqqq
283 | qqqi/4cAAAAAAAAAAAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAAAAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAA
284 | AAAAAH/yIiIiIiIiIiIi/4cAAAAAAAAAAAAAAH///////////////4cAAAAAAAAAAAAAAH//////////
285 | /////4cAAAAAAAAAAAAAAAd3d3d3d3d3d3d3d3AA///+Af//AAD///gAf/8AAOAf4AAf/wAA4A/AAA//
286 | AADgB4AAB/8AAOADAAAD/wAA4AEAAAP/AADgAAAAAf8AAOAAAAAB/wAA4AAAAAD/AADgAAAAAP8AAOAA
287 | ADgA/wAA4AAAOAD/AADgAAA4AP8AAOAAAAAA/wAA4AAAAAD/AADgAAAAAf8AAOAAAAAAAwAA4AAAAAAB
288 | AADgAAAAAAAAAOAAAAAAAAAA4AAAAAAAAADgAAAAAAAAAOAAAAAAAAAA4AAAAAAAAADgAAAAAAAAAOAA
289 | AAAAAAAA4AAAAAABAADAAAAAAAEAAIAAAAAAAQAAAAAAAAABAAD+AAAAAAEAAP8AAAAAAQAA/4AAAAAB
290 | AAD/wAAAAAEAAP/gAAAAAQAA//AAAAABAAD/+AAAAAEAAP//8AAAAQAA///wAAABAAD///AAAAEAAP//
291 | 8AAAAQAA///wAAABAAD///AAAAEAAP//8AAAAQAA///wAAABAAD///AAAAEAAP//+AAABwAA
292 |
293 |
294 |
--------------------------------------------------------------------------------
/CH340BConfigure/CH340BDeviceAccess.cs:
--------------------------------------------------------------------------------
1 | // *********************************************************************************************************
2 | //
3 | // Project : WCH CH340B Configuration Utility
4 | // FileName : CH340BDeviceAccess.cs
5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER
6 | // Co-Author(s) :
7 | // Created : 02 January, 2022
8 | //
9 | // *********************************************************************************************************
10 | //
11 | // Module Description
12 | //
13 | // This module has methods that will detect CH340B devices connected to PC USB port, read configuration data
14 | // from the selected CH340B device, write configuration data to the selected CH340B device.
15 | // *********************************************************************************************************
16 | //
17 | // History
18 | //
19 | // Date Version Author Changes
20 | //
21 | // 02 January, 2022 1.0.0 SENTHILNATHAN THANGAVEL Initial version
22 | //
23 | // *********************************************************************************************************
24 | using System;
25 | using System.Runtime.InteropServices;
26 | using System.Text;
27 | using System.Windows.Forms;
28 | using static CH340BConfigure.NativeAccess;
29 |
30 | namespace CH340BConfigure
31 | {
32 | public class CH340BDeviceAccess
33 | {
34 | // Device Info object array that has device's user friendly name, actual COM port name
35 | // This application supports multiple CH340B devices connected to the same PC's USB ports -
36 | // up to 10 number of devices
37 | internal DeviceInfo[] aoDevInfo = DeviceInfo.NewInitArray(10);
38 |
39 | // Allocate separate buffers for Read and Write functions
40 | private Byte[] abyReadData = new byte[1024];
41 | private Byte[] abyWriteData = new byte[1024];
42 | // Allocate a byte array buffer for using in the DeviceIoControl calls
43 | private Byte[] abyInputBuffer = null;
44 | private uint unBytesReturned = 0;
45 | // Device Handle
46 | private IntPtr pHandle = IntPtr.Zero;
47 | private IntPtr pspDeviceInterfaceData = IntPtr.Zero;
48 | private IntPtr pspDeviceInterfaceDetailData = IntPtr.Zero;
49 |
50 | internal class DeviceInfo
51 | {
52 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
53 | public string szComportName;
54 |
55 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
56 | public string szComportNameForHandle;
57 |
58 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
59 | public string szDeviceName;
60 |
61 | public int nDeviceIndex;
62 |
63 | // Array of Device Info objects
64 | static internal DeviceInfo[] NewInitArray(ulong num)
65 | {
66 | DeviceInfo[] aoDeviceInfo = new DeviceInfo[num];
67 | for (ulong i = 0; i < num; i++)
68 | {
69 | aoDeviceInfo[i] = new DeviceInfo();
70 | }
71 | return aoDeviceInfo;
72 | }
73 | }
74 |
75 | internal int FindDevices()
76 | {
77 | bool bResult = true;
78 | int nNumberOfDevices = 0;
79 | try
80 | {
81 | bResult = GetDevices(ref aoDevInfo, ref nNumberOfDevices);
82 | }
83 | catch (Exception ex)
84 | {
85 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK,
86 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
87 | }
88 | return nNumberOfDevices;
89 | }
90 |
91 | /*
92 | * Function Name: GetDevices
93 | * Description: This function looks for the CH340B devices connected to the PC USB port and
94 | * get the device friendly name, COM port name, which will be used in further device opening to perform Read / Write
95 | * functions with the device.
96 | * Arguments:
97 | * DeviceInfo[] - DeviceInfo object array - it will have the device info object for each device detected in the system
98 | * nTotalDevices - Integer value that represents the number of devices detected in the system
99 | * Return: boolean value - true if the function call is successsful, false if any error occurred
100 | * The code doesn't report error as of now. It checks for error using GetLastError, but not reporting to the caller.
101 | */
102 | private bool GetDevices(ref DeviceInfo[] aoDevInfo, ref int nTotalDevices)
103 | {
104 | bool bStatus = true;
105 | uint uintError = Constants.NO_ERROR;
106 | IntPtr hDevInfo = IntPtr.Zero;
107 | IntPtr hDevice = IntPtr.Zero;
108 | uint uintDeviceID = 0;
109 | uint uintDataT = 0;
110 | uint uintBufferSize = 0;
111 | // COM Port Interface Class GUID
112 | Guid sGuid = new Guid("86E0D1E0-8089-11D0-9CE4-08003E301F73");
113 | IntPtr psDeviceInfoData = IntPtr.Zero;
114 | NativeStructs.SP_DEVINFO_DATA sDeviceInfoData = new NativeStructs.SP_DEVINFO_DATA();
115 | IntPtr pPropertyBuffer = IntPtr.Zero;
116 | do
117 | {
118 | uintError = NativeAccess.Constants.NO_ERROR;
119 | nTotalDevices = 0;
120 | // Create a HDEVINFO with all the present devices of the COM Port Interface Class GUID Supplied.
121 | hDevInfo = NativeMethods.SetupDiGetClassDevs(ref sGuid, IntPtr.Zero, IntPtr.Zero,
122 | Constants.DIGCF_DEVICEINTERFACE | Constants.DIGCF_PRESENT);
123 | // Validate the hDevInfo handle
124 | if (Constants.INVALID_HANDLE_VALUE == hDevInfo)
125 | {
126 | uintError = Constants.ERROR_INVALID_HANDLE; // (Long Pointer Value - 1)
127 | bStatus = false;
128 | break;
129 | }
130 | // Enumerate through all devices in the set
131 | sDeviceInfoData.cbSize = Marshal.SizeOf(sDeviceInfoData);
132 | // Initialize pointer for sDeviceInfoData
133 | psDeviceInfoData = Marshal.AllocHGlobal(Marshal.SizeOf(sDeviceInfoData));
134 | Marshal.StructureToPtr(sDeviceInfoData, psDeviceInfoData, true);
135 | for (uintDeviceID = 0; NativeMethods.SetupDiEnumDeviceInfo(hDevInfo, uintDeviceID, psDeviceInfoData);
136 | uintDeviceID++)
137 | {
138 | sDeviceInfoData = (NativeStructs.SP_DEVINFO_DATA)Marshal.PtrToStructure(psDeviceInfoData,
139 | typeof(NativeStructs.SP_DEVINFO_DATA));
140 | // Get the device friendly name from the registry
141 | while (!NativeMethods.SetupDiGetDeviceRegistryProperty(hDevInfo, psDeviceInfoData,
142 | (uint)Constants.SPDRP.SPDRP_FRIENDLYNAME, ref uintDataT, pPropertyBuffer, uintBufferSize, ref uintBufferSize))
143 | {
144 | // Check for error
145 | uintError = (uint)Marshal.GetLastWin32Error();
146 | if (Constants.ERROR_INSUFFICIENT_BUFFER == uintError)
147 | {
148 | // If the error is insufficient buffer, then allocate the buffer for number of bytes specified by uintBufferSize
149 | pPropertyBuffer = Marshal.AllocHGlobal((int)uintBufferSize);
150 | }
151 | else
152 | {
153 | // If the error is not ERROR_INSUFFICIENT_BUFFER, quit the loop
154 | bStatus = false;
155 | break;
156 | }
157 | }
158 | IntPtr pDeviceName = new IntPtr(pPropertyBuffer.ToInt64());
159 | String szDeviceName = Marshal.PtrToStringAuto(pDeviceName);
160 | String szDevicePathName = System.String.Empty;
161 | String szComportName = "";
162 | try
163 | {
164 | szComportName = szDeviceName.Split(new char[] { '(', ')' })[1];
165 | }
166 | catch (Exception ex)
167 | {
168 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK,
169 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
170 | }
171 | if (string.IsNullOrEmpty(szComportName) == false)
172 | {
173 | // Form the COM Port name like this "\\\\.\\COMn"
174 | string szComportNameForHandle = "\\\\.\\" + szComportName;
175 | // Check if the device detected is really CH340B or other Virtual / Real COM Port devices
176 | bool bDeviceIsCh340B = CheckIfDeviceIsCh340B(szComportNameForHandle);
177 | if (bDeviceIsCh340B)
178 | {
179 | // If this is really CH340B then, store its friendly name, COM Port name
180 | // to the device info object
181 | aoDevInfo[nTotalDevices].szComportName = szComportName;
182 | aoDevInfo[nTotalDevices].szComportNameForHandle = szComportNameForHandle;
183 | aoDevInfo[nTotalDevices].szDeviceName = szDeviceName;
184 | aoDevInfo[nTotalDevices].nDeviceIndex = nTotalDevices;
185 | nTotalDevices++;
186 | }
187 | }
188 | }
189 |
190 | } while (false);
191 | // Free the memory allocated from unmanaged memory used
192 | if (psDeviceInfoData != IntPtr.Zero)
193 | {
194 | Marshal.FreeHGlobal(psDeviceInfoData);
195 | psDeviceInfoData = IntPtr.Zero;
196 | }
197 | if (pPropertyBuffer != IntPtr.Zero)
198 | {
199 | Marshal.FreeHGlobal(pPropertyBuffer);
200 | pPropertyBuffer = IntPtr.Zero;
201 | }
202 | // Destroy the device information list
203 | if (hDevInfo != IntPtr.Zero)
204 | {
205 | NativeMethods.SetupDiDestroyDeviceInfoList(hDevInfo);
206 | }
207 | return bStatus;
208 | }
209 |
210 | /*
211 | * Function Name: CheckIfDeviceIsCh340B
212 | * Description: This function checks whether the detected device is a CH340B or other COM port devices
213 | * Arguments:
214 | * IntPtr - pHandle - Managed Pointer variable that represents the device handle
215 | * Return: boolean value - true if the device detected is a CH340B or else false
216 | */
217 | private bool CheckIfDeviceIsCh340B(string szComportName)
218 | {
219 | bool bResult = false;
220 | bool bDeviceIsCh340B = false;
221 | try
222 | {
223 | // Open the device using the COM Port Name in the format "\\\\.\\COMn"
224 | pHandle = NativeMethods.CreateFile(szComportName, Constants.GENERIC_READ | Constants.GENERIC_WRITE,
225 | Constants.FILE_SHARE_READ | Constants.FILE_SHARE_WRITE, IntPtr.Zero, Constants.OPEN_EXISTING, 0, IntPtr.Zero);
226 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE)
227 | {
228 | // Initialize the vendor interface
229 | bResult = InitializeCh340BVendorInterface(pHandle);
230 | if (bResult == true)
231 | {
232 | // Get Serial Properties
233 | NativeStructs.SERIAL_COMMPROP sSerialCompProp = new NativeStructs.SERIAL_COMMPROP();
234 | IntPtr psSerialCompProp = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialCompProp));
235 | Marshal.StructureToPtr(sSerialCompProp, psSerialCompProp, false);
236 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_PROPERTIES, IntPtr.Zero, 0, psSerialCompProp,
237 | Marshal.SizeOf(sSerialCompProp), out unBytesReturned, IntPtr.Zero);
238 | Marshal.PtrToStructure(psSerialCompProp, sSerialCompProp);
239 | Marshal.FreeHGlobal(psSerialCompProp);
240 |
241 | // The magic value 0x43485523 is returned in the unsigned integer ProvSpec2 of Serial Comm Prop structure by the CH340B driver
242 | if (sSerialCompProp.ProvSpec2 == 0x43485523)
243 | {
244 | // Device is CH340B
245 | bDeviceIsCh340B = true;
246 | }
247 | }
248 | }
249 | }
250 | catch (Exception ex)
251 | {
252 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK,
253 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
254 | }
255 | // Close the device handle
256 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE)
257 | {
258 | NativeMethods.CloseHandle(pHandle);
259 | }
260 | return bDeviceIsCh340B;
261 | }
262 |
263 | /*
264 | * Function Name: InitializeCh340BVendorInterface
265 | * Description: This function initializes the Vendor Interface of the CH340B driver
266 | * Arguments:
267 | * IntPtr - pHandle - Manged Pointer variable that represents the device handle
268 | * Return: boolean value - true if the device detected is a CH340B or else false
269 | */
270 | private bool InitializeCh340BVendorInterface(IntPtr pHandle)
271 | {
272 | bool bResult = false;
273 |
274 | try
275 | {
276 | // Validate the device hanlde
277 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE)
278 | {
279 | // CH340B uses a vendor supplied driver on Microsoft Windows, that is its not fully complaint with
280 | // Microsoft's USB CDC driver, so the Microsoft USB CDC driver is not loaded and it requires
281 | // the vendor - chip manufacturer (WCH) supplied driver.
282 | // First the device must be informed to send the Vendor request command through Control Endpoint
283 | // The following sequence of commands are issued to the CH340B's Kernel mode driver and make the CH340B driver
284 | // to issue a vendor request through Control Endpoint to the CH340B.
285 |
286 | // Get Serial Properties
287 | NativeStructs.SERIAL_COMMPROP sSerialCompProp = new NativeStructs.SERIAL_COMMPROP();
288 | IntPtr psSerialCompProp = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialCompProp));
289 | Marshal.StructureToPtr(sSerialCompProp, psSerialCompProp, false);
290 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_PROPERTIES, IntPtr.Zero, 0, psSerialCompProp,
291 | Marshal.SizeOf(sSerialCompProp), out unBytesReturned, IntPtr.Zero);
292 | Marshal.PtrToStructure(psSerialCompProp, sSerialCompProp);
293 | Marshal.FreeHGlobal(psSerialCompProp);
294 |
295 | // Set Serial Queue size
296 | NativeStructs.SERIAL_QUEUE_SIZE sSerialQueueSize = new NativeStructs.SERIAL_QUEUE_SIZE();
297 | sSerialQueueSize.InSize = 0x00002000;
298 | sSerialQueueSize.OutSize = 0x00002000;
299 | IntPtr psSerialQueueSize = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialQueueSize));
300 | Marshal.StructureToPtr(sSerialQueueSize, psSerialQueueSize, false);
301 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_QUEUE_SIZE, psSerialQueueSize,
302 | Marshal.SizeOf(sSerialQueueSize), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero);
303 | Marshal.FreeHGlobal(psSerialQueueSize);
304 |
305 | // Get Serial TimeOuts
306 | NativeStructs.SERIAL_TIMEOUTS sSerialTimeOuts = new NativeStructs.SERIAL_TIMEOUTS();
307 | IntPtr psSerialTimeOuts = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialTimeOuts));
308 | Marshal.StructureToPtr(sSerialTimeOuts, psSerialTimeOuts, false);
309 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_TIMEOUTS, IntPtr.Zero, 0, psSerialTimeOuts,
310 | Marshal.SizeOf(sSerialTimeOuts), out unBytesReturned, IntPtr.Zero);
311 | Marshal.PtrToStructure(psSerialTimeOuts, sSerialTimeOuts);
312 | Marshal.FreeHGlobal(psSerialTimeOuts);
313 |
314 | // Set Serial Timeouts
315 | sSerialTimeOuts = new NativeStructs.SERIAL_TIMEOUTS();
316 | sSerialTimeOuts.ReadIntervalTimeout = 0x00000000;
317 | sSerialTimeOuts.ReadTotalTimeoutMultiplier = 0x00000064;
318 | sSerialTimeOuts.ReadTotalTimeoutConstant = 0x000003E8;
319 | sSerialTimeOuts.WriteTotalTimeoutMultiplier = 0x00000032;
320 | sSerialTimeOuts.WriteTotalTimeoutConstant = 0x000001F4;
321 | psSerialTimeOuts = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialTimeOuts));
322 | Marshal.StructureToPtr(sSerialTimeOuts, psSerialTimeOuts, false);
323 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_TIMEOUTS, psSerialTimeOuts,
324 | Marshal.SizeOf(sSerialTimeOuts), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero);
325 | Marshal.FreeHGlobal(psSerialTimeOuts);
326 |
327 | // Issue Serial Purge
328 | abyInputBuffer = new byte[4];
329 | abyInputBuffer[0] = 0x0F;
330 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_PURGE, abyInputBuffer, abyInputBuffer.Length,
331 | IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero);
332 |
333 | // Get Serial Baudrate
334 | NativeStructs.SERIAL_BAUD_RATE sSerialBaudRate = new NativeStructs.SERIAL_BAUD_RATE();
335 | IntPtr psSerialBaudRate = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialBaudRate));
336 | Marshal.StructureToPtr(sSerialBaudRate, psSerialBaudRate, false);
337 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_BAUD_RATE, IntPtr.Zero, 0, psSerialBaudRate,
338 | Marshal.SizeOf(sSerialBaudRate), out unBytesReturned, IntPtr.Zero);
339 | Marshal.PtrToStructure(psSerialBaudRate, sSerialBaudRate);
340 | Marshal.FreeHGlobal(psSerialBaudRate);
341 |
342 | // Get Serial Line control
343 | NativeStructs.SERIAL_LINE_CONTROL sSerialLineControl = new NativeStructs.SERIAL_LINE_CONTROL();
344 | IntPtr psSerialLineControl = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialLineControl));
345 | Marshal.StructureToPtr(sSerialLineControl, psSerialLineControl, false);
346 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_LINE_CONTROL, IntPtr.Zero, 0, psSerialLineControl,
347 | Marshal.SizeOf(sSerialLineControl), out unBytesReturned, IntPtr.Zero);
348 | Marshal.PtrToStructure(psSerialLineControl, sSerialLineControl);
349 | Marshal.FreeHGlobal(psSerialLineControl);
350 |
351 | // Get Serial CHARS
352 | NativeStructs.SERIAL_CHARS sSerialChars = new NativeStructs.SERIAL_CHARS();
353 | IntPtr psSerialChars = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialChars));
354 | Marshal.StructureToPtr(sSerialChars, psSerialChars, false);
355 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_CHARS, IntPtr.Zero, 0, psSerialChars,
356 | Marshal.SizeOf(sSerialChars), out unBytesReturned, IntPtr.Zero);
357 | Marshal.PtrToStructure(psSerialChars, sSerialChars);
358 | Marshal.FreeHGlobal(psSerialChars);
359 |
360 | // Get Serial Handflow
361 | NativeStructs.SERIAL_HANDFLOW sSerialHandFlow = new NativeStructs.SERIAL_HANDFLOW();
362 | IntPtr psSerialHandFlow = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialHandFlow));
363 | Marshal.StructureToPtr(sSerialHandFlow, psSerialHandFlow, false);
364 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_HANDFLOW, IntPtr.Zero, 0, psSerialHandFlow,
365 | Marshal.SizeOf(sSerialHandFlow), out unBytesReturned, IntPtr.Zero);
366 | Marshal.PtrToStructure(psSerialHandFlow, sSerialHandFlow);
367 | Marshal.FreeHGlobal(psSerialHandFlow);
368 |
369 | // Get Serial Baudrate
370 | sSerialBaudRate = new NativeStructs.SERIAL_BAUD_RATE();
371 | psSerialBaudRate = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialBaudRate));
372 | Marshal.StructureToPtr(sSerialBaudRate, psSerialBaudRate, false);
373 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_BAUD_RATE, IntPtr.Zero, 0, psSerialBaudRate,
374 | Marshal.SizeOf(sSerialBaudRate), out unBytesReturned, IntPtr.Zero);
375 | Marshal.PtrToStructure(psSerialBaudRate, sSerialBaudRate);
376 | Marshal.FreeHGlobal(psSerialBaudRate);
377 |
378 | // Get Serial Line control
379 | sSerialLineControl = new NativeStructs.SERIAL_LINE_CONTROL();
380 | psSerialLineControl = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialLineControl));
381 | Marshal.StructureToPtr(sSerialLineControl, psSerialLineControl, false);
382 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_LINE_CONTROL, IntPtr.Zero, 0, psSerialLineControl,
383 | Marshal.SizeOf(sSerialLineControl), out unBytesReturned, IntPtr.Zero);
384 | Marshal.PtrToStructure(psSerialLineControl, sSerialLineControl);
385 | Marshal.FreeHGlobal(psSerialLineControl);
386 |
387 | // Get Serial CHARS
388 | sSerialChars = new NativeStructs.SERIAL_CHARS();
389 | psSerialChars = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialChars));
390 | Marshal.StructureToPtr(sSerialChars, psSerialChars, false);
391 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_CHARS, IntPtr.Zero, 0, psSerialChars,
392 | Marshal.SizeOf(sSerialChars), out unBytesReturned, IntPtr.Zero);
393 | Marshal.PtrToStructure(psSerialChars, sSerialChars);
394 | Marshal.FreeHGlobal(psSerialChars);
395 |
396 | // Get Serial Handflow
397 | sSerialHandFlow = new NativeStructs.SERIAL_HANDFLOW();
398 | psSerialHandFlow = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialHandFlow));
399 | Marshal.StructureToPtr(sSerialHandFlow, psSerialHandFlow, false);
400 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_HANDFLOW, IntPtr.Zero, 0, psSerialHandFlow,
401 | Marshal.SizeOf(sSerialHandFlow), out unBytesReturned, IntPtr.Zero);
402 | Marshal.PtrToStructure(psSerialHandFlow, sSerialHandFlow);
403 | Marshal.FreeHGlobal(psSerialHandFlow);
404 |
405 | // Set Serial BaudRate
406 | sSerialBaudRate = new NativeStructs.SERIAL_BAUD_RATE();
407 | sSerialBaudRate.BaudRate = 300;
408 | psSerialBaudRate = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialBaudRate));
409 | Marshal.StructureToPtr(sSerialBaudRate, psSerialBaudRate, false);
410 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_BAUD_RATE, psSerialBaudRate,
411 | Marshal.SizeOf(sSerialBaudRate), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero);
412 | Marshal.FreeHGlobal(psSerialBaudRate);
413 |
414 | // Set Serial RTS
415 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_RTS, IntPtr.Zero, 0,
416 | IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero);
417 |
418 | // Set Serial DTR
419 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_DTR, IntPtr.Zero, 0,
420 | IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero);
421 |
422 | // Set Serial Line control
423 | sSerialLineControl = new NativeStructs.SERIAL_LINE_CONTROL();
424 | sSerialLineControl.StopBits = 0x00;
425 | sSerialLineControl.Parity = 0x00;
426 | sSerialLineControl.WordLength = 0x08;
427 | psSerialLineControl = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialLineControl));
428 | Marshal.StructureToPtr(sSerialLineControl, psSerialLineControl, false);
429 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_LINE_CONTROL,
430 | psSerialLineControl, Marshal.SizeOf(sSerialLineControl), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero);
431 | Marshal.FreeHGlobal(psSerialLineControl);
432 |
433 | // Set Serial CHARS
434 | sSerialChars = new NativeStructs.SERIAL_CHARS();
435 | sSerialChars.EofChar = 0x00;
436 | sSerialChars.ErrorChar = 0x00;
437 | sSerialChars.BreakChar = 0x00;
438 | sSerialChars.EventChar = 0x00;
439 | sSerialChars.XonChar = 0x11;
440 | sSerialChars.XoffChar = 0x13;
441 | psSerialChars = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialChars));
442 | Marshal.StructureToPtr(sSerialChars, psSerialChars, false);
443 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_CHARS, psSerialChars,
444 | Marshal.SizeOf(sSerialChars), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero);
445 | Marshal.FreeHGlobal(psSerialChars);
446 |
447 | // Set Serial Handflow
448 | sSerialHandFlow = new NativeStructs.SERIAL_HANDFLOW();
449 | sSerialHandFlow.ControlHandShake = 0x00000001;
450 | sSerialHandFlow.FlowReplace = 0x00000040;
451 | sSerialHandFlow.XonLimit = 0x000086C0;
452 | sSerialHandFlow.XoffLimit = 0x000021B0;
453 | psSerialHandFlow = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialHandFlow));
454 | Marshal.StructureToPtr(sSerialHandFlow, psSerialHandFlow, false);
455 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_HANDFLOW, psSerialHandFlow,
456 | Marshal.SizeOf(sSerialHandFlow), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero);
457 | Marshal.FreeHGlobal(psSerialHandFlow);
458 | }
459 | }
460 | catch (Exception ex)
461 | {
462 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK,
463 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
464 | }
465 |
466 | return bResult;
467 | }
468 |
469 | /*
470 | * Function Name: ReadConfigurationData
471 | * Description: This function reads the configuration data from CH340B's EEPROM and returns the data to the caller
472 | * Arguments:
473 | * int nSelectedDeviceIndex - index of the selected device - this denotes the index in the device list if
474 | * there are multiple devices found. If there is only one device, then its value would be 0
475 | * ref CH340BConfigurationData oCH340BConfigurationData - reference of the object of type CH340BConfigurationData
476 | * on returning this function, this oCH340BConfigurationData will have the actual configuration data read from the
477 | * chip.
478 | * Return: boolean value - true if the read function finishes successfully, else false
479 | */
480 | internal bool ReadConfigurationData(int nSelectedDeviceIndex, ref CH340BConfigurationData oCH340BConfigurationData)
481 | {
482 | bool bResult = false;
483 |
484 | try
485 | {
486 | // Open the device handle
487 | pHandle = NativeMethods.CreateFile(aoDevInfo[nSelectedDeviceIndex].szComportNameForHandle, Constants.GENERIC_READ | Constants.GENERIC_WRITE,
488 | Constants.FILE_SHARE_READ | Constants.FILE_SHARE_WRITE, IntPtr.Zero, Constants.OPEN_EXISTING, 0, IntPtr.Zero);
489 | if (pHandle == IntPtr.Zero || pHandle == Constants.INVALID_HANDLE_VALUE)
490 | {
491 | MessageBox.Show("Can't open device for reading configuration data.", "CH340B Configuration Utlity", MessageBoxButtons.OK,
492 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
493 | return bResult;
494 | }
495 | // Initialize the vendor interface of the CH340B driver
496 | InitializeCh340BVendorInterface(pHandle);
497 | // Read USB Vendor ID
498 | // Read the E2PROM location 0x04 and 0x05
499 | ushort ushVID = 0x0000;
500 | ushort ushVIDLSB = 0x0000;
501 | ushort ushVIDMSB = 0x0000;
502 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x04, 0x00 };
503 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
504 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero);
505 | ushVIDLSB = abyReadData[0];
506 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x05, 0x00 };
507 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
508 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero);
509 | ushVIDMSB = abyReadData[0];
510 | ushVID = (ushort)((ushVIDMSB << 8) | ushVIDLSB);
511 | oCH340BConfigurationData.ushVID = ushVID;
512 |
513 | // Read USB Product ID
514 | // Read the E2PROM location 0x06 and 0x07
515 | ushort ushPID = 0x0000;
516 | ushort ushPIDLSB = 0x0000;
517 | ushort ushPIDMSB = 0x0000;
518 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x06, 0x00 };
519 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
520 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero);
521 | ushPIDLSB = abyReadData[0];
522 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x07, 0x00 };
523 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
524 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero);
525 | ushPIDMSB = abyReadData[0];
526 | ushPID = (ushort)((ushPIDMSB << 8) | ushPIDLSB);
527 | oCH340BConfigurationData.ushPID = ushPID;
528 |
529 | // Read USB Product String
530 | // Read the E2PROM location 0x1A
531 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x1A, 0x00 };
532 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
533 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero);
534 | byte byUnicodeStringLength = abyReadData[0];
535 |
536 | // Read the E2PROM location 0x1B
537 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x1B, 0x00 };
538 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
539 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero);
540 | int nUsbProductStringIndentifier = abyReadData[0];
541 |
542 | // Read the E2PROM location 0x1C to 0x3F
543 | byte i = 0x1C;
544 | byte[] abyUnicodeProductString = new byte[36];
545 | int nIndex = 0;
546 | for (; i <= 0x3F; i++)
547 | {
548 | abyWriteData = new byte[4] { 0x40, 0xA1, i, 0x00 };
549 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
550 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero);
551 | abyUnicodeProductString[nIndex++] = abyReadData[0];
552 | }
553 |
554 | // Perform the conversion from one encoding to the other.
555 | byte[] abyAsciiProductString = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, abyUnicodeProductString, 0, byUnicodeStringLength - 2);
556 | // Convert the new byte[] into a char[] and then into a string.
557 | // This is a slightly different approach to converting to illustrate
558 | // the use of GetCharCount/GetChars.
559 | char[] asciiChars = new char[Encoding.UTF8.GetCharCount(abyAsciiProductString, 0, abyAsciiProductString.Length)];
560 | Encoding.UTF8.GetChars(abyAsciiProductString, 0, abyAsciiProductString.Length, asciiChars, 0);
561 | string asciiProductString = new string(asciiChars);
562 | oCH340BConfigurationData.szProductString = asciiProductString;
563 |
564 | // Read USB Serial Number
565 | // Read EEPROM location 0x10 to 0x17
566 | string szSerialNumber = "";
567 | i = 0x10;
568 | byte[] abyAsciiSerialNumberString = new byte[8];
569 | nIndex = 0;
570 | for (; i <= 0x17; i++) // 0x17 is the last EEPROM location to access
571 | {
572 | abyWriteData = new byte[4] { 0x40, 0xA1, i, 0x00 };
573 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
574 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero);
575 | abyAsciiSerialNumberString[nIndex++] = abyReadData[0];
576 | }
577 | if (abyAsciiSerialNumberString[0] > 0x21 && abyAsciiSerialNumberString[0] < 0x7F)
578 | {
579 | asciiChars = new char[Encoding.ASCII.GetCharCount(abyAsciiSerialNumberString, 0, abyAsciiSerialNumberString.Length)];
580 | Encoding.ASCII.GetChars(abyAsciiSerialNumberString, 0, abyAsciiSerialNumberString.Length, asciiChars, 0);
581 | szSerialNumber = new string(asciiChars);
582 | }
583 | oCH340BConfigurationData.szSerialNumber = szSerialNumber;
584 | bResult = true;
585 | }
586 | catch (Exception ex)
587 | {
588 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK,
589 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
590 | }
591 | try
592 | {
593 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE)
594 | {
595 | NativeMethods.CloseHandle(pHandle);
596 | }
597 | }
598 | catch (Exception ex)
599 | {
600 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK,
601 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
602 | }
603 | return bResult;
604 | }
605 |
606 | /*
607 | * Function Name: WriteConfigurationData
608 | * Description: This function writes the configuration data to CH340B's EEPROM
609 | * Arguments:
610 | * int nSelectedDeviceIndex - index of the selected device - this denotes the index in the device list if
611 | * there are multiple devices found. If there is only one device, then its value would be 0
612 | * CH340BConfigurationData oCH340BConfigurationData - reference of the object of type CH340BConfigurationData
613 | * this oCH340BConfigurationData will have the actual configuration data that is filled by the caller.
614 | * Return: boolean value - true if the write function finishes successfully, else false
615 | */
616 | internal bool WriteConfigurationData(int nSelectedDeviceIndex, CH340BConfigurationData oCH340BConfigurationData)
617 | {
618 | bool bResult = false;
619 |
620 | do
621 | {
622 | try
623 | {
624 | ushort ushVID = oCH340BConfigurationData.ushVID;
625 | ushort ushPID = oCH340BConfigurationData.ushPID;
626 | string szSerialNumber = oCH340BConfigurationData.szSerialNumber;
627 | string szProductString = oCH340BConfigurationData.szProductString;
628 |
629 | // Open device handle
630 | pHandle = NativeMethods.CreateFile(aoDevInfo[nSelectedDeviceIndex].szComportNameForHandle, Constants.GENERIC_READ | Constants.GENERIC_WRITE,
631 | Constants.FILE_SHARE_READ | Constants.FILE_SHARE_WRITE, IntPtr.Zero, Constants.OPEN_EXISTING, 0, IntPtr.Zero);
632 | if (pHandle == IntPtr.Zero || pHandle == Constants.INVALID_HANDLE_VALUE)
633 | {
634 | MessageBox.Show("Can't open device for writing configuration data.", "CH340B Configuration Utlity", MessageBoxButtons.OK,
635 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
636 | break;
637 | }
638 | InitializeCh340BVendorInterface(pHandle);
639 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x00, 0x5B };
640 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
641 | // all the values are now validated
642 |
643 | // Write VID to EEPROM 0x04 (LSB) and 0x05 (MSB)
644 | Byte byVIDLSB = (Byte)(ushVID & 0xFF);
645 | Byte byVIDMSB = (Byte)(ushVID >> 8 & 0xFF);
646 |
647 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x04, byVIDLSB };
648 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
649 |
650 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x05, byVIDMSB };
651 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
652 |
653 | // Write PID to EEPROM 0x06 (LSB) and 0x07 (MSB)
654 | Byte byPIDLSB = (Byte)(ushPID & 0xFF);
655 | Byte byPIDMSB = (Byte)(ushPID >> 8 & 0xFF);
656 |
657 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x06, byPIDLSB };
658 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
659 |
660 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x07, byPIDMSB };
661 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
662 |
663 | // Write Serial number to EEPROM
664 | if (string.IsNullOrEmpty(szSerialNumber) == false)
665 | {
666 | // Valid Serail number, write it to EEPROM location 0x10 to 0x17
667 | byte[] abyAsciiSerialNumber = Encoding.ASCII.GetBytes(szSerialNumber);
668 |
669 | // form a 8 byte array
670 | int nSerialNumberLength = abyAsciiSerialNumber.Length;
671 |
672 | if (nSerialNumberLength > 8)
673 | {
674 | nSerialNumberLength = 8;
675 | }
676 |
677 | byte[] abySerialNumber = new byte[8];
678 | Array.Copy(abyAsciiSerialNumber, abySerialNumber, nSerialNumberLength);
679 | int nIndex = 0;
680 | for (byte i = 0x10; i <= 0x17; i++)
681 | {
682 | abyWriteData = new byte[4] { 0x40, 0xA0, i, abySerialNumber[nIndex++] };
683 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
684 | }
685 | }
686 | else
687 | {
688 | // Serial number is empty
689 | // Clear the Serial number
690 | byte[] abySerialNumber = new byte[8];
691 | Array.Clear(abySerialNumber, 0, abySerialNumber.Length);
692 | int nIndex = 0;
693 | for (byte i = 0x10; i <= 0x17; i++)
694 | {
695 | abyWriteData = new byte[4] { 0x40, 0xA0, i, abySerialNumber[nIndex++] };
696 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
697 | }
698 | }
699 |
700 | // Write Product String to device
701 | // Prepare the array of bytes with Unicode byte values of the string and write the array to EEPROM location 0x1A to 0x3F
702 | if (string.IsNullOrEmpty(szProductString) == false)
703 | {
704 | byte[] abyUnicodeProdString = Encoding.Unicode.GetBytes(szProductString);
705 |
706 | // form a 38 byte array
707 | byte[] abyProdStringBuffer = new byte[38];
708 | abyProdStringBuffer[0] = (byte)(abyUnicodeProdString.Length + 2);
709 | abyProdStringBuffer[1] = 0x03;
710 |
711 | Array.Copy(abyUnicodeProdString, 0, abyProdStringBuffer, 2, abyUnicodeProdString.Length);
712 |
713 | int nIndex = 0;
714 | for (byte i = 0x1A; i <= 0x3F; i++)
715 | {
716 | abyWriteData = new byte[4] { 0x40, 0xA0, i, abyProdStringBuffer[nIndex++] };
717 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero);
718 | }
719 | }
720 | }
721 | catch (Exception ex)
722 | {
723 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK,
724 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
725 | }
726 |
727 | } while (false);
728 | try
729 | {
730 | // Close the device handle
731 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE)
732 | {
733 | NativeMethods.CloseHandle(pHandle);
734 | }
735 | }
736 | catch (Exception ex)
737 | {
738 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK,
739 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
740 | }
741 | return bResult;
742 | }
743 | }
744 | }
745 |
--------------------------------------------------------------------------------