├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── screenshots ├── 1.png └── 2.png └── src ├── Canaan.Kendryte.Flash.Cli ├── Canaan.Kendryte.Flash.Cli.csproj ├── Canaan.Kendryte.Flash.Cli.csproj.user ├── Controls │ ├── ConsoleProgressBar.cs │ └── ProgressAnimations.cs ├── Program.cs ├── Properties │ ├── PublishProfiles │ │ ├── FolderProfile.pubxml │ │ ├── FolderProfile.pubxml.user │ │ └── FolderProfile1.pubxml │ └── launchSettings.json └── Services │ ├── FlashService.cs │ └── ProgressIndicator.cs ├── Canaan.Kendryte.Flash.Shell ├── App.config ├── App.xaml ├── App.xaml.cs ├── AppBootstrapper.cs ├── Assets │ ├── Styles.xaml │ ├── k-flash.png │ └── plink.exe.gz ├── Canaan.Kendryte.Flash.Shell.csproj ├── Canaan.Kendryte.Flash.Shell.csproj.user ├── FodyWeavers.xml ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Resources │ └── LICENSE.txt ├── Services │ ├── SerialPortEnumerator.cs │ └── TerminalService.cs ├── ViewModels │ ├── FlashViewModel.cs │ ├── IShell.cs │ └── ShellViewModel.cs ├── Views │ ├── FlashView.xaml │ ├── FlashView.xaml.cs │ └── ShellView.xaml ├── k-flash.ico └── packages.config ├── Canaan.Kendryte.Flash.sln ├── Canaan.Kendryte.Flash ├── Canaan.Kendryte.Flash.csproj ├── FlashModeResponse.cs ├── FlashPackage.cs ├── ISPResponse.cs ├── KendryteLoader.cs └── Resources │ └── isp_flash.bin └── NuGet.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | autom4te.cache 2 | build 3 | build_i 4 | config.log 5 | config.status 6 | Makefile 7 | .DS_Store 8 | !/regression/Makefile 9 | .vs 10 | .vscode 11 | CMakeSettings.json 12 | *.dtb 13 | bin 14 | obj 15 | packages/ 16 | *.user 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2018 Canaan Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Kendryte Flash 2 | === 3 | 4 | ## Introduction 5 | 6 | Kendryte flash utility. 7 | 8 | ## Requirements 9 | 10 | ### GUI 11 | Microsoft [.NET Framework 4.7.1](https://www.microsoft.com/net/download/thank-you/net471) or higher. 12 | 13 | ![Screenshots](screenshots/1.png) 14 | 15 | ### CLI 16 | 17 | ![Screenshots](screenshots/2.png) -------------------------------------------------------------------------------- /screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kendryte/kendryte-flash-windows/4d5d11b236646b9eea4805c33241873c17463039/screenshots/1.png -------------------------------------------------------------------------------- /screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kendryte/kendryte-flash-windows/4d5d11b236646b9eea4805c33241873c17463039/screenshots/2.png -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Canaan.Kendryte.Flash.Cli.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.0 6 | win-x86;linux-x64 7 | K-Flash 8 | 0.3.3.0 9 | K-Flash 10 | Kendryte flash utility 11 | Copyright 2018 Canaan Inc. 12 | latest 13 | k-flash 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Canaan.Kendryte.Flash.Cli.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | <_LastSelectedProfileId>D:\Work\Repository\kendryte-flash-windows\src\Canaan.Kendryte.Flash.Cli\Properties\PublishProfiles\FolderProfile1.pubxml 5 | 6 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Controls/ConsoleProgressBar.cs: -------------------------------------------------------------------------------- 1 | namespace AaronLuna.ConsoleProgressBar 2 | { 3 | using System; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | 8 | public class ConsoleProgressBar : IDisposable, IProgress 9 | { 10 | private readonly TimeSpan _animationInterval = TimeSpan.FromSeconds(1.0 / 8); 11 | 12 | private string _currentText = string.Empty; 13 | internal int AnimationIndex; 14 | internal double CurrentProgress; 15 | internal bool Disposed; 16 | 17 | internal Timer Timer; 18 | 19 | public ConsoleProgressBar() 20 | { 21 | Console.OutputEncoding = Encoding.UTF8; 22 | 23 | NumberOfBlocks = 10; 24 | StartBracket = "["; 25 | EndBracket = "]"; 26 | CompletedBlock = "#"; 27 | IncompleteBlock = "-"; 28 | AnimationSequence = ProgressAnimations.Default; 29 | 30 | DisplayBar = true; 31 | DisplayPercentComplete = true; 32 | DisplayAnimation = true; 33 | 34 | Timer = new Timer(TimerHandler); 35 | 36 | // A progress bar is only for temporary display in a console window. 37 | // If the console output is redirected to a file, draw nothing. 38 | // Otherwise, we'll end up with a lot of garbage in the target file. 39 | if (!Console.IsOutputRedirected) ResetTimer(); 40 | } 41 | 42 | public int NumberOfBlocks { get; set; } 43 | public string StartBracket { get; set; } 44 | public string EndBracket { get; set; } 45 | public string CompletedBlock { get; set; } 46 | public string IncompleteBlock { get; set; } 47 | public string AnimationSequence { get; set; } 48 | public bool DisplayBar { get; set; } 49 | public bool DisplayPercentComplete { get; set; } 50 | public bool DisplayAnimation { get; set; } 51 | 52 | public void Dispose() 53 | { 54 | Dispose(true); 55 | GC.SuppressFinalize(this); 56 | } 57 | 58 | public void Report(double value) 59 | { 60 | // Make sure value is in [0..1] range 61 | value = Math.Max(0, Math.Min(1, value)); 62 | Interlocked.Exchange(ref CurrentProgress, value); 63 | } 64 | 65 | private void TimerHandler(object state) 66 | { 67 | lock (Timer) 68 | { 69 | if (Disposed) return; 70 | UpdateText(GetProgressBarText(CurrentProgress)); 71 | ResetTimer(); 72 | } 73 | } 74 | 75 | private string GetProgressBarText(double currentProgress) 76 | { 77 | const string singleSpace = " "; 78 | 79 | var numBlocksCompleted = (int)(currentProgress * NumberOfBlocks); 80 | 81 | var completedBlocks = 82 | Enumerable.Range(0, numBlocksCompleted).Aggregate( 83 | string.Empty, 84 | (current, _) => current + CompletedBlock); 85 | 86 | var incompleteBlocks = 87 | Enumerable.Range(0, NumberOfBlocks - numBlocksCompleted).Aggregate( 88 | string.Empty, 89 | (current, _) => current + IncompleteBlock); 90 | 91 | var progressBar = $"{StartBracket}{completedBlocks}{incompleteBlocks}{EndBracket}"; 92 | var percent = $"{currentProgress:P0}".PadLeft(4, '\u00a0'); 93 | var animationFrame = AnimationSequence[AnimationIndex++ % AnimationSequence.Length]; 94 | var animation = $"{animationFrame}"; 95 | 96 | progressBar = DisplayBar 97 | ? progressBar + singleSpace 98 | : string.Empty; 99 | 100 | percent = DisplayPercentComplete 101 | ? percent + singleSpace 102 | : string.Empty; 103 | 104 | if (!DisplayAnimation || currentProgress is 1) 105 | { 106 | animation = string.Empty; 107 | } 108 | 109 | return (progressBar + percent + animation).TrimEnd(); 110 | } 111 | 112 | internal void UpdateText(string text) 113 | { 114 | // Get length of common portion 115 | var commonPrefixLength = 0; 116 | var commonLength = Math.Min(_currentText.Length, text.Length); 117 | while (commonPrefixLength < commonLength && text[commonPrefixLength] == _currentText[commonPrefixLength]) 118 | commonPrefixLength++; 119 | 120 | // Backtrack to the first differing character 121 | var outputBuilder = new StringBuilder(); 122 | outputBuilder.Append('\b', _currentText.Length - commonPrefixLength); 123 | 124 | // Output new suffix 125 | outputBuilder.Append(text.Substring(commonPrefixLength)); 126 | 127 | // If the new text is shorter than the old one: delete overlapping characters 128 | var overlapCount = _currentText.Length - text.Length; 129 | if (overlapCount > 0) 130 | { 131 | outputBuilder.Append(' ', overlapCount); 132 | outputBuilder.Append('\b', overlapCount); 133 | } 134 | 135 | //Console.Write($"{Caption}{outputBuilder}"); 136 | Console.Write(outputBuilder); 137 | _currentText = text; 138 | } 139 | 140 | internal void ResetTimer() 141 | { 142 | Timer.Change(_animationInterval, TimeSpan.FromMilliseconds(-1)); 143 | } 144 | 145 | protected virtual void Dispose(bool disposing) 146 | { 147 | if (!disposing) return; 148 | 149 | lock (Timer) 150 | { 151 | Disposed = true; 152 | } 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Controls/ProgressAnimations.cs: -------------------------------------------------------------------------------- 1 | namespace AaronLuna.ConsoleProgressBar 2 | { 3 | using System; 4 | using System.Linq; 5 | 6 | using Microsoft.VisualBasic; 7 | 8 | public static class ProgressAnimations 9 | { 10 | // These characters render correctly on Windows and Mac 11 | public const string Default = @"|/-\-"; 12 | public const string BouncingBall = ".oO\u00b0Oo."; 13 | public const string Explosion = ".oO@*"; 14 | public const string RotatingTriangle = "\u25b2\u25ba\u25bc\u25c4"; 15 | public const string RotatingArrow = "\u2190\u2191\u2192\u2193"; 16 | public const string PulsingLine = "\u2212\u003d\u2261\u039e\u2261\u003d\u2212"; 17 | public const string Circles = "\u25cb\u263c\u00a4\u2219"; 18 | 19 | // These characters render correctly only on Mac 20 | public const string RotatingDot = "\u25dc\u25dd\u25de\u25df"; 21 | public const string GrowingBarVertical = "\u2581\u2582\u2583\u2584\u2585\u2586\u2587\u2588\u2587\u2586\u2585\u2584\u2583\u2581"; 22 | public const string RotatingPipe = "\u2524\u2518\u2534\u2514\u251c\u250c\u252c\u2510"; 23 | public const string RotatingCircle = "\u25d0\u25d3\u25d1\u25d2"; 24 | public const string GrowingBarHorizontal = "\u2589\u258a\u258b\u258c\u258d\u258e\u258f\u258e\u258d\u258c\u258b\u258a\u2589"; 25 | 26 | public static string RandomBrailleSequence() 27 | { 28 | var rand = new Random(); 29 | var sequence = string.Empty; 30 | foreach (int i in Enumerable.Range(0, 40)) 31 | { 32 | var charIndex = rand.Next(10241, 10496); 33 | var randChar = Strings.ChrW(charIndex); 34 | sequence += randChar; 35 | } 36 | 37 | return sequence; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Canaan.Kendryte.Flash.Cli.Services; 5 | using CommandLine; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace Canaan.Kendryte.Flash.Cli 10 | { 11 | public class Options 12 | { 13 | [Option('d', "device", Required = true, HelpText = "Set the serial device to communicate with Kendryte.")] 14 | public string Device { get; set; } 15 | 16 | [Option('b', "baudrate", Required = false, HelpText = "Set the serial device to communicate with Kendryte.", Default = 2000000)] 17 | public int BaudRate { get; set; } 18 | 19 | [Value(0, MetaName = "firmware", HelpText = "Firmware path")] 20 | public string Firmware { get; set; } 21 | } 22 | 23 | class Program 24 | { 25 | static async Task Main(string[] args) 26 | { 27 | FlashService flashService = null; 28 | 29 | Parser.Default.ParseArguments(args) 30 | .WithParsed(options => 31 | { 32 | var serviceProvider = new ServiceCollection() 33 | .AddSingleton() 34 | .AddSingleton() 35 | .AddSingleton(options) 36 | .AddLogging(c => 37 | { 38 | c.AddConsole(); 39 | }) 40 | .BuildServiceProvider(); 41 | 42 | AppDomain.CurrentDomain.UnhandledException += (s, e) => 43 | { 44 | if (e.ExceptionObject is Exception ex) 45 | Console.WriteLine("Fatal: " + ex.Message); 46 | else 47 | Console.WriteLine("Fatal: Unexpected error occurred."); 48 | Environment.Exit(-1); 49 | }; 50 | 51 | flashService = serviceProvider.GetRequiredService(); 52 | }); 53 | 54 | if (flashService != null) 55 | { 56 | await flashService.StartAsync(default(CancellationToken)); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | Release 9 | Any CPU 10 | netcoreapp3.0 11 | bin\Release\netcoreapp3.0\win-x64\publish\ 12 | win-x64 13 | true 14 | <_IsPortable>false 15 | 16 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Properties/PublishProfiles/FolderProfile.pubxml.user: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Properties/PublishProfiles/FolderProfile1.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | Release 9 | Any CPU 10 | netcoreapp3.0 11 | bin\Release\netcoreapp3.0\linux-x64\publish\ 12 | linux-x64 13 | true 14 | <_IsPortable>false 15 | 16 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Canaan.Kendryte.Flash.Cli": { 4 | "commandName": "Project", 5 | "commandLineArgs": "-d COM5 D:\\Work\\Repository\\kendryte-freertos-sdk\\build\\hello_world.bin" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Services/FlashService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace Canaan.Kendryte.Flash.Cli.Services 10 | { 11 | internal class FlashService 12 | { 13 | private readonly Options _options; 14 | private readonly uint _chip = 1; 15 | private readonly ProgressIndicator _progressIndicator; 16 | 17 | public FlashService(Options options, ProgressIndicator progressIndicator) 18 | { 19 | _options = options; 20 | _progressIndicator = progressIndicator; 21 | } 22 | 23 | public Task StartAsync(CancellationToken cancellationToken) 24 | { 25 | return StartFlash(); 26 | } 27 | 28 | public Task StopAsync(CancellationToken cancellationToken) 29 | { 30 | return Task.CompletedTask; 31 | } 32 | 33 | public async Task StartFlash() 34 | { 35 | if (string.IsNullOrEmpty(_options.Firmware)) 36 | throw new InvalidOperationException("Must specify firmware path."); 37 | var firmwareType = GetFirmwareType(_options.Firmware); 38 | if (firmwareType == FirmwareType.Unknown) 39 | throw new InvalidOperationException("Unknown firmware type."); 40 | if (string.IsNullOrEmpty(_options.Device)) 41 | throw new InvalidOperationException("Must select device."); 42 | if (_options.BaudRate < 110) 43 | throw new InvalidOperationException("Invalid baud rate."); 44 | 45 | using (var loader = new KendryteLoader(_options.Device, _options.BaudRate)) 46 | { 47 | loader.CurrentJobChanged += (s, e) => 48 | { 49 | _progressIndicator.SetJobItem(loader.CurrentJob, loader.JobItemsStatus[loader.CurrentJob]); 50 | }; 51 | 52 | Console.WriteLine("Flashing..."); 53 | await loader.DetectBoard(); 54 | await loader.InstallFlashBootloader(); 55 | await loader.BootBootloader(); 56 | await loader.FlashGreeting(); 57 | await loader.ChangeBaudRate(); 58 | await loader.InitializeFlash(_chip); 59 | 60 | if (firmwareType == FirmwareType.Single) 61 | { 62 | using (var file = File.OpenRead(_options.Firmware)) 63 | using (var br = new BinaryReader(file)) 64 | { 65 | await loader.FlashFirmware(0, br.ReadBytes((int)file.Length), true, false); 66 | } 67 | } 68 | else if (firmwareType == FirmwareType.FlashList) 69 | { 70 | using (var pkg = new FlashPackage(File.OpenRead(_options.Firmware))) 71 | { 72 | await pkg.LoadAsync(); 73 | 74 | foreach (var item in pkg.Files) 75 | { 76 | using (var br = new BinaryReader(item.Bin)) 77 | { 78 | await loader.FlashFirmware(item.Address, br.ReadBytes((int)item.Length), item.SHA256Prefix, item.Reverse4Bytes); 79 | } 80 | } 81 | } 82 | } 83 | 84 | await loader.Reboot(); 85 | } 86 | 87 | Console.WriteLine(Environment.NewLine + "Flash completed!"); 88 | } 89 | 90 | private FirmwareType GetFirmwareType(string firmware) 91 | { 92 | var ext = Path.GetExtension(firmware).ToLowerInvariant(); 93 | 94 | switch (ext) 95 | { 96 | case ".bin": 97 | return FirmwareType.Single; 98 | case ".kfpkg": 99 | return FirmwareType.FlashList; 100 | default: 101 | return FirmwareType.Unknown; 102 | } 103 | } 104 | 105 | private enum FirmwareType 106 | { 107 | Single, 108 | FlashList, 109 | Unknown 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Cli/Services/ProgressIndicator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Text; 5 | using AaronLuna.ConsoleProgressBar; 6 | 7 | namespace Canaan.Kendryte.Flash.Cli.Services 8 | { 9 | internal class ProgressIndicator 10 | { 11 | private readonly ConsoleProgressBar _progressBar; 12 | private JobItemStatus _jobItem; 13 | 14 | public ProgressIndicator() 15 | { 16 | _progressBar = new ConsoleProgressBar(); 17 | } 18 | 19 | public void SetJobItem(JobItemType itemType, JobItemStatus jobItem) 20 | { 21 | if(_jobItem != null) 22 | _jobItem.PropertyChanged -= JobItem_PropertyChanged; 23 | 24 | _jobItem = jobItem; 25 | jobItem.PropertyChanged += JobItem_PropertyChanged; 26 | _progressBar.UpdateText(itemType.ToString()); 27 | } 28 | 29 | private void JobItem_PropertyChanged(object sender, PropertyChangedEventArgs e) 30 | { 31 | switch (e.PropertyName) 32 | { 33 | case nameof(JobItemStatus.Progress): 34 | _progressBar.Report(_jobItem.Progress); 35 | break; 36 | default: 37 | break; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Assets/k-flash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kendryte/kendryte-flash-windows/4d5d11b236646b9eea4805c33241873c17463039/src/Canaan.Kendryte.Flash.Shell/Assets/k-flash.png -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Assets/plink.exe.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kendryte/kendryte-flash-windows/4d5d11b236646b9eea4805c33241873c17463039/src/Canaan.Kendryte.Flash.Shell/Assets/plink.exe.gz -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Canaan.Kendryte.Flash.Shell.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F7419577-0D3F-412E-814A-7C8F690CF133} 8 | WinExe 9 | Canaan.Kendryte.Flash.Shell 10 | K-Flash 11 | v4.7.1 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | true 17 | 18 | 19 | 20 | 21 | AnyCPU 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | 7.2 30 | true 31 | 32 | 33 | AnyCPU 34 | pdbonly 35 | true 36 | bin\Release\ 37 | TRACE 38 | prompt 39 | 4 40 | 7.2 41 | true 42 | 43 | 44 | k-flash.ico 45 | 46 | 47 | 48 | 49 | 50 | 51 | packages\Caliburn.Micro.Core.3.2.0\lib\net45\Caliburn.Micro.dll 52 | 53 | 54 | packages\Caliburn.Micro.3.2.0\lib\net45\Caliburn.Micro.Platform.dll 55 | 56 | 57 | packages\Caliburn.Micro.3.2.0\lib\net45\Caliburn.Micro.Platform.Core.dll 58 | 59 | 60 | packages\ControlzEx.3.0.2.4\lib\net462\ControlzEx.dll 61 | 62 | 63 | packages\Costura.Fody.3.1.2\lib\net46\Costura.dll 64 | 65 | 66 | packages\Dragablz.0.0.3.203\lib\net45\Dragablz.dll 67 | 68 | 69 | packages\MahApps.Metro.1.6.5\lib\net47\MahApps.Metro.dll 70 | 71 | 72 | packages\MaterialDesignColors.1.1.3\lib\net45\MaterialDesignColors.dll 73 | 74 | 75 | packages\MaterialDesignThemes.MahApps.0.0.11\lib\net45\MaterialDesignThemes.MahApps.dll 76 | 77 | 78 | packages\MaterialDesignThemes.2.5.0-ci1161\lib\net45\MaterialDesignThemes.Wpf.dll 79 | 80 | 81 | packages\Microsoft.Extensions.Configuration.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll 82 | 83 | 84 | packages\Microsoft.Extensions.Configuration.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll 85 | 86 | 87 | packages\Microsoft.Extensions.Primitives.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll 88 | 89 | 90 | packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll 91 | 92 | 93 | packages\Ookii.Dialogs.1.0\lib\net35\Ookii.Dialogs.Wpf.dll 94 | 95 | 96 | ..\..\packages\PInvoke.Kernel32.0.5.184\lib\net45\PInvoke.Kernel32.dll 97 | 98 | 99 | ..\..\packages\PInvoke.User32.0.5.184\lib\net45\PInvoke.User32.dll 100 | 101 | 102 | ..\..\packages\PInvoke.Windows.Core.0.5.184\lib\net35\PInvoke.Windows.Core.dll 103 | 104 | 105 | ..\..\packages\PInvoke.Windows.ShellScalingApi.0.5.184\lib\net45\PInvoke.Windows.ShellScalingApi.dll 106 | 107 | 108 | 109 | packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll 110 | 111 | 112 | 113 | ..\..\packages\System.IO.Pipelines.4.5.2\lib\netstandard2.0\System.IO.Pipelines.dll 114 | 115 | 116 | 117 | packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll 118 | 119 | 120 | 121 | packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll 122 | 123 | 124 | packages\System.Runtime.CompilerServices.Unsafe.4.5.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll 125 | 126 | 127 | ..\..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll 128 | 129 | 130 | packages\ControlzEx.3.0.2.4\lib\net462\System.Windows.Interactivity.dll 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 4.0 140 | 141 | 142 | ..\..\packages\Validation.2.4.15\lib\net45\Validation.dll 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | MSBuild:Compile 151 | Designer 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | App.xaml 161 | Code 162 | 163 | 164 | FlashView.xaml 165 | 166 | 167 | Designer 168 | MSBuild:Compile 169 | 170 | 171 | Designer 172 | MSBuild:Compile 173 | 174 | 175 | MSBuild:Compile 176 | Designer 177 | 178 | 179 | 180 | 181 | Code 182 | 183 | 184 | True 185 | True 186 | Resources.resx 187 | 188 | 189 | True 190 | Settings.settings 191 | True 192 | 193 | 194 | ResXFileCodeGenerator 195 | Resources.Designer.cs 196 | 197 | 198 | 199 | 200 | SettingsSingleFileGenerator 201 | Settings.Designer.cs 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | {fae7f0a7-6630-4440-ac23-691a92be5b77} 219 | Canaan.Kendryte.Flash 220 | 221 | 222 | 223 | 224 | 225 | 226 | 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 227 | 228 | 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Canaan.Kendryte.Flash.Shell.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | ProjectFiles 5 | 6 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | using System.Reflection; 16 | using System.Resources; 17 | using System.Runtime.CompilerServices; 18 | using System.Runtime.InteropServices; 19 | using System.Windows; 20 | 21 | [assembly: AssemblyTitle("K-Flash")] 22 | [assembly: AssemblyDescription("Kendryte flash utility")] 23 | [assembly: AssemblyConfiguration("")] 24 | [assembly: AssemblyCompany("Canaan Inc.")] 25 | [assembly: AssemblyProduct("K-Flash")] 26 | [assembly: AssemblyCopyright("Copyright 2018 Canaan Inc.")] 27 | [assembly: AssemblyTrademark("")] 28 | [assembly: AssemblyCulture("")] 29 | 30 | [assembly: ComVisible(false)] 31 | 32 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] 33 | 34 | [assembly: AssemblyVersion("0.4.2.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Canaan.Kendryte.Flash.Shell.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Canaan.Kendryte.Flash.Shell.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性 51 | /// 重写当前线程的 CurrentUICulture 属性。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// 查找类似 Copyright 2018 Canaan Inc. 65 | /// 66 | ///Licensed under the Apache License, Version 2.0 (the "License"); 67 | ///you may not use this file except in compliance with the License. 68 | ///You may obtain a copy of the License at 69 | /// 70 | /// http://www.apache.org/licenses/LICENSE-2.0 71 | /// 72 | ///Unless required by applicable law or agreed to in writing, software 73 | ///distributed under the License is distributed on an "AS IS" BASIS, 74 | ///WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 75 | ///See the License for the specific language govern [字符串的其余部分被截断]"; 的本地化字符串。 76 | /// 77 | internal static string LICENSE { 78 | get { 79 | return ResourceManager.GetString("LICENSE", resourceCulture); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/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 | 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 | ..\Resources\LICENSE.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312 123 | 124 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Canaan.Kendryte.Flash.Shell.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Resources/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2018-2019 Canaan Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Services/SerialPortEnumerator.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | using System; 16 | using System.Collections.Generic; 17 | using System.Linq; 18 | using System.Management; 19 | using System.Text; 20 | using System.Text.RegularExpressions; 21 | using System.Threading.Tasks; 22 | using Caliburn.Micro; 23 | 24 | namespace Canaan.Kendryte.Flash.Shell.Services 25 | { 26 | public class SerialDevice : IEquatable 27 | { 28 | public string Name { get; set; } 29 | public string Port { get; set; } 30 | 31 | public override bool Equals(object obj) 32 | { 33 | return Equals(obj as SerialDevice); 34 | } 35 | 36 | public bool Equals(SerialDevice other) 37 | { 38 | return other != null && 39 | Name == other.Name && 40 | Port == other.Port; 41 | } 42 | 43 | public override int GetHashCode() 44 | { 45 | var hashCode = 48670396; 46 | hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Name); 47 | hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Port); 48 | return hashCode; 49 | } 50 | 51 | public static bool operator ==(SerialDevice device1, SerialDevice device2) 52 | { 53 | return EqualityComparer.Default.Equals(device1, device2); 54 | } 55 | 56 | public static bool operator !=(SerialDevice device1, SerialDevice device2) 57 | { 58 | return !(device1 == device2); 59 | } 60 | } 61 | 62 | public class SerialPortEnumerator : IDisposable 63 | { 64 | private static readonly Version _osVersionSupportsPnP = new Version(6, 2); 65 | 66 | private ManagementEventWatcher _arrivalWatcher; 67 | private ManagementEventWatcher _removalWatcher; 68 | 69 | public BindableCollection Devices { get; } = new BindableCollection(); 70 | 71 | public event EventHandler DevicesUpdated; 72 | 73 | public SerialPortEnumerator() 74 | { 75 | UpdateDevices(); 76 | RegisterUpdateEvents(); 77 | } 78 | 79 | private void RegisterUpdateEvents() 80 | { 81 | var deviceArrivalQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2"); 82 | var deviceRemovalQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3"); 83 | 84 | _arrivalWatcher = new ManagementEventWatcher(deviceArrivalQuery); 85 | _removalWatcher = new ManagementEventWatcher(deviceRemovalQuery); 86 | 87 | _arrivalWatcher.EventArrived += DeviceUpdated_EventHandler; 88 | _removalWatcher.EventArrived += DeviceUpdated_EventHandler; 89 | 90 | _arrivalWatcher.Start(); 91 | _removalWatcher.Start(); 92 | } 93 | 94 | private void UnregisterUpdateEvents() 95 | { 96 | if (_arrivalWatcher != null) 97 | { 98 | _arrivalWatcher.Stop(); 99 | _arrivalWatcher.EventArrived -= DeviceUpdated_EventHandler; 100 | _arrivalWatcher.Dispose(); 101 | } 102 | 103 | if (_removalWatcher != null) 104 | { 105 | _removalWatcher.Stop(); 106 | _removalWatcher.EventArrived -= DeviceUpdated_EventHandler; 107 | _removalWatcher.Dispose(); 108 | } 109 | } 110 | 111 | private void DeviceUpdated_EventHandler(object sender, EventArrivedEventArgs e) 112 | { 113 | UpdateDevices(); 114 | } 115 | 116 | private void UpdateDevices() 117 | { 118 | SelectQuery query; 119 | 120 | // Workaround for Win 7 that doesn't has 'PNPClass' property 121 | if (Environment.OSVersion.Version < _osVersionSupportsPnP) 122 | { 123 | query = new SelectQuery("Win32_PnPEntity", "Caption like '%(COM%)'", new[] { "Caption" }); 124 | } 125 | else 126 | { 127 | query = new SelectQuery("Win32_PnPEntity", "PNPClass='Ports'", new[] { "Caption" }); 128 | } 129 | 130 | var searcher = new ManagementObjectSearcher(query); 131 | 132 | Devices.Clear(); 133 | foreach (var pnpDevice in searcher.Get()) 134 | { 135 | var port = Regex.Match((string)pnpDevice["Caption"], @"(?<=\()COM\d+(?=\))"); 136 | if (port.Success) 137 | { 138 | Devices.Add(new SerialDevice 139 | { 140 | Name = (string)pnpDevice["Caption"], 141 | Port = port.Value 142 | }); 143 | } 144 | } 145 | 146 | DevicesUpdated?.Invoke(this, EventArgs.Empty); 147 | } 148 | 149 | private bool _disposedValue = false; 150 | 151 | protected virtual void Dispose(bool disposing) 152 | { 153 | if (!_disposedValue) 154 | { 155 | if (disposing) 156 | { 157 | UnregisterUpdateEvents(); 158 | } 159 | 160 | _disposedValue = true; 161 | } 162 | } 163 | 164 | public void Dispose() 165 | { 166 | Dispose(true); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Services/TerminalService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.IO.Compression; 6 | using System.Linq; 7 | using System.Runtime.InteropServices; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using PInvoke; 11 | 12 | namespace Canaan.Kendryte.Flash.Shell.Services 13 | { 14 | public class TerminalService 15 | { 16 | private readonly Kernel32.SafeObjectHandle _job; 17 | private readonly string _plinkFile; 18 | private readonly Kernel32.SafeObjectHandle _plinkHandle; 19 | private Process _process; 20 | 21 | public TerminalService() 22 | { 23 | _job = Kernel32.CreateJobObject(IntPtr.Zero, null); 24 | 25 | var limit = new Kernel32.JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); 26 | limit.BasicLimitInformation.LimitFlags = Kernel32.JOB_OBJECT_LIMIT_FLAGS.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 27 | unsafe 28 | { 29 | if (!Kernel32.SetInformationJobObject(_job, Kernel32.JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, &limit, (uint)sizeof(Kernel32.JOBOBJECT_EXTENDED_LIMIT_INFORMATION))) 30 | Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 31 | } 32 | 33 | _plinkFile = Path.GetTempFileName(); 34 | File.SetAttributes(_plinkFile, File.GetAttributes(_plinkFile) | FileAttributes.Temporary); 35 | _plinkHandle = ExtractPlink(); 36 | } 37 | 38 | public void Start(string port, int baudRate, uint chip) 39 | { 40 | Stop(); 41 | var arg = $"-serial {port} -sercfg {baudRate},8,1,N,N"; 42 | if (chip == 3) 43 | arg += " -mem"; 44 | 45 | _process = Process.Start(new ProcessStartInfo(_plinkFile, arg) 46 | { 47 | UseShellExecute = false 48 | }); 49 | 50 | System.Threading.Thread.Sleep(100); 51 | User32.SetWindowText(_process.MainWindowHandle, "K-Flash Terminal"); 52 | Kernel32.AssignProcessToJobObject(_job, new Kernel32.SafeObjectHandle(_process.Handle, false)); 53 | } 54 | 55 | public void Stop() 56 | { 57 | if (_process != null) 58 | { 59 | if (!_process.HasExited) 60 | { 61 | _process.Kill(); 62 | _process.WaitForExit(); 63 | } 64 | 65 | _process.Dispose(); 66 | _process = null; 67 | } 68 | } 69 | 70 | private Kernel32.SafeObjectHandle ExtractPlink() 71 | { 72 | using (Stream dst = File.OpenWrite(_plinkFile), 73 | src = new GZipStream(typeof(TerminalService).Assembly.GetManifestResourceStream("Canaan.Kendryte.Flash.Shell.Assets.plink.exe.gz"), CompressionMode.Decompress)) 74 | { 75 | src.CopyTo(dst); 76 | } 77 | 78 | var handle = Kernel32.CreateFile(_plinkFile, new Kernel32.ACCESS_MASK(0), Kernel32.FileShare.FILE_SHARE_READ | Kernel32.FileShare.FILE_SHARE_DELETE, IntPtr.Zero, 79 | Kernel32.CreationDisposition.OPEN_EXISTING, Kernel32.CreateFileFlags.FILE_ATTRIBUTE_TEMPORARY | Kernel32.CreateFileFlags.FILE_FLAG_DELETE_ON_CLOSE, Kernel32.SafeObjectHandle.Null); 80 | if (handle.IsInvalid) 81 | Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 82 | return handle; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/ViewModels/FlashViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | using System; 16 | using System.Collections.Generic; 17 | using System.IO; 18 | using System.Linq; 19 | using System.Management; 20 | using System.Text; 21 | using System.Text.RegularExpressions; 22 | using System.Threading.Tasks; 23 | using System.Windows; 24 | using Caliburn.Micro; 25 | using Canaan.Kendryte.Flash.Shell.Properties; 26 | using Canaan.Kendryte.Flash.Shell.Services; 27 | using Ookii.Dialogs.Wpf; 28 | 29 | namespace Canaan.Kendryte.Flash.Shell.ViewModels 30 | { 31 | public class FlashViewModel : Screen 32 | { 33 | private SerialPortEnumerator _serialPortEnumerator = new SerialPortEnumerator(); 34 | private TerminalService _terminalService = new TerminalService(); 35 | 36 | public BindableCollection Devices => _serialPortEnumerator.Devices; 37 | 38 | public Dictionary Chips { get; } = new Dictionary 39 | { 40 | { "In-Chip", 1 }, 41 | { "In-Memory", 3 }, 42 | #if DEBUG 43 | { "On-Board", 0 } 44 | #endif 45 | }; 46 | 47 | public IReadOnlyList BaudRates { get; } = new List 48 | { 49 | 115200, 50 | 921600, 51 | 1500000, 52 | 2000000 53 | }; 54 | 55 | private JobItemType? _currentJob; 56 | public JobItemType? CurrentJob 57 | { 58 | get => _currentJob; 59 | set => Set(ref _currentJob, value); 60 | } 61 | 62 | private JobItemStatus _currentJobStatus; 63 | public JobItemStatus CurrentJobStatus 64 | { 65 | get => _currentJobStatus; 66 | set => Set(ref _currentJobStatus, value); 67 | } 68 | 69 | private uint _chip; 70 | public uint Chip 71 | { 72 | get => _chip; 73 | set => Set(ref _chip, value); 74 | } 75 | 76 | private int _baudRate; 77 | public int BaudRate 78 | { 79 | get => _baudRate; 80 | set => Set(ref _baudRate, value); 81 | } 82 | 83 | private string _oldDevice; 84 | 85 | private string _device; 86 | public string Device 87 | { 88 | get => _device; 89 | set 90 | { 91 | Set(ref _device, value); 92 | if (!string.IsNullOrEmpty(value)) 93 | _oldDevice = value; 94 | } 95 | } 96 | 97 | private string _firmware; 98 | public string Firmware 99 | { 100 | get => _firmware; 101 | set => Set(ref _firmware, value); 102 | } 103 | 104 | private bool _isFlashing; 105 | public bool IsFlashing 106 | { 107 | get => _isFlashing; 108 | set 109 | { 110 | if (Set(ref _isFlashing, value)) 111 | { 112 | NotifyOfPropertyChange(nameof(CanStartFlash)); 113 | } 114 | } 115 | } 116 | 117 | public bool CanStartFlash => !IsFlashing; 118 | 119 | private string _license; 120 | public string License 121 | { 122 | get => _license; 123 | set => Set(ref _license, value); 124 | } 125 | 126 | private bool _openTerminal = true; 127 | public bool OpenTerminal 128 | { 129 | get => _openTerminal; 130 | set => Set(ref _openTerminal, value); 131 | } 132 | 133 | public FlashViewModel() 134 | { 135 | Chip = Chips.First().Value; 136 | BaudRate = BaudRates.Last(); 137 | License = Resources.LICENSE; 138 | 139 | Device = Devices.FirstOrDefault()?.Port; 140 | _serialPortEnumerator.DevicesUpdated += (s, e) => 141 | { 142 | Device = Devices.FirstOrDefault(o => o.Port == _oldDevice)?.Port; 143 | }; 144 | } 145 | 146 | public async void StartFlash() 147 | { 148 | if (string.IsNullOrEmpty(Firmware)) 149 | throw new InvalidOperationException("Must specify firmware path."); 150 | var firmwareType = GetFirmwareType(Firmware); 151 | if (firmwareType == FirmwareType.Unknown) 152 | throw new InvalidOperationException("Unknown firmware type."); 153 | if (string.IsNullOrEmpty(Device)) 154 | throw new InvalidOperationException("Must select device."); 155 | if (BaudRate < 110) 156 | throw new InvalidOperationException("Invalid baud rate."); 157 | if (Chip == 3 && firmwareType == FirmwareType.FlashList) 158 | throw new InvalidOperationException("In memory mode only supports bin firmware."); 159 | 160 | try 161 | { 162 | IsFlashing = true; 163 | 164 | _terminalService.Stop(); 165 | using (var loader = new KendryteLoader(Device, BaudRate)) 166 | { 167 | loader.CurrentJobChanged += (s, e) => 168 | { 169 | CurrentJob = loader.CurrentJob; 170 | CurrentJobStatus = loader.JobItemsStatus[loader.CurrentJob]; 171 | }; 172 | 173 | await loader.DetectBoard(); 174 | if (Chip == 3) 175 | { 176 | using (var file = File.OpenRead(Firmware)) 177 | using (var br = new BinaryReader(file)) 178 | { 179 | await loader.InstallFlashBootloader(br.ReadBytes((int)file.Length)); 180 | } 181 | } 182 | else 183 | { 184 | await loader.InstallFlashBootloader(); 185 | await loader.BootBootloader(); 186 | await loader.FlashGreeting(); 187 | await loader.ChangeBaudRate(); 188 | await loader.InitializeFlash(Chip); 189 | 190 | if (firmwareType == FirmwareType.Single) 191 | { 192 | using (var file = File.OpenRead(Firmware)) 193 | using (var br = new BinaryReader(file)) 194 | { 195 | await loader.FlashFirmware(0, br.ReadBytes((int)file.Length), true, false); 196 | } 197 | } 198 | else if (firmwareType == FirmwareType.FlashList) 199 | { 200 | using (var pkg = new FlashPackage(File.OpenRead(Firmware))) 201 | { 202 | await pkg.LoadAsync(); 203 | 204 | foreach (var item in pkg.Files) 205 | { 206 | using (var br = new BinaryReader(item.Bin)) 207 | { 208 | await loader.FlashFirmware(item.Address, br.ReadBytes((int)item.Length), item.SHA256Prefix, item.Reverse4Bytes); 209 | } 210 | } 211 | } 212 | } 213 | 214 | if (!OpenTerminal) 215 | await loader.Reboot(); 216 | } 217 | 218 | IsFlashing = false; 219 | CurrentJob = null; 220 | CurrentJobStatus = null; 221 | } 222 | 223 | if (OpenTerminal) 224 | _terminalService.Start(Device, 115200, Chip); 225 | else 226 | MessageBox.Show("Flash completed!", "K-Flash", MessageBoxButton.OK, MessageBoxImage.Information); 227 | } 228 | finally 229 | { 230 | IsFlashing = false; 231 | } 232 | } 233 | 234 | protected override void OnDeactivate(bool close) 235 | { 236 | _serialPortEnumerator?.Dispose(); 237 | 238 | base.OnDeactivate(close); 239 | } 240 | 241 | private FirmwareType GetFirmwareType(string firmware) 242 | { 243 | var ext = Path.GetExtension(firmware).ToLowerInvariant(); 244 | 245 | switch (ext) 246 | { 247 | case ".bin": 248 | return FirmwareType.Single; 249 | case ".kfpkg": 250 | return FirmwareType.FlashList; 251 | default: 252 | return FirmwareType.Unknown; 253 | } 254 | } 255 | 256 | public void BrowseFirmware() 257 | { 258 | var dialog = new VistaOpenFileDialog 259 | { 260 | Title = "Open firmware", 261 | Filter = "Firmware (*.bin;*.kfpkg)|*.bin;*.kfpkg", 262 | CheckFileExists = true, 263 | Multiselect = false 264 | }; 265 | 266 | if (dialog.ShowDialog() == true) 267 | { 268 | Firmware = dialog.FileName; 269 | } 270 | } 271 | 272 | private enum FirmwareType 273 | { 274 | Single, 275 | FlashList, 276 | Unknown 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/ViewModels/IShell.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | namespace Canaan.Kendryte.Flash.Shell 16 | { 17 | public interface IShell { } 18 | } -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/ViewModels/ShellViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | namespace Canaan.Kendryte.Flash.Shell.ViewModels 16 | { 17 | public class ShellViewModel : Caliburn.Micro.PropertyChangedBase, IShell 18 | { 19 | private object _content; 20 | public object Content 21 | { 22 | get => _content; 23 | set => Set(ref _content, value); 24 | } 25 | 26 | public ShellViewModel() 27 | { 28 | Content = new FlashViewModel(); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Views/FlashView.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Views/FlashView.xaml.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | using System; 16 | using System.Collections.Generic; 17 | using System.Diagnostics; 18 | using System.Linq; 19 | using System.Text; 20 | using System.Threading.Tasks; 21 | using System.Windows; 22 | using System.Windows.Controls; 23 | using System.Windows.Data; 24 | using System.Windows.Documents; 25 | using System.Windows.Input; 26 | using System.Windows.Media; 27 | using System.Windows.Media.Imaging; 28 | using System.Windows.Navigation; 29 | using System.Windows.Shapes; 30 | using Canaan.Kendryte.Flash.Shell.ViewModels; 31 | 32 | namespace Canaan.Kendryte.Flash.Shell.Views 33 | { 34 | /// 35 | /// FlashView.xaml 的交互逻辑 36 | /// 37 | public partial class FlashView : UserControl 38 | { 39 | public FlashView() 40 | { 41 | InitializeComponent(); 42 | } 43 | 44 | private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) 45 | { 46 | Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri)); 47 | e.Handled = true; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/Views/ShellView.xaml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/k-flash.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kendryte/kendryte-flash-windows/4d5d11b236646b9eea4805c33241873c17463039/src/Canaan.Kendryte.Flash.Shell/k-flash.ico -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.Shell/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2003 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Canaan.Kendryte.Flash", "Canaan.Kendryte.Flash\Canaan.Kendryte.Flash.csproj", "{FAE7F0A7-6630-4440-AC23-691A92BE5B77}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Canaan.Kendryte.Flash.Shell", "Canaan.Kendryte.Flash.Shell\Canaan.Kendryte.Flash.Shell.csproj", "{F7419577-0D3F-412E-814A-7C8F690CF133}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Canaan.Kendryte.Flash.Cli", "Canaan.Kendryte.Flash.Cli\Canaan.Kendryte.Flash.Cli.csproj", "{C65C81CE-22E5-4579-9135-FA529BB72F92}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {FAE7F0A7-6630-4440-AC23-691A92BE5B77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {FAE7F0A7-6630-4440-AC23-691A92BE5B77}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {FAE7F0A7-6630-4440-AC23-691A92BE5B77}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {FAE7F0A7-6630-4440-AC23-691A92BE5B77}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {F7419577-0D3F-412E-814A-7C8F690CF133}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {F7419577-0D3F-412E-814A-7C8F690CF133}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {F7419577-0D3F-412E-814A-7C8F690CF133}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {F7419577-0D3F-412E-814A-7C8F690CF133}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {C65C81CE-22E5-4579-9135-FA529BB72F92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {C65C81CE-22E5-4579-9135-FA529BB72F92}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {C65C81CE-22E5-4579-9135-FA529BB72F92}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {C65C81CE-22E5-4579-9135-FA529BB72F92}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {49E5B8D4-DD23-4E7E-B81F-7E846F3EDA86} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash/Canaan.Kendryte.Flash.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net471;netcoreapp2.1 5 | 8.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash/FlashModeResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | using System; 16 | using System.Collections.Generic; 17 | using System.Linq; 18 | using System.Text; 19 | using System.Threading.Tasks; 20 | 21 | namespace Canaan.Kendryte.Flash 22 | { 23 | public class FlashModeResponse 24 | { 25 | public enum Operation 26 | { 27 | ISP_DEBUG_INFO = 0xD1, 28 | ISP_NOP = 0xD2, 29 | ISP_FLASH_ERASE = 0xD3, 30 | ISP_FLASH_WRITE = 0xD4, 31 | ISP_REBOOT = 0xD5, 32 | ISP_UARTHS_BAUDRATE_SET = 0xD6, 33 | FLASHMODE_FLASH_INIT = 0xD7 34 | } 35 | 36 | public enum ErrorCode 37 | { 38 | ISP_RET_DEFAULT = 0x00, 39 | ISP_RET_OK = 0xE0, 40 | ISP_RET_BAD_DATA_LEN = 0xE1, 41 | ISP_RET_BAD_DATA_CHECKSUM = 0xE2, 42 | ISP_RET_INVALID_COMMAND = 0xE3 43 | } 44 | 45 | public static (Operation op, ErrorCode errorCode) Parse(ReadOnlySpan rawData) 46 | { 47 | return ((Operation)rawData[0], (ErrorCode)rawData[1]); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash/FlashPackage.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | using System; 16 | using System.Collections.Generic; 17 | using System.IO; 18 | using System.IO.Compression; 19 | using System.Linq; 20 | using System.Text; 21 | using System.Threading.Tasks; 22 | using Newtonsoft.Json; 23 | 24 | namespace Canaan.Kendryte.Flash 25 | { 26 | public class FlashFile 27 | { 28 | public uint Address { get; } 29 | 30 | private ZipArchiveEntry _bin; 31 | public Stream Bin => _bin.Open(); 32 | 33 | public long Length => _bin.Length; 34 | 35 | public bool SHA256Prefix { get; } 36 | 37 | public bool Reverse4Bytes { get; } 38 | 39 | public FlashFile(uint address, ZipArchiveEntry bin, bool sha256Prefix, bool reverse4Bytes) 40 | { 41 | Address = address; 42 | _bin = bin; 43 | SHA256Prefix = sha256Prefix; 44 | Reverse4Bytes = reverse4Bytes; 45 | } 46 | } 47 | 48 | public class FlashPackage : IDisposable 49 | { 50 | private static readonly string[] _supportedVersions = 51 | { 52 | "0.1.0", 53 | "0.1.1" 54 | }; 55 | 56 | private readonly ZipArchive _pkgArchive; 57 | private FlashListRoot _flashList; 58 | 59 | public IReadOnlyList Files { get; private set; } 60 | 61 | public FlashPackage(Stream stream) 62 | { 63 | _pkgArchive = new ZipArchive(stream, ZipArchiveMode.Read); 64 | } 65 | 66 | public async Task LoadAsync() 67 | { 68 | _flashList = await LoadFlashListAsync(); 69 | 70 | if (!_supportedVersions.Contains(_flashList.Version)) 71 | throw new NotSupportedException("This version of kfkpg is not supported."); 72 | 73 | Files = (from f in _flashList.Files 74 | select new FlashFile(f.Address, _pkgArchive.GetEntry(f.Bin), f.SHA256Prefix, f.Reverse4Bytes)).ToList(); 75 | } 76 | 77 | private async Task LoadFlashListAsync() 78 | { 79 | using (var sr = new StreamReader(_pkgArchive.GetEntry("flash-list.json").Open())) 80 | { 81 | return JsonConvert.DeserializeObject(await sr.ReadToEndAsync()); 82 | } 83 | } 84 | 85 | private class FlashListRoot 86 | { 87 | public string Version { get; set; } 88 | public FlashListFile[] Files { get; set; } 89 | } 90 | 91 | private class FlashListFile 92 | { 93 | public uint Address { get; set; } 94 | public string Bin { get; set; } 95 | public bool SHA256Prefix { get; set; } 96 | public bool Reverse4Bytes { get; set; } 97 | } 98 | 99 | #region IDisposable Support 100 | private bool _disposedValue = false; 101 | 102 | protected virtual void Dispose(bool disposing) 103 | { 104 | if (!_disposedValue) 105 | { 106 | if (disposing) 107 | { 108 | _pkgArchive.Dispose(); 109 | } 110 | 111 | _disposedValue = true; 112 | } 113 | } 114 | 115 | public void Dispose() 116 | { 117 | Dispose(true); 118 | } 119 | #endregion 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash/ISPResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | using System; 16 | using System.Collections.Generic; 17 | using System.Linq; 18 | using System.Text; 19 | using System.Threading.Tasks; 20 | 21 | namespace Canaan.Kendryte.Flash 22 | { 23 | public class ISPResponse 24 | { 25 | public enum Operation 26 | { 27 | ISP_ECHO = 0xC1, 28 | ISP_NOP = 0xC2, 29 | ISP_MEMORY_WRITE = 0xC3, 30 | ISP_MEMORY_READ = 0xC4, 31 | ISP_MEMORY_BOOT = 0xC5, 32 | ISP_DEBUG_INFO = 0xD1 33 | } 34 | 35 | public enum ErrorCode 36 | { 37 | ISP_RET_DEFAULT = 0x00, 38 | ISP_RET_OK = 0xE0, 39 | ISP_RET_BAD_DATA_LEN = 0xE1, 40 | ISP_RET_BAD_DATA_CHECKSUM = 0xE2, 41 | ISP_RET_INVALID_COMMAND = 0xE3 42 | } 43 | 44 | public static (Operation op, ErrorCode errorCode) Parse(ReadOnlySpan rawData) 45 | { 46 | return ((Operation)rawData[0], (ErrorCode)rawData[1]); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash/KendryteLoader.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Canaan Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | using System; 16 | using System.Collections.Generic; 17 | using System.ComponentModel; 18 | using System.Diagnostics; 19 | using System.IO; 20 | using System.IO.Ports; 21 | using System.Linq; 22 | using System.Runtime.CompilerServices; 23 | using System.Security.Cryptography; 24 | using System.Text; 25 | using System.Threading; 26 | using System.Threading.Tasks; 27 | using Force.Crc32; 28 | 29 | namespace Canaan.Kendryte.Flash 30 | { 31 | public enum JobItemType 32 | { 33 | DetectBoard, 34 | BootToISPMode, 35 | Greeting, 36 | InstallFlashBootloader, 37 | FlashGreeting, 38 | ChangeBaudRate, 39 | InitializeFlash, 40 | FlashFirmware, 41 | Reboot 42 | } 43 | 44 | public enum JobItemRunningStatus 45 | { 46 | NotStarted, 47 | Running, 48 | Finished, 49 | Error 50 | } 51 | 52 | public class JobItemStatus : INotifyPropertyChanged 53 | { 54 | public event PropertyChangedEventHandler PropertyChanged; 55 | 56 | private JobItemRunningStatus _runningStatus; 57 | 58 | public JobItemRunningStatus RunningStatus 59 | { 60 | get => _runningStatus; 61 | set => Set(ref _runningStatus, value); 62 | } 63 | 64 | private float _progress; 65 | 66 | public float Progress 67 | { 68 | get => _progress; 69 | set => Set(ref _progress, value); 70 | } 71 | 72 | private bool Set(ref T property, T value, [CallerMemberName]string propertyName = null) 73 | { 74 | if (!EqualityComparer.Default.Equals(property, value)) 75 | { 76 | property = value; 77 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | } 84 | 85 | public enum Board 86 | { 87 | MAIXGO, /* first check MaixGo*/ 88 | KD233, 89 | Generic, 90 | Unknown 91 | } 92 | 93 | public class KendryteLoader : IDisposable 94 | { 95 | private static readonly byte[] _greeting = new byte[] 96 | { 97 | 0xc0, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 98 | }; 99 | 100 | private static readonly byte[] _flashGreeting = new byte[] 101 | { 102 | 0xc0, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 103 | }; 104 | 105 | private readonly SerialPort _port; 106 | private readonly int _baudRate; 107 | private Board _board; 108 | private readonly SynchronizationContext _synchronizationContext; 109 | 110 | public Dictionary JobItemsStatus { get; } 111 | 112 | private JobItemType _currentJob; 113 | public JobItemType CurrentJob 114 | { 115 | get => _currentJob; 116 | set 117 | { 118 | _currentJob = value; 119 | CurrentJobChanged?.Invoke(this, EventArgs.Empty); 120 | } 121 | } 122 | 123 | public event EventHandler CurrentJobChanged; 124 | 125 | public Action ConnectionEstablished { get; set; } 126 | 127 | #if DEBUG 128 | private Stopwatch _sw = new Stopwatch(); 129 | private TimeSpan _write, _send, _wait, _writepacket; 130 | #endif 131 | 132 | public KendryteLoader(string device, int baudRate) 133 | { 134 | _baudRate = baudRate; 135 | _synchronizationContext = SynchronizationContext.Current; 136 | JobItemsStatus = (from e in (JobItemType[])Enum.GetValues(typeof(JobItemType)) 137 | select new 138 | { 139 | Key = e, 140 | Value = new JobItemStatus() 141 | }).ToDictionary(o => o.Key, o => o.Value); 142 | 143 | _port = new SerialPort(device, 115200, Parity.None, 8, StopBits.One) 144 | { 145 | ReadTimeout = 2000 146 | }; 147 | 148 | _port.Open(); 149 | } 150 | 151 | public async Task BootToISPMode() 152 | { 153 | var status = JobItemsStatus[JobItemType.BootToISPMode]; 154 | CurrentJob = JobItemType.BootToISPMode; 155 | await DoJob(status, async () => 156 | { 157 | if (_board == Board.KD233) 158 | { 159 | await BootToISPModeForBoard1(); 160 | } 161 | else if (_board == Board.Generic) 162 | { 163 | await BootToISPModeForBoard2(); 164 | } 165 | else if (_board == Board.MAIXGO) 166 | { 167 | await BootToISPModeForBoardMaixGoOpenec(); 168 | } 169 | else 170 | { 171 | throw new NotSupportedException("Unable to enter ISP mode."); 172 | } 173 | }); 174 | } 175 | 176 | private async Task BootToISPModeForBoard1() 177 | { 178 | _port.DtrEnable = true; 179 | _port.RtsEnable = true; 180 | await Task.Delay(TimeSpan.FromMilliseconds(50)); 181 | _port.DtrEnable = false; 182 | await Task.Delay(TimeSpan.FromMilliseconds(50)); 183 | } 184 | 185 | private async Task BootToISPModeForBoard2() 186 | { 187 | _port.DtrEnable = false; 188 | _port.RtsEnable = false; 189 | await Task.Delay(TimeSpan.FromMilliseconds(10)); 190 | _port.DtrEnable = false; 191 | _port.RtsEnable = true; 192 | await Task.Delay(TimeSpan.FromMilliseconds(10)); 193 | _port.RtsEnable = false; 194 | _port.DtrEnable = true; 195 | await Task.Delay(TimeSpan.FromMilliseconds(10)); 196 | } 197 | 198 | private async Task BootToISPModeForBoardMaixGoOpenec() 199 | { 200 | _port.DtrEnable = true; 201 | _port.RtsEnable = false; 202 | await Task.Delay(TimeSpan.FromMilliseconds(50)); 203 | _port.DtrEnable = false; 204 | _port.RtsEnable = true; 205 | await Task.Delay(TimeSpan.FromMilliseconds(50)); 206 | } 207 | 208 | //FIXME 如果板子没有回复,则会一直等待。 209 | public async Task Greeting() 210 | { 211 | var status = JobItemsStatus[JobItemType.Greeting]; 212 | CurrentJob = JobItemType.Greeting; 213 | await DoJob(status, () => 214 | { 215 | return Task.Run(() => 216 | { 217 | _port.Write(_greeting, 0, _greeting.Length); 218 | var resp = ISPResponse.Parse(ReceiveOnReturn()); 219 | if (resp.errorCode != ISPResponse.ErrorCode.ISP_RET_OK) 220 | throw new InvalidOperationException("Error in greeting."); 221 | }); 222 | }); 223 | } 224 | 225 | public async Task DetectBoard() 226 | { 227 | foreach (var board in (Board[])Enum.GetValues(typeof(Board))) 228 | { 229 | if (await DetectBoard(board)) break; 230 | } 231 | } 232 | 233 | private async Task DetectBoard(Board board) 234 | { 235 | _board = board; 236 | 237 | var status = JobItemsStatus[JobItemType.DetectBoard]; 238 | CurrentJob = JobItemType.DetectBoard; 239 | try 240 | { 241 | await BootToISPMode(); 242 | await Greeting(); 243 | return true; 244 | } 245 | catch (TimeoutException) 246 | { 247 | return false; 248 | } 249 | } 250 | 251 | public async Task InstallFlashBootloader(byte[] bootloader = null) 252 | { 253 | var status = JobItemsStatus[JobItemType.InstallFlashBootloader]; 254 | CurrentJob = JobItemType.InstallFlashBootloader; 255 | await DoJob(status, () => 256 | { 257 | return Task.Run(async () => 258 | { 259 | if (bootloader == null) 260 | { 261 | using (var bootloaderStream = typeof(KendryteLoader).Assembly.GetManifestResourceStream("Canaan.Kendryte.Flash.Resources.isp_flash.bin")) 262 | { 263 | bootloader = new byte[bootloaderStream.Length]; 264 | bootloaderStream.Read(bootloader, 0, bootloader.Length); 265 | } 266 | } 267 | 268 | const int dataframeSize = 1024; 269 | 270 | uint totalWritten = 0; 271 | var buffer = new byte[4 * 4 + dataframeSize]; 272 | uint address = 0x80000000; 273 | 274 | foreach (var chunk in SplitToChunks(bootloader, dataframeSize)) 275 | { 276 | SendPacket(buffer, (ushort)ISPResponse.Operation.ISP_MEMORY_WRITE, address, payload: chunk, shouldRetry: () => 277 | { 278 | var result = ISPResponse.Parse(ReceiveOnReturn()); 279 | return !CheckResponse(result.errorCode); 280 | }); 281 | 282 | address += (uint)chunk.Count; 283 | totalWritten += (uint)chunk.Count; 284 | await ExecuteOnUIAsync(() => status.Progress = (float)totalWritten / bootloader.Length); 285 | } 286 | }); 287 | }); 288 | } 289 | 290 | public async Task BootBootloader() 291 | { 292 | var status = JobItemsStatus[JobItemType.InstallFlashBootloader]; 293 | CurrentJob = JobItemType.InstallFlashBootloader; 294 | await DoJob(status, () => 295 | { 296 | return Task.Run(async () => 297 | { 298 | var buffer = new byte[4 * 4]; 299 | SendPacket(buffer, (ushort)ISPResponse.Operation.ISP_MEMORY_BOOT, 0x80000000); 300 | await ExecuteOnUIAsync(() => status.Progress = 0.5f); 301 | await Task.Delay(TimeSpan.FromSeconds(2)); 302 | }); 303 | }); 304 | } 305 | 306 | public async Task FlashGreeting() 307 | { 308 | var status = JobItemsStatus[JobItemType.FlashGreeting]; 309 | CurrentJob = JobItemType.FlashGreeting; 310 | await DoJob(status, () => 311 | { 312 | return Task.Run(() => 313 | { 314 | _port.Write(_flashGreeting, 0, _flashGreeting.Length); 315 | var resp = FlashModeResponse.Parse(ReceiveOnReturn()); 316 | if (!CheckResponse(resp.errorCode)) 317 | throw new InvalidOperationException("Error in flash greeting."); 318 | }); 319 | }); 320 | } 321 | 322 | public async Task ChangeBaudRate() 323 | { 324 | var status = JobItemsStatus[JobItemType.ChangeBaudRate]; 325 | CurrentJob = JobItemType.ChangeBaudRate; 326 | await DoJob(status, () => 327 | { 328 | return Task.Run(async () => 329 | { 330 | var buffer = new byte[4 * 5]; 331 | var payload = new ArraySegment(BitConverter.GetBytes(_baudRate)); 332 | SendPacket(buffer, (ushort)FlashModeResponse.Operation.ISP_UARTHS_BAUDRATE_SET, 0, payload: payload); 333 | 334 | _port.Close(); 335 | await Task.Delay(50); 336 | _port.BaudRate = _baudRate; 337 | _port.Open(); 338 | }); 339 | }); 340 | } 341 | 342 | public async Task InitializeFlash(uint chip) 343 | { 344 | var status = JobItemsStatus[JobItemType.InitializeFlash]; 345 | CurrentJob = JobItemType.InitializeFlash; 346 | await DoJob(status, () => 347 | { 348 | return Task.Run(() => 349 | { 350 | var buffer = new byte[4 * 4]; 351 | SendPacket(buffer, (ushort)FlashModeResponse.Operation.FLASHMODE_FLASH_INIT, chip, () => 352 | { 353 | var resp = FlashModeResponse.Parse(ReceiveOnReturn()); 354 | if (!CheckResponse(resp.errorCode)) 355 | throw new InvalidOperationException("Error in flash initializing."); 356 | return false; 357 | }); 358 | }); 359 | }); 360 | } 361 | 362 | public async Task FlashFirmware(uint address, byte[] data, bool sha256Prefix, bool reverse4Bytes) 363 | { 364 | var status = JobItemsStatus[JobItemType.FlashFirmware]; 365 | CurrentJob = JobItemType.FlashFirmware; 366 | await DoJob(status, () => 367 | { 368 | return Task.Run(async () => 369 | { 370 | data = ZeroPadding(data, 64); 371 | if (reverse4Bytes) 372 | Reverse4Bytes(data); 373 | byte[] dataPack; 374 | if (sha256Prefix) 375 | { 376 | dataPack = new byte[1 + 4 + data.Length + 32]; 377 | using (var stream = new MemoryStream(dataPack)) 378 | using (var bw = new BinaryWriter(stream, Encoding.UTF8, leaveOpen: true)) 379 | { 380 | bw.Write((byte)0); 381 | bw.Write((uint)data.Length); 382 | bw.Write(data, 0, data.Length); 383 | 384 | bw.Flush(); 385 | using (var sha256 = SHA256.Create()) 386 | { 387 | var digest = sha256.ComputeHash(dataPack, 0, 1 + 4 + data.Length); 388 | bw.Write(digest); 389 | } 390 | } 391 | } 392 | else 393 | { 394 | dataPack = data; 395 | } 396 | 397 | const int dataframeSize = 4096 * 16; 398 | 399 | uint totalWritten = 0; 400 | var buffer = new byte[4 * 4 + dataframeSize]; 401 | 402 | #if DEBUG 403 | var sw = new Stopwatch(); 404 | sw.Start(); 405 | #endif 406 | 407 | foreach (var chunk in SplitToChunks(dataPack, dataframeSize)) 408 | { 409 | #if DEBUG 410 | sw.Restart(); 411 | #endif 412 | SendPacket(buffer, (ushort)FlashModeResponse.Operation.ISP_FLASH_WRITE, address, payload: chunk, shouldRetry: () => 413 | { 414 | var result = FlashModeResponse.Parse(ReceiveOnReturn()); 415 | return !CheckResponse(result.errorCode); 416 | }); 417 | #if DEBUG 418 | sw.Stop(); 419 | _writepacket += sw.Elapsed; 420 | Debug.WriteLine($"Send packet takes {_writepacket}"); 421 | #endif 422 | 423 | address += dataframeSize; 424 | totalWritten += (uint)chunk.Count; 425 | await ExecuteOnUIAsync(() => status.Progress = (float)totalWritten / dataPack.Length); 426 | } 427 | }); 428 | }); 429 | } 430 | 431 | private static byte[] ZeroPadding(byte[] data, int align) 432 | { 433 | var toPad = (int)Math.Ceiling(data.Length / (double)align) * align - data.Length; 434 | if (toPad == 0) 435 | { 436 | return data; 437 | } 438 | else 439 | { 440 | var newData = new byte[data.Length + toPad]; 441 | Array.Copy(data, newData, data.Length); 442 | return newData; 443 | } 444 | } 445 | 446 | private static void Reverse4Bytes(byte[] data) 447 | { 448 | if (data.Length % 4 != 0) 449 | throw new InvalidDataException("Data must be 4 bytes aligned."); 450 | for (int i = 0; i < data.Length; i += 4) 451 | { 452 | var span = new Span(data, i, 4); 453 | span.Reverse(); 454 | } 455 | } 456 | 457 | public async Task Reboot() 458 | { 459 | var status = JobItemsStatus[JobItemType.Reboot]; 460 | CurrentJob = JobItemType.Reboot; 461 | await DoJob(status, async () => 462 | { 463 | await DoJob(status, async () => 464 | { 465 | if (_board == Board.KD233) 466 | { 467 | await RebootForBoard1(); 468 | } 469 | else if (_board == Board.Generic) 470 | { 471 | await RebootForBoard2(); 472 | } 473 | else if (_board == Board.MAIXGO) 474 | { 475 | await RebootForBoardMaixGoOpenec(); 476 | } 477 | }); 478 | }); 479 | } 480 | 481 | public async Task RebootForBoard1() 482 | { 483 | _port.RtsEnable = false; 484 | _port.DtrEnable = true; 485 | await Task.Delay(TimeSpan.FromMilliseconds(50)); 486 | _port.DtrEnable = false; 487 | } 488 | 489 | public async Task RebootForBoard2() 490 | { 491 | _port.DtrEnable = false; 492 | _port.RtsEnable = false; 493 | await Task.Delay(TimeSpan.FromMilliseconds(10)); 494 | _port.DtrEnable = false; 495 | _port.RtsEnable = true; 496 | await Task.Delay(TimeSpan.FromMilliseconds(10)); 497 | _port.DtrEnable = false; 498 | _port.RtsEnable = false; 499 | } 500 | 501 | public async Task RebootForBoardMaixGoOpenec() 502 | { 503 | _port.RtsEnable = false; 504 | _port.DtrEnable = true; 505 | await Task.Delay(TimeSpan.FromMilliseconds(50)); 506 | _port.RtsEnable = true; 507 | _port.DtrEnable = true; 508 | await Task.Delay(TimeSpan.FromMilliseconds(50)); 509 | _port.RtsEnable = true; 510 | _port.DtrEnable = true; 511 | } 512 | 513 | private async Task DoJob(JobItemStatus status, Func job) 514 | { 515 | try 516 | { 517 | status.RunningStatus = JobItemRunningStatus.Running; 518 | status.Progress = 0; 519 | 520 | await job(); 521 | 522 | status.Progress = 1; 523 | status.RunningStatus = JobItemRunningStatus.Finished; 524 | } 525 | catch 526 | { 527 | status.RunningStatus = JobItemRunningStatus.Error; 528 | throw; 529 | } 530 | } 531 | 532 | private bool CheckResponse(ISPResponse.ErrorCode errorCode) 533 | { 534 | return errorCode == ISPResponse.ErrorCode.ISP_RET_OK || errorCode == ISPResponse.ErrorCode.ISP_RET_DEFAULT; 535 | } 536 | 537 | private bool CheckResponse(FlashModeResponse.ErrorCode errorCode) 538 | { 539 | return errorCode == FlashModeResponse.ErrorCode.ISP_RET_OK || errorCode == FlashModeResponse.ErrorCode.ISP_RET_DEFAULT; 540 | } 541 | 542 | private void SendPacket(byte[] buffer, ushort operation, uint address, Func shouldRetry = null, ArraySegment? payload = null) 543 | { 544 | int toWrite = 4 * 4; 545 | using (var stream = new MemoryStream(buffer)) 546 | using (var bw = new BinaryWriter(stream, Encoding.UTF8, leaveOpen: true)) 547 | { 548 | bw.Write(operation); 549 | bw.Write((ushort)0x00); 550 | bw.Write((uint)0); // checksum 551 | bw.Write(address); 552 | 553 | if (payload is ArraySegment realPayload) 554 | { 555 | bw.Write((uint)realPayload.Count); 556 | bw.Write(realPayload.Array, realPayload.Offset, realPayload.Count); 557 | toWrite += realPayload.Count; 558 | } 559 | else 560 | { 561 | bw.Write(0U); 562 | } 563 | 564 | bw.Flush(); 565 | var checksum = Crc32Algorithm.Compute(buffer, 4 * 2, toWrite - 4 * 2); 566 | bw.Seek(4, SeekOrigin.Begin); 567 | bw.Write(checksum); 568 | } 569 | 570 | while (true) 571 | { 572 | Write(new ReadOnlyMemory(buffer, 0, toWrite)); 573 | #if DEBUG 574 | _sw.Restart(); 575 | #endif 576 | if (shouldRetry == null || !shouldRetry()) 577 | { 578 | #if DEBUG 579 | _sw.Stop(); 580 | _wait += _sw.Elapsed; 581 | Debug.WriteLine($"Wait response takes {_wait}"); 582 | #endif 583 | break; 584 | } 585 | else 586 | { 587 | Debug.Assert(false); 588 | } 589 | } 590 | } 591 | 592 | private byte[] ReceiveOnReturn() 593 | { 594 | using (var stream = new MemoryStream()) 595 | { 596 | while (_port.ReadByte() != 0xc0) ; 597 | 598 | bool escapeNext = false; 599 | while (true) 600 | { 601 | var data = _port.ReadByte(); 602 | if (data == 0xc0) break; 603 | if (data == 0xdb) 604 | { 605 | escapeNext = true; 606 | } 607 | else if (escapeNext) 608 | { 609 | escapeNext = false; 610 | if (data == 0xdc) 611 | stream.WriteByte(0xc0); 612 | else if (data == 0xdd) 613 | stream.WriteByte(0xdb); 614 | else 615 | throw new InvalidDataException($"Invalid SLIP escape: {data:X2}."); 616 | } 617 | else 618 | { 619 | stream.WriteByte((byte)data); 620 | } 621 | } 622 | 623 | return stream.ToArray(); 624 | } 625 | } 626 | 627 | private void Write(ReadOnlyMemory data) 628 | { 629 | IEnumerable EscapeData() 630 | { 631 | yield return 0xc0; 632 | for (int i = 0; i < data.Length; i++) 633 | { 634 | var b = data.Span[i]; 635 | if (b == 0xdb) 636 | { 637 | yield return 0xdb; 638 | yield return 0xdd; 639 | } 640 | else if (b == 0xc0) 641 | { 642 | yield return 0xdb; 643 | yield return 0xdc; 644 | } 645 | else 646 | { 647 | yield return b; 648 | } 649 | } 650 | 651 | yield return 0xc0; 652 | } 653 | 654 | var buffer = EscapeData().ToArray(); 655 | _port.Write(buffer, 0, buffer.Length); 656 | } 657 | 658 | private IEnumerable> SplitToChunks(byte[] data, int chunkSize) 659 | { 660 | int start = 0; 661 | while (true) 662 | { 663 | var count = Math.Min(data.Length - start, chunkSize); 664 | if (count == 0) 665 | yield break; 666 | yield return new ArraySegment(data, start, count); 667 | start += count; 668 | } 669 | } 670 | 671 | private Task ExecuteOnUIAsync(Action action) 672 | { 673 | if (_synchronizationContext != null) 674 | { 675 | var tcs = new TaskCompletionSource(); 676 | _synchronizationContext.Send(o => 677 | { 678 | try 679 | { 680 | action(); 681 | tcs.SetResult(null); 682 | } 683 | catch (Exception ex) 684 | { 685 | tcs.SetException(ex); 686 | } 687 | }, null); 688 | return tcs.Task; 689 | } 690 | else 691 | { 692 | action(); 693 | return Task.CompletedTask; 694 | } 695 | } 696 | 697 | #region IDisposable Support 698 | private bool _disposedValue = false; 699 | 700 | protected virtual void Dispose(bool disposing) 701 | { 702 | if (!_disposedValue) 703 | { 704 | if (disposing) 705 | { 706 | _port.Dispose(); 707 | } 708 | 709 | _disposedValue = true; 710 | } 711 | } 712 | 713 | public void Dispose() 714 | { 715 | Dispose(true); 716 | } 717 | #endregion 718 | } 719 | } 720 | -------------------------------------------------------------------------------- /src/Canaan.Kendryte.Flash/Resources/isp_flash.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kendryte/kendryte-flash-windows/4d5d11b236646b9eea4805c33241873c17463039/src/Canaan.Kendryte.Flash/Resources/isp_flash.bin -------------------------------------------------------------------------------- /src/NuGet.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | --------------------------------------------------------------------------------