├── .gitattributes ├── .gitignore ├── LICENSE ├── PartTool.Designer.cs ├── PartTool.cs ├── PartTool.resx ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── README.md ├── docs ├── screen_copy.jpg ├── screen_expert.jpg ├── screen_flash.jpg ├── screen_fuse.jpg ├── screen_info.jpg └── screen_partition.jpg ├── esp_tools_gui.csproj ├── esp_tools_gui.sln ├── exes ├── ESP32py.ico ├── cxfreeze.zip ├── espefuse.exe ├── espefuse.py ├── espefuse.spec ├── espsecure.exe ├── espsecure.py ├── esptool.exe ├── esptool.py ├── gen_esp32part.exe ├── gen_esp32part.py ├── parttool.exe ├── parttool.py ├── python3.dll ├── python310.dll └── setup_esp.py ├── images ├── add.png ├── add32.png ├── burn.png ├── burn32.png ├── esp32.jpg ├── export.png ├── export32.png ├── import.png ├── import32.png ├── kchart.png └── kde-folder-open.png └── src ├── App.config ├── App.cs ├── Connecting.Designer.cs ├── Connecting.cs ├── Connecting.resx ├── ESP32.ico ├── MainPage.Designer.cs ├── MainPage.cs ├── MainPage.resx ├── Tool.cs ├── ToolEfuse.cs ├── ToolPart.cs ├── ToolPartition.cs ├── ToolSecure.cs └── ToolTool.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | 33 | # Visual Studio 2015/2017 cache/options directory 34 | .vs/ 35 | # Uncomment if you have tasks that create the project's static files in wwwroot 36 | #wwwroot/ 37 | 38 | # Visual Studio 2017 auto generated files 39 | Generated\ Files/ 40 | 41 | # MSTest test Results 42 | [Tt]est[Rr]esult*/ 43 | [Bb]uild[Ll]og.* 44 | 45 | # NUnit 46 | *.VisualState.xml 47 | TestResult.xml 48 | nunit-*.xml 49 | 50 | # Build Results of an ATL Project 51 | [Dd]ebugPS/ 52 | [Rr]eleasePS/ 53 | dlldata.c 54 | 55 | # Benchmark Results 56 | BenchmarkDotNet.Artifacts/ 57 | 58 | # .NET Core 59 | project.lock.json 60 | project.fragment.lock.json 61 | artifacts/ 62 | 63 | # StyleCop 64 | StyleCopReport.xml 65 | 66 | # Files built by Visual Studio 67 | *_i.c 68 | *_p.c 69 | *_h.h 70 | *.ilk 71 | *.meta 72 | *.obj 73 | *.iobj 74 | *.pch 75 | *.pdb 76 | *.ipdb 77 | *.pgc 78 | *.pgd 79 | *.rsp 80 | *.sbr 81 | *.tlb 82 | *.tli 83 | *.tlh 84 | *.tmp 85 | *.tmp_proj 86 | *_wpftmp.csproj 87 | *.log 88 | *.vspscc 89 | *.vssscc 90 | .builds 91 | *.pidb 92 | *.svclog 93 | *.scc 94 | 95 | # Chutzpah Test files 96 | _Chutzpah* 97 | 98 | # Visual C++ cache files 99 | ipch/ 100 | *.aps 101 | *.ncb 102 | *.opendb 103 | *.opensdf 104 | *.sdf 105 | *.cachefile 106 | *.VC.db 107 | *.VC.VC.opendb 108 | 109 | # Visual Studio profiler 110 | *.psess 111 | *.vsp 112 | *.vspx 113 | *.sap 114 | 115 | # Visual Studio Trace Files 116 | *.e2e 117 | 118 | # TFS 2012 Local Workspace 119 | $tf/ 120 | 121 | # Guidance Automation Toolkit 122 | *.gpState 123 | 124 | # ReSharper is a .NET coding add-in 125 | _ReSharper*/ 126 | *.[Rr]e[Ss]harper 127 | *.DotSettings.user 128 | 129 | # JustCode is a .NET coding add-in 130 | .JustCode 131 | 132 | # TeamCity is a build add-in 133 | _TeamCity* 134 | 135 | # DotCover is a Code Coverage Tool 136 | *.dotCover 137 | 138 | # AxoCover is a Code Coverage Tool 139 | .axoCover/* 140 | !.axoCover/settings.json 141 | 142 | # Visual Studio code coverage results 143 | *.coverage 144 | *.coveragexml 145 | 146 | # NCrunch 147 | _NCrunch_* 148 | .*crunch*.local.xml 149 | nCrunchTemp_* 150 | 151 | # MightyMoose 152 | *.mm.* 153 | AutoTest.Net/ 154 | 155 | # Web workbench (sass) 156 | .sass-cache/ 157 | 158 | # Installshield output folder 159 | [Ee]xpress/ 160 | 161 | # DocProject is a documentation generator add-in 162 | DocProject/buildhelp/ 163 | DocProject/Help/*.HxT 164 | DocProject/Help/*.HxC 165 | DocProject/Help/*.hhc 166 | DocProject/Help/*.hhk 167 | DocProject/Help/*.hhp 168 | DocProject/Help/Html2 169 | DocProject/Help/html 170 | 171 | # Click-Once directory 172 | publish/ 173 | 174 | # Publish Web Output 175 | *.[Pp]ublish.xml 176 | *.azurePubxml 177 | # Note: Comment the next line if you want to checkin your web deploy settings, 178 | # but database connection strings (with potential passwords) will be unencrypted 179 | *.pubxml 180 | *.publishproj 181 | 182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 183 | # checkin your Azure Web App publish settings, but sensitive information contained 184 | # in these scripts will be unencrypted 185 | PublishScripts/ 186 | 187 | # NuGet Packages 188 | *.nupkg 189 | # NuGet Symbol Packages 190 | *.snupkg 191 | # The packages folder can be ignored because of Package Restore 192 | **/[Pp]ackages/* 193 | # except build/, which is used as an MSBuild target. 194 | !**/[Pp]ackages/build/ 195 | # Uncomment if necessary however generally it will be regenerated when needed 196 | #!**/[Pp]ackages/repositories.config 197 | # NuGet v3's project.json files produces more ignorable files 198 | *.nuget.props 199 | *.nuget.targets 200 | 201 | # Microsoft Azure Build Output 202 | csx/ 203 | *.build.csdef 204 | 205 | # Microsoft Azure Emulator 206 | ecf/ 207 | rcf/ 208 | 209 | # Windows Store app package directories and files 210 | AppPackages/ 211 | BundleArtifacts/ 212 | Package.StoreAssociation.xml 213 | _pkginfo.txt 214 | *.appx 215 | *.appxbundle 216 | *.appxupload 217 | 218 | # Visual Studio cache files 219 | # files ending in .cache can be ignored 220 | *.[Cc]ache 221 | # but keep track of directories ending in .cache 222 | !?*.[Cc]ache/ 223 | 224 | # Others 225 | ClientBin/ 226 | ~$* 227 | *~ 228 | *.dbmdl 229 | *.dbproj.schemaview 230 | *.jfm 231 | *.pfx 232 | *.publishsettings 233 | orleans.codegen.cs 234 | 235 | # Including strong name files can present a security risk 236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 237 | #*.snk 238 | 239 | # Since there are multiple workflows, uncomment next line to ignore bower_components 240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 241 | #bower_components/ 242 | 243 | # RIA/Silverlight projects 244 | Generated_Code/ 245 | 246 | # Backup & report files from converting an old project file 247 | # to a newer Visual Studio version. Backup files are not needed, 248 | # because we have git ;-) 249 | _UpgradeReport_Files/ 250 | Backup*/ 251 | UpgradeLog*.XML 252 | UpgradeLog*.htm 253 | ServiceFabricBackup/ 254 | *.rptproj.bak 255 | 256 | # SQL Server files 257 | *.mdf 258 | *.ldf 259 | *.ndf 260 | 261 | # Business Intelligence projects 262 | *.rdl.data 263 | *.bim.layout 264 | *.bim_*.settings 265 | *.rptproj.rsuser 266 | *- [Bb]ackup.rdl 267 | *- [Bb]ackup ([0-9]).rdl 268 | *- [Bb]ackup ([0-9][0-9]).rdl 269 | 270 | # Microsoft Fakes 271 | FakesAssemblies/ 272 | 273 | # GhostDoc plugin setting file 274 | *.GhostDoc.xml 275 | 276 | # Node.js Tools for Visual Studio 277 | .ntvs_analysis.dat 278 | node_modules/ 279 | 280 | # Visual Studio 6 build log 281 | *.plg 282 | 283 | # Visual Studio 6 workspace options file 284 | *.opt 285 | 286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 287 | *.vbw 288 | 289 | # Visual Studio LightSwitch build output 290 | **/*.HTMLClient/GeneratedArtifacts 291 | **/*.DesktopClient/GeneratedArtifacts 292 | **/*.DesktopClient/ModelManifest.xml 293 | **/*.Server/GeneratedArtifacts 294 | **/*.Server/ModelManifest.xml 295 | _Pvt_Extensions 296 | 297 | # Paket dependency manager 298 | .paket/paket.exe 299 | paket-files/ 300 | 301 | # FAKE - F# Make 302 | .fake/ 303 | 304 | # CodeRush personal settings 305 | .cr/personal 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | 315 | # Tabs Studio 316 | *.tss 317 | 318 | # Telerik's JustMock configuration file 319 | *.jmconfig 320 | 321 | # BizTalk build output 322 | *.btp.cs 323 | *.btm.cs 324 | *.odx.cs 325 | *.xsd.cs 326 | 327 | # OpenCover UI analysis results 328 | OpenCover/ 329 | 330 | # Azure Stream Analytics local run output 331 | ASALocalRun/ 332 | 333 | # MSBuild Binary and Structured Log 334 | *.binlog 335 | 336 | # NVidia Nsight GPU debugger configuration file 337 | *.nvuser 338 | 339 | # MFractors (Xamarin productivity tool) working folder 340 | .mfractor/ 341 | 342 | # Local History for Visual Studio 343 | .localhistory/ 344 | 345 | # BeatPulse healthcheck temp database 346 | healthchecksdb 347 | 348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 349 | MigrationBackup/ 350 | exes/build 351 | -------------------------------------------------------------------------------- /PartTool.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace esp_tools_gui 2 | { 3 | partial class PartTool 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("Partition Name"); 33 | System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("Partitions", new System.Windows.Forms.TreeNode[] { 34 | treeNode1}); 35 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PartTool)); 36 | this.trackBarOta = new System.Windows.Forms.TrackBar(); 37 | this.label1 = new System.Windows.Forms.Label(); 38 | this.progressBar1 = new System.Windows.Forms.ProgressBar(); 39 | this.labelProgress = new System.Windows.Forms.Label(); 40 | this.checkBoxOta = new System.Windows.Forms.CheckBox(); 41 | this.checkBoxNvs = new System.Windows.Forms.CheckBox(); 42 | this.trackBarNvs = new System.Windows.Forms.TrackBar(); 43 | this.checkBoxEeprom = new System.Windows.Forms.CheckBox(); 44 | this.trackBarEeprom = new System.Windows.Forms.TrackBar(); 45 | this.checkBoxSpiffs = new System.Windows.Forms.CheckBox(); 46 | this.trackBarSpiffs = new System.Windows.Forms.TrackBar(); 47 | this.labelOta = new System.Windows.Forms.Label(); 48 | this.labelNvs = new System.Windows.Forms.Label(); 49 | this.labelEeprom = new System.Windows.Forms.Label(); 50 | this.labelSpiffs = new System.Windows.Forms.Label(); 51 | this.button1 = new System.Windows.Forms.Button(); 52 | this.button2 = new System.Windows.Forms.Button(); 53 | this.button3 = new System.Windows.Forms.Button(); 54 | this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); 55 | this.labelOta1 = new System.Windows.Forms.Label(); 56 | this.trackBarOta1 = new System.Windows.Forms.TrackBar(); 57 | this.checkBoxOtaLock = new System.Windows.Forms.CheckBox(); 58 | this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); 59 | this.button4 = new System.Windows.Forms.Button(); 60 | this.button5 = new System.Windows.Forms.Button(); 61 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 62 | this.button6 = new System.Windows.Forms.Button(); 63 | this.textBox2 = new System.Windows.Forms.TextBox(); 64 | this.label3 = new System.Windows.Forms.Label(); 65 | this.textBox1 = new System.Windows.Forms.TextBox(); 66 | this.label2 = new System.Windows.Forms.Label(); 67 | this.treeView1 = new System.Windows.Forms.TreeView(); 68 | this.imageList1 = new System.Windows.Forms.ImageList(this.components); 69 | this.trackBarOtaD = new System.Windows.Forms.TrackBar(); 70 | this.checkBoxOtaD = new System.Windows.Forms.CheckBox(); 71 | this.labelOtaD = new System.Windows.Forms.Label(); 72 | this.labelFfat = new System.Windows.Forms.Label(); 73 | this.checkBoxFfat = new System.Windows.Forms.CheckBox(); 74 | this.trackBarFfat = new System.Windows.Forms.TrackBar(); 75 | ((System.ComponentModel.ISupportInitialize)(this.trackBarOta)).BeginInit(); 76 | ((System.ComponentModel.ISupportInitialize)(this.trackBarNvs)).BeginInit(); 77 | ((System.ComponentModel.ISupportInitialize)(this.trackBarEeprom)).BeginInit(); 78 | ((System.ComponentModel.ISupportInitialize)(this.trackBarSpiffs)).BeginInit(); 79 | ((System.ComponentModel.ISupportInitialize)(this.trackBarOta1)).BeginInit(); 80 | this.groupBox1.SuspendLayout(); 81 | ((System.ComponentModel.ISupportInitialize)(this.trackBarOtaD)).BeginInit(); 82 | ((System.ComponentModel.ISupportInitialize)(this.trackBarFfat)).BeginInit(); 83 | this.SuspendLayout(); 84 | // 85 | // trackBarOta 86 | // 87 | this.trackBarOta.LargeChange = 1000; 88 | this.trackBarOta.Location = new System.Drawing.Point(90, 20); 89 | this.trackBarOta.Maximum = 4000; 90 | this.trackBarOta.Name = "trackBarOta"; 91 | this.trackBarOta.Size = new System.Drawing.Size(377, 45); 92 | this.trackBarOta.SmallChange = 4; 93 | this.trackBarOta.TabIndex = 0; 94 | this.trackBarOta.TickFrequency = 80; 95 | this.trackBarOta.TickStyle = System.Windows.Forms.TickStyle.Both; 96 | this.trackBarOta.Scroll += new System.EventHandler(this.trackBarOta_Scroll); 97 | this.trackBarOta.ValueChanged += new System.EventHandler(this.trackBarOta_ValueChanged); 98 | // 99 | // label1 100 | // 101 | this.label1.AutoSize = true; 102 | this.label1.Location = new System.Drawing.Point(30, 377); 103 | this.label1.Name = "label1"; 104 | this.label1.Size = new System.Drawing.Size(91, 13); 105 | this.label1.TabIndex = 1; 106 | this.label1.Text = "Used / Total size:"; 107 | // 108 | // progressBar1 109 | // 110 | this.progressBar1.Location = new System.Drawing.Point(12, 393); 111 | this.progressBar1.MarqueeAnimationSpeed = 200; 112 | this.progressBar1.Name = "progressBar1"; 113 | this.progressBar1.Size = new System.Drawing.Size(484, 23); 114 | this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Continuous; 115 | this.progressBar1.TabIndex = 2; 116 | // 117 | // labelProgress 118 | // 119 | this.labelProgress.AutoSize = true; 120 | this.labelProgress.Location = new System.Drawing.Point(381, 376); 121 | this.labelProgress.Name = "labelProgress"; 122 | this.labelProgress.Size = new System.Drawing.Size(54, 13); 123 | this.labelProgress.TabIndex = 3; 124 | this.labelProgress.Text = "0 / 4120k"; 125 | // 126 | // checkBoxOta 127 | // 128 | this.checkBoxOta.AutoSize = true; 129 | this.checkBoxOta.Checked = true; 130 | this.checkBoxOta.CheckState = System.Windows.Forms.CheckState.Checked; 131 | this.checkBoxOta.Location = new System.Drawing.Point(12, 48); 132 | this.checkBoxOta.Name = "checkBoxOta"; 133 | this.checkBoxOta.Size = new System.Drawing.Size(48, 17); 134 | this.checkBoxOta.TabIndex = 4; 135 | this.checkBoxOta.Text = "OTA"; 136 | this.checkBoxOta.UseVisualStyleBackColor = true; 137 | this.checkBoxOta.CheckedChanged += new System.EventHandler(this.checkBoxOta_CheckedChanged); 138 | // 139 | // checkBoxNvs 140 | // 141 | this.checkBoxNvs.AutoSize = true; 142 | this.checkBoxNvs.Checked = true; 143 | this.checkBoxNvs.CheckState = System.Windows.Forms.CheckState.Checked; 144 | this.checkBoxNvs.Location = new System.Drawing.Point(12, 177); 145 | this.checkBoxNvs.Name = "checkBoxNvs"; 146 | this.checkBoxNvs.Size = new System.Drawing.Size(48, 17); 147 | this.checkBoxNvs.TabIndex = 6; 148 | this.checkBoxNvs.Text = "NVS"; 149 | this.checkBoxNvs.UseVisualStyleBackColor = true; 150 | this.checkBoxNvs.CheckedChanged += new System.EventHandler(this.checkBoxNvs_CheckedChanged); 151 | // 152 | // trackBarNvs 153 | // 154 | this.trackBarNvs.LargeChange = 1000; 155 | this.trackBarNvs.Location = new System.Drawing.Point(90, 164); 156 | this.trackBarNvs.Maximum = 4000; 157 | this.trackBarNvs.Name = "trackBarNvs"; 158 | this.trackBarNvs.Size = new System.Drawing.Size(377, 45); 159 | this.trackBarNvs.SmallChange = 4; 160 | this.trackBarNvs.TabIndex = 5; 161 | this.trackBarNvs.TickFrequency = 80; 162 | this.trackBarNvs.TickStyle = System.Windows.Forms.TickStyle.Both; 163 | this.trackBarNvs.ValueChanged += new System.EventHandler(this.trackBarNvs_ValueChanged); 164 | // 165 | // checkBoxEeprom 166 | // 167 | this.checkBoxEeprom.AutoSize = true; 168 | this.checkBoxEeprom.Location = new System.Drawing.Point(12, 228); 169 | this.checkBoxEeprom.Name = "checkBoxEeprom"; 170 | this.checkBoxEeprom.Size = new System.Drawing.Size(72, 17); 171 | this.checkBoxEeprom.TabIndex = 8; 172 | this.checkBoxEeprom.Text = "EEPROM"; 173 | this.checkBoxEeprom.UseVisualStyleBackColor = true; 174 | this.checkBoxEeprom.CheckedChanged += new System.EventHandler(this.checkBoxEeprom_CheckedChanged); 175 | // 176 | // trackBarEeprom 177 | // 178 | this.trackBarEeprom.Enabled = false; 179 | this.trackBarEeprom.LargeChange = 1000; 180 | this.trackBarEeprom.Location = new System.Drawing.Point(90, 215); 181 | this.trackBarEeprom.Maximum = 4000; 182 | this.trackBarEeprom.Name = "trackBarEeprom"; 183 | this.trackBarEeprom.Size = new System.Drawing.Size(377, 45); 184 | this.trackBarEeprom.SmallChange = 4; 185 | this.trackBarEeprom.TabIndex = 7; 186 | this.trackBarEeprom.TickFrequency = 80; 187 | this.trackBarEeprom.TickStyle = System.Windows.Forms.TickStyle.Both; 188 | this.trackBarEeprom.ValueChanged += new System.EventHandler(this.trackBarEeprom_ValueChanged); 189 | // 190 | // checkBoxSpiffs 191 | // 192 | this.checkBoxSpiffs.AutoSize = true; 193 | this.checkBoxSpiffs.Location = new System.Drawing.Point(12, 279); 194 | this.checkBoxSpiffs.Name = "checkBoxSpiffs"; 195 | this.checkBoxSpiffs.Size = new System.Drawing.Size(62, 17); 196 | this.checkBoxSpiffs.TabIndex = 10; 197 | this.checkBoxSpiffs.Text = "SPIFFS"; 198 | this.checkBoxSpiffs.UseVisualStyleBackColor = true; 199 | this.checkBoxSpiffs.CheckedChanged += new System.EventHandler(this.checkBoxSpiffs_CheckedChanged); 200 | // 201 | // trackBarSpiffs 202 | // 203 | this.trackBarSpiffs.Enabled = false; 204 | this.trackBarSpiffs.LargeChange = 1000; 205 | this.trackBarSpiffs.Location = new System.Drawing.Point(90, 266); 206 | this.trackBarSpiffs.Maximum = 4000; 207 | this.trackBarSpiffs.Name = "trackBarSpiffs"; 208 | this.trackBarSpiffs.Size = new System.Drawing.Size(377, 45); 209 | this.trackBarSpiffs.SmallChange = 4; 210 | this.trackBarSpiffs.TabIndex = 9; 211 | this.trackBarSpiffs.TickFrequency = 80; 212 | this.trackBarSpiffs.TickStyle = System.Windows.Forms.TickStyle.Both; 213 | this.trackBarSpiffs.ValueChanged += new System.EventHandler(this.trackBarSpiffs_ValueChanged); 214 | // 215 | // labelOta 216 | // 217 | this.labelOta.AutoSize = true; 218 | this.labelOta.Location = new System.Drawing.Point(465, 34); 219 | this.labelOta.Name = "labelOta"; 220 | this.labelOta.Size = new System.Drawing.Size(31, 13); 221 | this.labelOta.TabIndex = 11; 222 | this.labelOta.Text = "100k"; 223 | // 224 | // labelNvs 225 | // 226 | this.labelNvs.AutoSize = true; 227 | this.labelNvs.Location = new System.Drawing.Point(465, 177); 228 | this.labelNvs.Name = "labelNvs"; 229 | this.labelNvs.Size = new System.Drawing.Size(31, 13); 230 | this.labelNvs.TabIndex = 12; 231 | this.labelNvs.Text = "100k"; 232 | // 233 | // labelEeprom 234 | // 235 | this.labelEeprom.AutoSize = true; 236 | this.labelEeprom.Location = new System.Drawing.Point(465, 228); 237 | this.labelEeprom.Name = "labelEeprom"; 238 | this.labelEeprom.Size = new System.Drawing.Size(31, 13); 239 | this.labelEeprom.TabIndex = 13; 240 | this.labelEeprom.Text = "100k"; 241 | // 242 | // labelSpiffs 243 | // 244 | this.labelSpiffs.AutoSize = true; 245 | this.labelSpiffs.Location = new System.Drawing.Point(465, 279); 246 | this.labelSpiffs.Name = "labelSpiffs"; 247 | this.labelSpiffs.Size = new System.Drawing.Size(31, 13); 248 | this.labelSpiffs.TabIndex = 14; 249 | this.labelSpiffs.Text = "100k"; 250 | // 251 | // button1 252 | // 253 | this.button1.Image = global::esp_tools_gui.Properties.Resources.export32; 254 | this.button1.ImageAlign = System.Drawing.ContentAlignment.TopCenter; 255 | this.button1.Location = new System.Drawing.Point(118, 433); 256 | this.button1.Name = "button1"; 257 | this.button1.Size = new System.Drawing.Size(100, 55); 258 | this.button1.TabIndex = 15; 259 | this.button1.Text = "Export Table"; 260 | this.button1.TextAlign = System.Drawing.ContentAlignment.BottomCenter; 261 | this.button1.UseVisualStyleBackColor = true; 262 | this.button1.Click += new System.EventHandler(this.button1_Click); 263 | // 264 | // button2 265 | // 266 | this.button2.Image = global::esp_tools_gui.Properties.Resources.burn32; 267 | this.button2.ImageAlign = System.Drawing.ContentAlignment.TopCenter; 268 | this.button2.Location = new System.Drawing.Point(224, 433); 269 | this.button2.Name = "button2"; 270 | this.button2.Size = new System.Drawing.Size(100, 55); 271 | this.button2.TabIndex = 16; 272 | this.button2.Text = "Burn Table"; 273 | this.button2.TextAlign = System.Drawing.ContentAlignment.BottomCenter; 274 | this.button2.UseVisualStyleBackColor = true; 275 | this.button2.Click += new System.EventHandler(this.button2_Click); 276 | // 277 | // button3 278 | // 279 | this.button3.Location = new System.Drawing.Point(12, 496); 280 | this.button3.Name = "button3"; 281 | this.button3.Size = new System.Drawing.Size(484, 30); 282 | this.button3.TabIndex = 17; 283 | this.button3.Text = "Cancel"; 284 | this.button3.UseVisualStyleBackColor = true; 285 | this.button3.Click += new System.EventHandler(this.button3_Click); 286 | // 287 | // saveFileDialog1 288 | // 289 | this.saveFileDialog1.Filter = "bin-File|*.bin|csv-File|*.csv"; 290 | this.saveFileDialog1.RestoreDirectory = true; 291 | this.saveFileDialog1.Title = "Save Partition Table"; 292 | // 293 | // labelOta1 294 | // 295 | this.labelOta1.AutoSize = true; 296 | this.labelOta1.Location = new System.Drawing.Point(465, 76); 297 | this.labelOta1.Name = "labelOta1"; 298 | this.labelOta1.Size = new System.Drawing.Size(31, 13); 299 | this.labelOta1.TabIndex = 20; 300 | this.labelOta1.Text = "100k"; 301 | // 302 | // trackBarOta1 303 | // 304 | this.trackBarOta1.Enabled = false; 305 | this.trackBarOta1.LargeChange = 1000; 306 | this.trackBarOta1.Location = new System.Drawing.Point(90, 62); 307 | this.trackBarOta1.Maximum = 4000; 308 | this.trackBarOta1.Name = "trackBarOta1"; 309 | this.trackBarOta1.Size = new System.Drawing.Size(377, 45); 310 | this.trackBarOta1.SmallChange = 4; 311 | this.trackBarOta1.TabIndex = 18; 312 | this.trackBarOta1.TickFrequency = 80; 313 | this.trackBarOta1.TickStyle = System.Windows.Forms.TickStyle.Both; 314 | this.trackBarOta1.ValueChanged += new System.EventHandler(this.trackBarOta1_ValueChanged); 315 | // 316 | // checkBoxOtaLock 317 | // 318 | this.checkBoxOtaLock.AutoSize = true; 319 | this.checkBoxOtaLock.Checked = true; 320 | this.checkBoxOtaLock.CheckState = System.Windows.Forms.CheckState.Checked; 321 | this.checkBoxOtaLock.Location = new System.Drawing.Point(33, 72); 322 | this.checkBoxOtaLock.Name = "checkBoxOtaLock"; 323 | this.checkBoxOtaLock.Size = new System.Drawing.Size(50, 17); 324 | this.checkBoxOtaLock.TabIndex = 21; 325 | this.checkBoxOtaLock.Text = "Lock"; 326 | this.checkBoxOtaLock.UseVisualStyleBackColor = true; 327 | this.checkBoxOtaLock.CheckedChanged += new System.EventHandler(this.checkBoxOtaLock_CheckedChanged); 328 | // 329 | // openFileDialog1 330 | // 331 | this.openFileDialog1.FileName = "openFileDialog1"; 332 | this.openFileDialog1.Filter = "bin-File|*.bin|csv-File|*.csv"; 333 | this.openFileDialog1.FilterIndex = 2; 334 | this.openFileDialog1.RestoreDirectory = true; 335 | this.openFileDialog1.Title = "Import Partition Table"; 336 | // 337 | // button4 338 | // 339 | this.button4.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; 340 | this.button4.Image = global::esp_tools_gui.Properties.Resources.import32; 341 | this.button4.ImageAlign = System.Drawing.ContentAlignment.TopCenter; 342 | this.button4.Location = new System.Drawing.Point(12, 433); 343 | this.button4.Name = "button4"; 344 | this.button4.Size = new System.Drawing.Size(100, 55); 345 | this.button4.TabIndex = 22; 346 | this.button4.Text = "Import Table"; 347 | this.button4.TextAlign = System.Drawing.ContentAlignment.BottomCenter; 348 | this.button4.UseVisualStyleBackColor = true; 349 | this.button4.Click += new System.EventHandler(this.button4_Click); 350 | // 351 | // button5 352 | // 353 | this.button5.Image = global::esp_tools_gui.Properties.Resources.add32; 354 | this.button5.ImageAlign = System.Drawing.ContentAlignment.TopCenter; 355 | this.button5.Location = new System.Drawing.Point(330, 433); 356 | this.button5.Name = "button5"; 357 | this.button5.Size = new System.Drawing.Size(166, 55); 358 | this.button5.TabIndex = 23; 359 | this.button5.Text = "Add to Arduino IDE"; 360 | this.button5.TextAlign = System.Drawing.ContentAlignment.BottomCenter; 361 | this.button5.UseVisualStyleBackColor = true; 362 | this.button5.Click += new System.EventHandler(this.button5_Click); 363 | // 364 | // groupBox1 365 | // 366 | this.groupBox1.Controls.Add(this.button6); 367 | this.groupBox1.Controls.Add(this.textBox2); 368 | this.groupBox1.Controls.Add(this.label3); 369 | this.groupBox1.Controls.Add(this.textBox1); 370 | this.groupBox1.Controls.Add(this.label2); 371 | this.groupBox1.Controls.Add(this.treeView1); 372 | this.groupBox1.Location = new System.Drawing.Point(531, 13); 373 | this.groupBox1.Name = "groupBox1"; 374 | this.groupBox1.Size = new System.Drawing.Size(485, 513); 375 | this.groupBox1.TabIndex = 24; 376 | this.groupBox1.TabStop = false; 377 | this.groupBox1.Text = "Partitions"; 378 | // 379 | // button6 380 | // 381 | this.button6.Image = global::esp_tools_gui.Properties.Resources.add32; 382 | this.button6.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; 383 | this.button6.Location = new System.Drawing.Point(332, 461); 384 | this.button6.Name = "button6"; 385 | this.button6.Size = new System.Drawing.Size(146, 46); 386 | this.button6.TabIndex = 24; 387 | this.button6.Text = "Add to Arduino IDE"; 388 | this.button6.TextAlign = System.Drawing.ContentAlignment.MiddleRight; 389 | this.button6.UseVisualStyleBackColor = true; 390 | this.button6.Click += new System.EventHandler(this.button6_Click); 391 | // 392 | // textBox2 393 | // 394 | this.textBox2.Location = new System.Drawing.Point(79, 487); 395 | this.textBox2.Name = "textBox2"; 396 | this.textBox2.Size = new System.Drawing.Size(247, 20); 397 | this.textBox2.TabIndex = 5; 398 | // 399 | // label3 400 | // 401 | this.label3.AutoSize = true; 402 | this.label3.Location = new System.Drawing.Point(7, 490); 403 | this.label3.Name = "label3"; 404 | this.label3.Size = new System.Drawing.Size(63, 13); 405 | this.label3.TabIndex = 4; 406 | this.label3.Text = "Description:"; 407 | // 408 | // textBox1 409 | // 410 | this.textBox1.Location = new System.Drawing.Point(79, 461); 411 | this.textBox1.Name = "textBox1"; 412 | this.textBox1.ReadOnly = true; 413 | this.textBox1.Size = new System.Drawing.Size(97, 20); 414 | this.textBox1.TabIndex = 3; 415 | // 416 | // label2 417 | // 418 | this.label2.AutoSize = true; 419 | this.label2.Location = new System.Drawing.Point(7, 464); 420 | this.label2.Name = "label2"; 421 | this.label2.Size = new System.Drawing.Size(66, 13); 422 | this.label2.TabIndex = 2; 423 | this.label2.Text = "Table name:"; 424 | // 425 | // treeView1 426 | // 427 | this.treeView1.ImageIndex = 5; 428 | this.treeView1.ImageList = this.imageList1; 429 | this.treeView1.Indent = 20; 430 | this.treeView1.ItemHeight = 16; 431 | this.treeView1.Location = new System.Drawing.Point(6, 19); 432 | this.treeView1.Name = "treeView1"; 433 | treeNode1.ImageIndex = 4; 434 | treeNode1.Name = "Knoten2"; 435 | treeNode1.Text = "Partition Name"; 436 | treeNode2.Name = "Knoten0"; 437 | treeNode2.Text = "Partitions"; 438 | this.treeView1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { 439 | treeNode2}); 440 | this.treeView1.SelectedImageIndex = 0; 441 | this.treeView1.Size = new System.Drawing.Size(472, 436); 442 | this.treeView1.TabIndex = 1; 443 | // 444 | // imageList1 445 | // 446 | this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); 447 | this.imageList1.TransparentColor = System.Drawing.Color.Transparent; 448 | this.imageList1.Images.SetKeyName(0, "add.png"); 449 | this.imageList1.Images.SetKeyName(1, "burn.png"); 450 | this.imageList1.Images.SetKeyName(2, "export.png"); 451 | this.imageList1.Images.SetKeyName(3, "import.png"); 452 | this.imageList1.Images.SetKeyName(4, "kchart.png"); 453 | this.imageList1.Images.SetKeyName(5, "kde-folder-open.png"); 454 | // 455 | // trackBarOtaD 456 | // 457 | this.trackBarOtaD.Enabled = false; 458 | this.trackBarOtaD.LargeChange = 1000; 459 | this.trackBarOtaD.Location = new System.Drawing.Point(90, 113); 460 | this.trackBarOtaD.Maximum = 128; 461 | this.trackBarOtaD.Name = "trackBarOtaD"; 462 | this.trackBarOtaD.Size = new System.Drawing.Size(377, 45); 463 | this.trackBarOtaD.SmallChange = 4; 464 | this.trackBarOtaD.TabIndex = 25; 465 | this.trackBarOtaD.TickFrequency = 80; 466 | this.trackBarOtaD.TickStyle = System.Windows.Forms.TickStyle.Both; 467 | // 468 | // checkBoxOtaD 469 | // 470 | this.checkBoxOtaD.AutoSize = true; 471 | this.checkBoxOtaD.Checked = true; 472 | this.checkBoxOtaD.CheckState = System.Windows.Forms.CheckState.Checked; 473 | this.checkBoxOtaD.Enabled = false; 474 | this.checkBoxOtaD.Location = new System.Drawing.Point(12, 123); 475 | this.checkBoxOtaD.Name = "checkBoxOtaD"; 476 | this.checkBoxOtaD.Size = new System.Drawing.Size(71, 17); 477 | this.checkBoxOtaD.TabIndex = 26; 478 | this.checkBoxOtaD.Text = "OTAData"; 479 | this.checkBoxOtaD.UseVisualStyleBackColor = true; 480 | // 481 | // labelOtaD 482 | // 483 | this.labelOtaD.AutoSize = true; 484 | this.labelOtaD.Location = new System.Drawing.Point(465, 127); 485 | this.labelOtaD.Name = "labelOtaD"; 486 | this.labelOtaD.Size = new System.Drawing.Size(31, 13); 487 | this.labelOtaD.TabIndex = 27; 488 | this.labelOtaD.Text = "100k"; 489 | // 490 | // labelFfat 491 | // 492 | this.labelFfat.AutoSize = true; 493 | this.labelFfat.Location = new System.Drawing.Point(465, 330); 494 | this.labelFfat.Name = "labelFfat"; 495 | this.labelFfat.Size = new System.Drawing.Size(31, 13); 496 | this.labelFfat.TabIndex = 30; 497 | this.labelFfat.Text = "100k"; 498 | // 499 | // checkBoxFfat 500 | // 501 | this.checkBoxFfat.AutoSize = true; 502 | this.checkBoxFfat.Location = new System.Drawing.Point(12, 330); 503 | this.checkBoxFfat.Name = "checkBoxFfat"; 504 | this.checkBoxFfat.Size = new System.Drawing.Size(52, 17); 505 | this.checkBoxFfat.TabIndex = 29; 506 | this.checkBoxFfat.Text = "FFAT"; 507 | this.checkBoxFfat.UseVisualStyleBackColor = true; 508 | this.checkBoxFfat.CheckedChanged += new System.EventHandler(this.checkBoxFfat_CheckedChanged); 509 | // 510 | // trackBarFfat 511 | // 512 | this.trackBarFfat.Enabled = false; 513 | this.trackBarFfat.LargeChange = 1000; 514 | this.trackBarFfat.Location = new System.Drawing.Point(90, 317); 515 | this.trackBarFfat.Maximum = 4000; 516 | this.trackBarFfat.Name = "trackBarFfat"; 517 | this.trackBarFfat.Size = new System.Drawing.Size(377, 45); 518 | this.trackBarFfat.SmallChange = 4; 519 | this.trackBarFfat.TabIndex = 28; 520 | this.trackBarFfat.TickFrequency = 80; 521 | this.trackBarFfat.TickStyle = System.Windows.Forms.TickStyle.Both; 522 | this.trackBarFfat.ValueChanged += new System.EventHandler(this.trackBarFfat_ValueChanged); 523 | // 524 | // PartTool 525 | // 526 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 527 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 528 | this.ClientSize = new System.Drawing.Size(1044, 547); 529 | this.Controls.Add(this.groupBox1); 530 | this.Controls.Add(this.labelFfat); 531 | this.Controls.Add(this.checkBoxFfat); 532 | this.Controls.Add(this.trackBarFfat); 533 | this.Controls.Add(this.labelOtaD); 534 | this.Controls.Add(this.checkBoxOtaD); 535 | this.Controls.Add(this.trackBarOtaD); 536 | this.Controls.Add(this.button5); 537 | this.Controls.Add(this.button4); 538 | this.Controls.Add(this.checkBoxOtaLock); 539 | this.Controls.Add(this.labelOta1); 540 | this.Controls.Add(this.trackBarOta1); 541 | this.Controls.Add(this.button3); 542 | this.Controls.Add(this.button2); 543 | this.Controls.Add(this.button1); 544 | this.Controls.Add(this.labelSpiffs); 545 | this.Controls.Add(this.labelEeprom); 546 | this.Controls.Add(this.labelNvs); 547 | this.Controls.Add(this.labelOta); 548 | this.Controls.Add(this.checkBoxSpiffs); 549 | this.Controls.Add(this.trackBarSpiffs); 550 | this.Controls.Add(this.checkBoxEeprom); 551 | this.Controls.Add(this.trackBarEeprom); 552 | this.Controls.Add(this.checkBoxNvs); 553 | this.Controls.Add(this.trackBarNvs); 554 | this.Controls.Add(this.checkBoxOta); 555 | this.Controls.Add(this.labelProgress); 556 | this.Controls.Add(this.progressBar1); 557 | this.Controls.Add(this.label1); 558 | this.Controls.Add(this.trackBarOta); 559 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 560 | this.MaximizeBox = false; 561 | this.MinimizeBox = false; 562 | this.Name = "PartTool"; 563 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 564 | this.Text = "PartTool"; 565 | this.Load += new System.EventHandler(this.PartTool_Load); 566 | ((System.ComponentModel.ISupportInitialize)(this.trackBarOta)).EndInit(); 567 | ((System.ComponentModel.ISupportInitialize)(this.trackBarNvs)).EndInit(); 568 | ((System.ComponentModel.ISupportInitialize)(this.trackBarEeprom)).EndInit(); 569 | ((System.ComponentModel.ISupportInitialize)(this.trackBarSpiffs)).EndInit(); 570 | ((System.ComponentModel.ISupportInitialize)(this.trackBarOta1)).EndInit(); 571 | this.groupBox1.ResumeLayout(false); 572 | this.groupBox1.PerformLayout(); 573 | ((System.ComponentModel.ISupportInitialize)(this.trackBarOtaD)).EndInit(); 574 | ((System.ComponentModel.ISupportInitialize)(this.trackBarFfat)).EndInit(); 575 | this.ResumeLayout(false); 576 | this.PerformLayout(); 577 | 578 | } 579 | 580 | #endregion 581 | 582 | private System.Windows.Forms.TrackBar trackBarOta; 583 | private System.Windows.Forms.Label label1; 584 | private System.Windows.Forms.ProgressBar progressBar1; 585 | private System.Windows.Forms.Label labelProgress; 586 | private System.Windows.Forms.CheckBox checkBoxOta; 587 | private System.Windows.Forms.CheckBox checkBoxNvs; 588 | private System.Windows.Forms.TrackBar trackBarNvs; 589 | private System.Windows.Forms.CheckBox checkBoxEeprom; 590 | private System.Windows.Forms.TrackBar trackBarEeprom; 591 | private System.Windows.Forms.CheckBox checkBoxSpiffs; 592 | private System.Windows.Forms.TrackBar trackBarSpiffs; 593 | private System.Windows.Forms.Label labelOta; 594 | private System.Windows.Forms.Label labelNvs; 595 | private System.Windows.Forms.Label labelEeprom; 596 | private System.Windows.Forms.Label labelSpiffs; 597 | private System.Windows.Forms.Button button1; 598 | private System.Windows.Forms.Button button2; 599 | private System.Windows.Forms.Button button3; 600 | private System.Windows.Forms.SaveFileDialog saveFileDialog1; 601 | private System.Windows.Forms.Label labelOta1; 602 | private System.Windows.Forms.TrackBar trackBarOta1; 603 | private System.Windows.Forms.CheckBox checkBoxOtaLock; 604 | private System.Windows.Forms.Button button4; 605 | private System.Windows.Forms.OpenFileDialog openFileDialog1; 606 | private System.Windows.Forms.Button button5; 607 | private System.Windows.Forms.GroupBox groupBox1; 608 | private System.Windows.Forms.TreeView treeView1; 609 | private System.Windows.Forms.ImageList imageList1; 610 | private System.Windows.Forms.Button button6; 611 | private System.Windows.Forms.TextBox textBox2; 612 | private System.Windows.Forms.Label label3; 613 | private System.Windows.Forms.TextBox textBox1; 614 | private System.Windows.Forms.Label label2; 615 | private System.Windows.Forms.TrackBar trackBarOtaD; 616 | private System.Windows.Forms.CheckBox checkBoxOtaD; 617 | private System.Windows.Forms.Label labelOtaD; 618 | private System.Windows.Forms.Label labelFfat; 619 | private System.Windows.Forms.CheckBox checkBoxFfat; 620 | private System.Windows.Forms.TrackBar trackBarFfat; 621 | } 622 | } -------------------------------------------------------------------------------- /PartTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Text.RegularExpressions; 10 | using System.Threading.Tasks; 11 | using System.Windows.Forms; 12 | 13 | namespace esp_tools_gui 14 | { 15 | public partial class PartTool : Form 16 | { 17 | static int flashSizeBytes = 0; 18 | static int flashSizeKB = 0; 19 | 20 | private ToolPartition partition; 21 | 22 | public static int BaseAddress = 0x9000; 23 | 24 | public static int Eeprom = 0; 25 | public static int Nvs = 0; 26 | public static int Ota0 = 0; 27 | public static int Ota1 = 0; 28 | public static int Otad = 8 * 1024; 29 | public static bool OtaEnabled = false; 30 | public static int Spiffs = 0; 31 | public static int Ffat = 0; 32 | 33 | public PartTool(int flashMB, ToolPartition partitionTool) 34 | { 35 | InitializeComponent(); 36 | flashSizeBytes = flashMB * 1024 * 1024; 37 | flashSizeKB = flashMB * 1024; 38 | 39 | progressBar1.Value = 0; 40 | progressBar1.Maximum = flashSizeKB; 41 | 42 | partition = partitionTool; 43 | 44 | this.Width /= 2; 45 | } 46 | 47 | private void PartTool_Load(object sender, EventArgs e) 48 | { 49 | trackBarOta.SmallChange = 64; 50 | trackBarOta1.SmallChange = 64; 51 | trackBarOtaD.SmallChange = 1; 52 | trackBarOta.TickFrequency = 256; 53 | trackBarOta1.TickFrequency = 256; 54 | trackBarOtaD.TickFrequency = 8; 55 | 56 | trackBarEeprom.SmallChange = 4; 57 | trackBarNvs.SmallChange = 4; 58 | trackBarEeprom.TickFrequency = 4; 59 | trackBarNvs.TickFrequency = 4; 60 | 61 | trackBarSpiffs.SmallChange = 4; 62 | trackBarSpiffs.TickFrequency = 128; 63 | trackBarFfat.SmallChange = 4; 64 | trackBarFfat.TickFrequency = 128; 65 | Calculate(); 66 | } 67 | 68 | public int Calculate() 69 | { 70 | int total = 0; 71 | int free = 0; 72 | total = BaseAddress; 73 | if (checkBoxNvs.Checked) total += Nvs; 74 | if (checkBoxOta.Checked) total += Otad + Ota0 + Ota1; 75 | else total += Ota0; 76 | if (checkBoxEeprom.Checked) total += Eeprom; 77 | if (checkBoxSpiffs.Checked) total += Spiffs; 78 | if (checkBoxFfat.Checked) total += Ffat; 79 | total /= 1024; 80 | free = flashSizeKB - total; 81 | 82 | progressBar1.Value = Math.Min(progressBar1.Maximum, total); 83 | if(total > progressBar1.Maximum) 84 | { 85 | labelProgress.ForeColor = Color.DarkRed; 86 | } 87 | else 88 | { 89 | labelProgress.ForeColor = Color.Black; 90 | } 91 | labelProgress.Text = total + "kb / " + flashSizeKB + "kb"; 92 | 93 | labelOta.Text = trackBarOta.Value + "kb"; 94 | if (checkBoxOtaLock.Checked) 95 | { 96 | labelOta1.Text = trackBarOta.Value + "kb"; 97 | trackBarOta1.Value = trackBarOta.Value; 98 | } 99 | else 100 | { 101 | labelOta1.Text = trackBarOta1.Value + "kb"; 102 | } 103 | labelOtaD.Text = trackBarOtaD.Value + "kb"; 104 | labelNvs.Text = (checkBoxNvs.Checked ? trackBarNvs.Value.ToString() : "0") + "kb"; 105 | labelEeprom.Text = (checkBoxEeprom.Checked ? trackBarEeprom.Value.ToString() : "0") + "kb"; 106 | labelSpiffs.Text = (checkBoxSpiffs.Checked ? trackBarSpiffs.Value.ToString() : "0") + "kb"; 107 | labelFfat.Text = (checkBoxFfat.Checked ? trackBarFfat.Value.ToString() : "0") + "kb"; 108 | 109 | if (free < 0) return free; 110 | 111 | trackBarEeprom.Maximum = trackBarEeprom.Value + free; 112 | trackBarNvs.Maximum = trackBarNvs.Value + free; 113 | if (checkBoxOta.Checked) 114 | trackBarOta.Maximum = trackBarOta.Value + free / 2; 115 | else 116 | trackBarOta.Maximum = trackBarOta.Value + free; 117 | trackBarOta1.Maximum = trackBarOta1.Value + free; 118 | trackBarSpiffs.Maximum = trackBarSpiffs.Value + free; 119 | trackBarFfat.Maximum = trackBarFfat.Value + free; 120 | 121 | return free; 122 | } 123 | 124 | public void SetEeprom(int size) 125 | { 126 | Eeprom = size; 127 | if (!trackBarEeprom.Enabled) checkBoxEeprom.Checked = true; 128 | if (size / 1024 > trackBarEeprom.Maximum) trackBarEeprom.Maximum = size / 1024; 129 | trackBarEeprom.Value = size / 1024; 130 | Calculate(); 131 | } 132 | public void SetNvs(int size) 133 | { 134 | Nvs = size; 135 | if (size / 1024 > trackBarNvs.Maximum) trackBarNvs.Maximum = size / 1024; 136 | trackBarNvs.Value = size / 1024; 137 | Calculate(); 138 | } 139 | public void SetOta0(int size, bool? useOta) 140 | { 141 | Ota0 = size; 142 | if (size / 1024 > trackBarOta.Maximum) trackBarOta.Maximum = size / 1024; 143 | trackBarOta.Value = size / 1024; 144 | if (useOta != null) 145 | { 146 | OtaEnabled = (bool)useOta; 147 | checkBoxOta.Checked = (bool)useOta; 148 | if (useOta == true) 149 | { 150 | Ota1 = size; 151 | } 152 | else 153 | { 154 | Ota1 = 0; 155 | } 156 | } 157 | Calculate(); 158 | } 159 | public void SetOta1(int size) 160 | { 161 | Ota1 = size; 162 | if (size / 1024 > trackBarOta1.Maximum) trackBarOta1.Maximum = size / 1024; 163 | trackBarOta1.Value = size / 1024; 164 | checkBoxOta.Checked = true; 165 | checkBoxOtaLock.Checked = (Ota1 == Ota0); 166 | OtaEnabled = true; 167 | Calculate(); 168 | } 169 | public void SetOtaD(int size) 170 | { 171 | //Otad = size; 172 | if (size / 1024 > trackBarOtaD.Maximum) trackBarOtaD.Maximum = size / 1024; 173 | trackBarOtaD.Minimum = 0; 174 | trackBarOtaD.Value = size / 1024; 175 | checkBoxOtaD.Checked = true; 176 | Calculate(); 177 | } 178 | 179 | public void SetSpiffs(int size) 180 | { 181 | Spiffs = size; 182 | if (!trackBarSpiffs.Enabled) checkBoxSpiffs.Checked = true; 183 | if (size / 1024 > trackBarSpiffs.Maximum) trackBarSpiffs.Maximum = size / 1024; 184 | trackBarSpiffs.Value = size / 1024; 185 | Calculate(); 186 | } 187 | 188 | public void SetFfat(int size) 189 | { 190 | Ffat = size; 191 | if (!trackBarFfat.Enabled) checkBoxFfat.Checked = true; 192 | if (size / 1024 > trackBarFfat.Maximum) trackBarFfat.Maximum = size / 1024; 193 | trackBarFfat.Value = size / 1024; 194 | Calculate(); 195 | } 196 | 197 | private void trackBarOta_ValueChanged(object sender, EventArgs e) 198 | { 199 | Ota0 = (trackBarOta.Value - trackBarOta.Value % 64) * 1024; 200 | trackBarOta.Value = Ota0 / 1024; 201 | if (checkBoxOtaLock.Checked) 202 | { 203 | Ota1 = Ota0; 204 | if (Ota0 / 1024 > trackBarOta1.Maximum) trackBarOta1.Maximum = Ota0 / 1024; 205 | trackBarOta1.Value = Ota0 / 1024; 206 | if (trackBarOta.Value > trackBarOta1.Maximum) trackBarOta1.Maximum = trackBarOta.Value; 207 | trackBarOta1.Value = trackBarOta.Value; 208 | } 209 | Calculate(); 210 | } 211 | 212 | private void trackBarOta1_ValueChanged(object sender, EventArgs e) 213 | { 214 | if (!checkBoxOtaLock.Checked) 215 | { 216 | Ota1 = (trackBarOta1.Value - (trackBarOta1.Value % 64)) * 1024; 217 | trackBarOta1.Value = Ota1 / 1024; 218 | Calculate(); 219 | } 220 | } 221 | 222 | private void trackBarNvs_ValueChanged(object sender, EventArgs e) 223 | { 224 | Nvs = (trackBarNvs.Value - trackBarNvs.Value % 4) * 1024; 225 | trackBarNvs.Value = Nvs / 1024; 226 | Calculate(); 227 | } 228 | 229 | private void trackBarEeprom_ValueChanged(object sender, EventArgs e) 230 | { 231 | Eeprom = (trackBarEeprom.Value - trackBarEeprom.Value % 4) * 1024; 232 | trackBarEeprom.Value = Eeprom / 1024; 233 | Calculate(); 234 | } 235 | 236 | private void trackBarSpiffs_ValueChanged(object sender, EventArgs e) 237 | { 238 | Spiffs = (trackBarSpiffs.Value - trackBarSpiffs.Value % 4) * 1024; 239 | trackBarSpiffs.Value = Spiffs / 1024; 240 | Calculate(); 241 | } 242 | 243 | private void trackBarFfat_ValueChanged(object sender, EventArgs e) 244 | { 245 | Ffat = (trackBarFfat.Value - trackBarFfat.Value % 4) * 1024; 246 | trackBarFfat.Value = Ffat / 1024; 247 | Calculate(); 248 | } 249 | 250 | private void checkBoxOta_CheckedChanged(object sender, EventArgs e) 251 | { 252 | OtaEnabled = checkBoxOta.Checked; 253 | checkBoxOtaLock.Enabled = checkBoxOta.Checked; 254 | if (checkBoxOta.Checked) 255 | { 256 | trackBarOta1.Enabled = !checkBoxOtaLock.Checked; 257 | Ota1 = Ota0; 258 | Calculate(); 259 | } 260 | else 261 | { 262 | trackBarOta1.Enabled = false; 263 | Ota1 = 0; 264 | Calculate(); 265 | } 266 | } 267 | 268 | private void checkBoxNvs_CheckedChanged(object sender, EventArgs e) 269 | { 270 | if (checkBoxNvs.Checked) 271 | { 272 | Nvs = trackBarNvs.Value * 1024; 273 | trackBarNvs.Enabled = true; 274 | Calculate(); 275 | } 276 | else 277 | { 278 | Nvs = 0; 279 | trackBarNvs.Enabled = false; 280 | Calculate(); 281 | } 282 | } 283 | 284 | private void checkBoxEeprom_CheckedChanged(object sender, EventArgs e) 285 | { 286 | if (checkBoxEeprom.Checked) 287 | { 288 | Eeprom = trackBarEeprom.Value * 1024; 289 | trackBarEeprom.Enabled = true; 290 | Calculate(); 291 | } 292 | else 293 | { 294 | Eeprom = 0; 295 | trackBarEeprom.Enabled = false; 296 | Calculate(); 297 | } 298 | } 299 | 300 | private void checkBoxSpiffs_CheckedChanged(object sender, EventArgs e) 301 | { 302 | if (checkBoxSpiffs.Checked) 303 | { 304 | Spiffs = trackBarSpiffs.Value * 1024; 305 | trackBarSpiffs.Enabled = true; 306 | Calculate(); 307 | } 308 | else 309 | { 310 | Spiffs = 0; 311 | trackBarSpiffs.Enabled = false; 312 | Calculate(); 313 | } 314 | } 315 | 316 | private void checkBoxFfat_CheckedChanged(object sender, EventArgs e) 317 | { 318 | if (checkBoxFfat.Checked) 319 | { 320 | Ffat = trackBarFfat.Value * 1024; 321 | trackBarFfat.Enabled = true; 322 | Calculate(); 323 | } 324 | else 325 | { 326 | Ffat = 0; 327 | trackBarFfat.Enabled = false; 328 | Calculate(); 329 | } 330 | } 331 | 332 | private void button3_Click(object sender, EventArgs e) 333 | { 334 | if (groupBox1.Left == progressBar1.Left) 335 | { 336 | groupBox1.Left = this.Width + 100; 337 | } 338 | else 339 | { 340 | DialogResult = DialogResult.Cancel; 341 | this.Close(); 342 | } 343 | } 344 | 345 | private void button2_Click(object sender, EventArgs e) 346 | { 347 | DialogResult = DialogResult.Yes; 348 | Close(); 349 | } 350 | 351 | private void trackBarOta_Scroll(object sender, EventArgs e) 352 | { 353 | 354 | } 355 | 356 | private void button1_Click(object sender, EventArgs e) 357 | { 358 | if (saveFileDialog1.ShowDialog() == DialogResult.OK) 359 | { 360 | SavePartition(saveFileDialog1.FileName); 361 | } 362 | } 363 | 364 | private async void SavePartition(string filename) 365 | { 366 | await partition.CreatePartition(Nvs, Ota0, Ota1, Eeprom, Spiffs, Ffat); 367 | File.Copy(partition.GetPartitionPath(filename.EndsWith(".bin")), filename, true); 368 | } 369 | 370 | private void checkBoxOtaLock_CheckedChanged(object sender, EventArgs e) 371 | { 372 | trackBarOta1.Enabled = !checkBoxOtaLock.Checked; 373 | } 374 | 375 | private int convertCSVInteger(string inString) 376 | { 377 | if(inString.StartsWith("0x")) 378 | { 379 | return Convert.ToInt32(inString.Trim(), 16); 380 | } 381 | else 382 | { 383 | int multiplier = 0; 384 | if(inString.Contains("K")) 385 | { 386 | inString = inString.Replace("K", ""); 387 | multiplier = 1024; 388 | } 389 | else if (inString.Contains("M")) 390 | { 391 | inString = inString.Replace("M", ""); 392 | multiplier = 1024 * 1024; 393 | } 394 | return Convert.ToInt32(inString.Trim(), 10) * multiplier; 395 | } 396 | } 397 | 398 | private async void button4_Click(object sender, EventArgs e) 399 | { 400 | openFileDialog1.Title = "Import partition table"; 401 | 402 | if (openFileDialog1.ShowDialog() != DialogResult.OK) return; 403 | 404 | if(await partition.ImportTable(openFileDialog1.FileName)) 405 | { 406 | var csv = File.ReadAllLines(partition.GetPartitionPath(false)); 407 | foreach(var line in csv) 408 | { 409 | if (line.StartsWith("#")) continue; 410 | var items = line.Split(','); 411 | if (items.Count() < 5) continue; 412 | switch(items[0].Trim()) 413 | { 414 | case "nvs": SetNvs(convertCSVInteger(items[4])); break; 415 | case "app0": SetOta0(convertCSVInteger(items[4]), null); break; 416 | case "app1": SetOta1(convertCSVInteger(items[4])); break; 417 | case "eeprom": SetEeprom(convertCSVInteger(items[4])); break; 418 | case "ffat": SetFfat(convertCSVInteger(items[4])); break; 419 | case "spiffs": SetSpiffs(convertCSVInteger(items[4])); break; 420 | case "otadata": Otad = convertCSVInteger(items[4]); break; 421 | default: MessageBox.Show("Error: can't import this partition: " + items[0].Trim() + " - it will be ignored", "Import partitions"); break; 422 | } 423 | 424 | /* 425 | nvs, data, nvs, 0x9000, 0x5000, 426 | otadata, data, ota, 0xe000, 0x2000, 427 | app0, app, ota_0, 0x10000, 0x180000, 428 | app1, app, ota_1, 0x190000, 0x100000, 429 | eeprom, data, 0x99, 0x310000, 0x1000, 430 | spiffs, data, spiffs, 0x311000, 0x16f000, 431 | */ 432 | } 433 | } 434 | else 435 | { 436 | MessageBox.Show("Unable to import partition table " + openFileDialog1.FileName, "Import"); 437 | } 438 | } 439 | 440 | private void button5_Click(object sender, EventArgs e) 441 | { 442 | treeView1.Nodes.Clear(); 443 | openFileDialog1.Title = "Select partition file to insert into Arduino IDE:"; 444 | openFileDialog1.FilterIndex = 1; 445 | 446 | if (sender == button6) 447 | { 448 | // do not open the dialog again 449 | } 450 | else 451 | { 452 | if (openFileDialog1.ShowDialog() != DialogResult.OK) return; 453 | } 454 | 455 | textBox1.Text = Path.GetFileNameWithoutExtension(openFileDialog1.FileName); 456 | 457 | var appData = EnterPartitionFolder(); 458 | if (appData == "") return; 459 | 460 | var dirs = Directory.GetDirectories(appData); 461 | foreach(var d in dirs) 462 | { 463 | var boardsFile = File.ReadAllLines(Path.Combine(d, "boards.txt")); 464 | TreeNode tn = treeView1.Nodes.Add(Path.GetFileName(d), Path.GetFileName(d), 5); 465 | List boards = new List(); 466 | foreach(var l in boardsFile) 467 | { 468 | var m = Regex.Match(l, @"([a-zA-Z0-9_]*).name="); 469 | if (m.Groups.Count > 1) 470 | { 471 | boards.Add(m.Groups[1].Value); 472 | tn.Nodes.Add(m.Groups[1].Value, m.Groups[1].Value, 5); 473 | } 474 | } 475 | boards.ForEach(x => { 476 | List tn2 = new List(); 477 | foreach (var l in boardsFile) 478 | { 479 | var m = Regex.Match(l, @"^" + x + @".menu.PartitionScheme.([a-zA-Z0-9_]*)=(.*)"); 480 | if (m.Groups.Count > 2) 481 | { 482 | tn2.Add(tn.Nodes[x].Nodes.Add(m.Groups[1].Value, m.Groups[2].Value, 5)); 483 | //tn.Nodes.Add(m.Groups[1].Value, m.Groups[1].Value, 5); 484 | } 485 | } 486 | if(tn2.Count > 0) 487 | { 488 | foreach (var l in boardsFile) 489 | { 490 | tn2.ForEach(y => 491 | { 492 | var m = Regex.Match(l, @"^" + x + @".menu.PartitionScheme." + y.Name + @"\." + @"([a-zA-Z0-9_.]*)=(.*)"); 493 | if (m.Groups.Count > 2) 494 | { 495 | y.Nodes.Add(m.Groups[1].Value, m.Groups[1].Value + ":" + m.Groups[2].Value, 4); 496 | //tn.Nodes.Add(m.Groups[1].Value, m.Groups[1].Value, 5); 497 | } 498 | }); 499 | } 500 | } 501 | else 502 | { 503 | tn.Nodes[x].Remove(); 504 | } 505 | }); 506 | 507 | } 508 | 509 | groupBox1.Visible = true; 510 | groupBox1.Left = progressBar1.Left; 511 | } 512 | 513 | private string EnterSubFolder(string mainFolder, string subFolder, bool showError = true) 514 | { 515 | if(!Directory.Exists(Path.Combine(mainFolder, subFolder))) 516 | { 517 | if(showError) MessageBox.Show("Folder " + Path.Combine(mainFolder, subFolder) + " not found"); 518 | return ""; 519 | } 520 | return Path.Combine(mainFolder, subFolder); 521 | } 522 | 523 | private string EnterPartitionFolder() 524 | { 525 | var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 526 | var isLocal = EnterSubFolder(appData, "local", false); 527 | if (isLocal == "") appData = EnterSubFolder(appData, "../local"); 528 | else appData = isLocal; 529 | appData = EnterSubFolder(appData, "Arduino15"); 530 | if (appData != "") appData = EnterSubFolder(appData, "packages"); 531 | if (appData != "") appData = EnterSubFolder(appData, "esp32"); 532 | if (appData != "") appData = EnterSubFolder(appData, "hardware"); 533 | if (appData != "") appData = EnterSubFolder(appData, "esp32"); 534 | return appData; 535 | } 536 | 537 | private void button6_Click(object sender, EventArgs e) 538 | { 539 | if (textBox2.Text.Length < 3) 540 | { 541 | MessageBox.Show("Add a description for your partition", "No description", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 542 | return; 543 | } 544 | if (treeView1.Nodes.Count == 0 || treeView1.Nodes[0].Nodes.Count == 0) 545 | { 546 | MessageBox.Show("No board found inside this directory.", "No board", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 547 | return; 548 | } 549 | TreeNode editNode = null; 550 | int partitionSize = GetSizeFromFile(openFileDialog1.FileName); 551 | 552 | for (var j = 0; j < treeView1.Nodes[0].Nodes.Count; j++) 553 | { 554 | if (treeView1.Nodes[0].Nodes[j].IsSelected) 555 | { 556 | editNode = treeView1.Nodes[0].Nodes[j]; 557 | break; 558 | } 559 | } 560 | if (editNode == null) 561 | { 562 | MessageBox.Show("Please select the board to copy the new partition.", "No board", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 563 | return; 564 | } 565 | if (partitionSize == 0) 566 | { 567 | MessageBox.Show("Unable to detect partition size of OTA0", "invalid partition file", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 568 | return; 569 | } 570 | 571 | var appData = EnterPartitionFolder(); 572 | appData = EnterSubFolder(appData, editNode.Parent.Text); 573 | if (appData == "") return; 574 | var boardsFile = File.ReadAllLines(Path.Combine(appData, "boards.txt")).ToList(); 575 | List boards = new List(); 576 | bool boardFound = false; 577 | bool partitionsFound = false; 578 | int lineIndex = 0; 579 | int index = 0; 580 | boardsFile.ForEach(l => { 581 | index++; 582 | if(lineIndex > 0) 583 | { 584 | 585 | } 586 | else if (!boardFound) 587 | { 588 | var m = Regex.Match(l, @"([a-zA-Z0-9_]*).name="); 589 | if (m.Groups.Count > 1 && m.Groups[1].Value == editNode.Text) 590 | { 591 | boardFound = true; 592 | } 593 | } 594 | else 595 | { 596 | if (!partitionsFound) 597 | { 598 | if (Regex.IsMatch(l, @"^" + editNode.Text + @".menu.PartitionScheme.")) 599 | { 600 | partitionsFound = true; 601 | } 602 | } 603 | else 604 | { 605 | if (!Regex.IsMatch(l, @"^" + editNode.Text + @".menu.PartitionScheme.")) 606 | { 607 | lineIndex = index - 1; 608 | } 609 | } 610 | } 611 | }); 612 | if(lineIndex > 0) 613 | { 614 | boardsFile.Insert(lineIndex, editNode.Text + ".menu.PartitionScheme." + textBox1.Text + ".upload.maximum_size=" + partitionSize); 615 | boardsFile.Insert(lineIndex, editNode.Text + ".menu.PartitionScheme." + textBox1.Text + ".build.partitions=" + textBox1.Text); 616 | boardsFile.Insert(lineIndex, editNode.Text + ".menu.PartitionScheme." + textBox1.Text + "=" + textBox2.Text); 617 | 618 | File.WriteAllLines(Path.Combine(appData, "boards.txt"), boardsFile); 619 | 620 | button5_Click(sender, e); 621 | } 622 | else 623 | { 624 | MessageBox.Show("Unable to find partition scheme on this board", "index not found", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 625 | return; 626 | } 627 | } 628 | 629 | private int GetSizeFromFile(string file) 630 | { 631 | if (file.EndsWith(".bin")) 632 | { 633 | var bytes = File.ReadAllBytes(file); 634 | for (var j = 0; j < 16; j++) 635 | { 636 | if(Encoding.ASCII.GetString(bytes, 12 + 32 * j, 10).Trim('\0') == "app0") 637 | { 638 | int size = 0; 639 | for(var k=0;k<4;k++) 640 | { 641 | size = (size << 8) + bytes[11 + 32 * j - k]; 642 | } 643 | return size; 644 | } 645 | } 646 | } 647 | else 648 | { 649 | var lines = File.ReadAllLines(file); 650 | } 651 | return 0; 652 | } 653 | } 654 | } 655 | -------------------------------------------------------------------------------- /PartTool.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 | 17, 17 122 | 123 | 124 | 153, 17 125 | 126 | 127 | 293, 17 128 | 129 | 130 | 131 | AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w 132 | LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 133 | ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACO 134 | EwAAAk1TRnQBSQFMAgEBBgEAARABAAEQAQABEAEAARABAAT/AREBAAj/AUIBTQE2BwABNgMAASgDAAFA 135 | AwABIAMAAQEBAAEQBgABEJoAAf8BfwH/AX8BvQF3AVoBawE5AWcBWgFrAb0BdwH/AX9uAAH/AX8BoAEB 136 | AQABAgFAAQIBgAECAWABAgEgAQIBwAEBAYABAQFAAQEB/wF/BgABtQFWAbUBVgG1AVYBtQFWAbUBVgG1 137 | AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVYBtQFWAbUBVgG1AVZEAAEZAWMBHQEBAaMBAQEAAQIBIAEC 138 | ARUBVwGcAXMB0QFGAaABAQGgAQEBYAEBAYwBYQH/AX8EAAFTAX8BDwF/AQ8BfwEPAX8BDwF/AQ8BfwEP 139 | AX8BDwF/AQ8BfwEPAX8BDwF/AQ8BfwEPAX8BDwF/AVMBf0IAAZwBcwEcAQEBHAEBAc0BBQGsAQEBBAEC 140 | AQABAgHAAQEBIAECASABAgGgASEBgAEhAQgBUQEpAWEB/wF/AgAB7QF+AagBfgGoAX4BqAF+AagBfgGo 141 | AX4BqAF+AagBfgGoAX4BqAF+AagBfgGoAX4BqAF+AagBfgHtAX5CAAEcAQEBGwEBARsBAQEbAQEBXAEJ 142 | AS0BCgEMAQIBoAECAWMBIgFjASIBZAFIAkQBxwFEAYYBTAE5AWcCAAHKAX4BhQF+AYUBfgGFAX4BhQF+ 143 | AYUBfgGFAX4BhQF+AYUBfgGFAX4BhQF+AYUBfgGFAX4BhQF+AcoBfkIAARsBAQH4AQABGQEFAfkBAAH5 144 | AQAB+AEAAToBCQHAAQIBIwFAAQIBPAECATgBAgE0Aa0BWQECATwB3gF7AgAByQF6AYUBegGFAXoBhQF6 145 | AYUBegGFAXoBhQF6AYUBegGFAXoBhQF6AYUBegGFAXoBhQF6AYUBegHJAXpCAAH5AQAB1gEAAVUBFQHT 146 | AQAB1AEAAdQBAAHVAQABkAEAAQIBQAEBASwBEAFmAQABVAEAAVQBAAFwBAABqAF6AWQBegFkAXoBZAF6 147 | AWQBegFkAXoBZAF6AWQBegFkAXoBZAF6AWQBegFkAXoBZAF6AWQBegGoAXpCAAHWAQABvQEVAT0BAQE9 148 | AS4B1QEAAY8BAAGPAQABawEAAVMBdgEAAUwBAAFMAQABbAEAAWwBAAFsAgABmQF7AYcBdgFjAXoBYwF6 149 | AWMBegFjAXoBYwF6AWMBegFjAXoBYwF6AWMBegFjAXoBYwF6AWMBegFjAXoBhwF2QgABsgEAARwBAQEc 150 | AQEBHAEBARwBAQEdATIB0wEAAY0BAAEhAWABIQFQAQABYAEAAWABAAFkAQABZAIAAYgBcgFmAXYBQgF2 151 | AUIBdgFCAXYBQgF2AUIBdgFCAXYBQgF2AUIBdgFCAXYBQgF2AUIBdgFCAXYBQgF2AWYBdkIAAd0BTgEb 152 | AQEBGwEBARsBAQEbAQEBGwEBARsBAQFrAQABjQEAAYwBXQFrAV0BCAFZAYQBVAHWAW4GAAHNAXoBzQF6 153 | Ac0BegHNAXoBzQF6Ac0BegHNAXoBzQF6Ac4BegHOAXoBzgF6Ac4BegHOAXpGAAH5AQAB+QEAARkBBQE6 154 | AQkBOgEJAToBCQE6AQUBagEAAYwBUQFKAVEB5wFICgABDgF/AQ4BfwEOAX8BDgF/AQ8BfwEPAX8BLwF/ 155 | AS8BfwEPAX8BDgF/AQ4BfwEOAX8BDgF/SAAB2AEpAVYBFQGXASEB+AEpARkBMgEZATYBSBEAAQ4BfwEO 156 | AX8BDgF/AQ4BfwEOAX8BDwF/AQ8BfwEPAX8BDgF/AQ4BfwEOAX8BDgF/AQ4Bf04AAd4BewFXAT4B9gEx 157 | Ab4BdxAAAS8BfwEvAX8BLwF/AS8BfwFHAWYBRwFmAUcBZgFHAWYBRwFmAUcBZgFHAWYBRwFmAUcBZmYA 158 | AUgBZgFIAWYBSAFm+gAB/wF/Af8BfwG9AXcBnAFzATkBZwH3AV4B1gFaAfcBXgFaAWsBnAFzAd4BewH/ 159 | AX8B/wF/BAAB/wF/Ab0BdwGcAXMBnAFzAZwBcwGcAXMBnAFzAZwBcwGcAXMB/wF/DAAB/wF/Ab0BdwGc 160 | AXMBnAFzAZwBcwGcAXMBnAFzAZwBcwGcAXMB/wF/DAAB/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/ 161 | Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8KAAEKAWUBCQFhAY0BZQGuAWEBlAFuAbYBcgEK 162 | AWkKAAH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Ad4BewFaAWsBnAFzCgAB/wF/Af8BfwH/ 163 | AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwHeAXsBWgFrAZwBcwgAAf8BfwEsAU4BTQFSAU0BUgFNAVIBbQFW 164 | AW0BVgFtAVYBbQFWAW0BVgFtAVYBbQFWAU0BUgFNAVIBTAFSASwBTggAAekBYAF7AW8BegFvAfYBXgFx 165 | AVIB9gFeAVoBawH/AX8BMgFuCAAB/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwHeAnsBbwG9 166 | AXcBGAFjCAAB/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwHeAnsBbwG9AXcBGAFjCAAB6wFF 167 | AQsBSgEsAU4BLAFOAUwBUgFNAVIBTQFSAU0BUgFNAVIBTQFSAUwBUgEsAU4BLAFKAQsBSgHrAUUGAAHI 168 | AWQBnAFzAc0BTQGxAX8BsQF/AbIBfwGyAX8B0gF/AZMBVgFaAW8BMgFuBgAB/wF/Af8BfwH/AX8B/wF/ 169 | Af8BfwH/AX8B/wF/Af8BfwHeAXsBvQF3Af8BfwG9AXcBnAFzBgAB/wF/Af8BfwH/AX8B/wF/Af8BfwH/ 170 | AX8B/wF/Af8BfwHeAXsBvQF3Af8BfwG9AXcBnAFzBgABDAFKASwBTgFNAVIBTQFSAW0BVgFuAVYBjgFa 171 | AY4BWgGOAVoBbQFWAW0BVgFNAVIBTAFSASwBTgELAUoEAAHpAWQBewFzAUoBSQGOAX8BSwF7ASkBewEp 172 | AXsBKQF7AUsBewGQAX8BcgFSARgBZwHIAWQEAAH/AX8B/wF/Ad4BewH/AX8B/wF/Af8BfwH/AX8B/wF/ 173 | Af8BfwE0ASYBvQF3AZwBcwGcAXMB3gF7BAAB/wF/Af8BfwHeAXsB/wF/Af8BfwH/AX8B/wF/Af8BfwH/ 174 | AX8B3gF7Ab0BdwGcAXMBnAFzAd4BewQAASwBTgFNAVIBbQFWAY4BWgGOAVoBrgFeAa8BXgGvAV4BrwFe 175 | AY4BXgGOAVoBjgFaAW0BVgFNAVIBLAFOBAAB6QFoAXsBbwGtAXIBCAF3AUkBfwEIAXcBCAF3AQgBdwEI 176 | AXcBhAFgAdcBfwE5AWcBtQF2BAAB/wF/Af8BfwHeAXsB/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B+wE6 177 | AZsBQgFbAWsB3gF7AZwBcwQAAf8BfwH/AX8B3gF7Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwHb 178 | AT4B6gEUAd4BewGcAXMEAAFNAVIBbgFWAY4BWgGvAV4BrwFiAc8BYgHQAWYB0AFmAdABZgHPAWIBrwFi 179 | Aa8BXgGOAVoBbQFWAU0BUgIAAf8BfwHpAWQBMQFOAcUBaAGmAXAByQF+AWYBdgFGAXIBRgFyAWYBcgGF 180 | AVwBYwFAAbUBWgF0AXYEAAH/AX8B/wF/Ad4BewH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwG5AToBmgE+ 181 | AVgBNgENAREBnAFzBAAB/wF/Af8BfwHeAXsB/wF/Af8BfwH/AX8B/wF/Af8BfwFNAR0BWQE6AbsBQgHp 182 | ARQB/wF/AZwBcwQAAW4BVgGOAV4BrwFeAc8BYgHQAWYB8AFmAfABagHwAWoB8AFqAfABZgEgAQMB4AEC 183 | ASABAwGOAVoBbQFWAgABewF3AbUBbgGFAUABhQFgAYYBYAEGAXIBpQFxAaUBcQHnAXwBxwF5AbgBfwFk 184 | AUQB7wFFAY0BZQQAAf8BfwH/AX8B3gF7Ad4BewH/AX8B/wF/AQwBEQGzASEBNwEyAVkBOgFZATYBNwEy 185 | AdUBKQFyAR0EAAH/AX8B/wF/Ad4BewHeAXsB/wF/Af8BfwH/AX8BswEhARYBLgFYATYBeQE6AZoBPgFY 186 | ATIBswEhBAABjgFaAa8BXgHPAWIB8AFmAfABagERAWsBEQFrAREBbwEAAQMBoAECAYABBgFgAQoBgAEG 187 | AcABAgGOAVoCAAH/AX8BKwFlAa4BSQGFAVQBpwFkAYUBcQGIAXkBIwFtAegBfAGnAWABBwFpAWQBRAG1 188 | AVYBSwFtBAAB/wF/Af8BfwHeAXsB3gF7Ad4BewH/AX8B7AEQAfUBLQF4AToBeQE+AVgBOgEWAS4BtAEl 189 | AXEBGQHtAQwCAAH/AX8B/wF/Ad4BewHeAXsB3gF7AXwBawEvAREBkgEdAdUBKQEXATIBOAEyATcBMgH2 190 | ASkBUQEZBAABjgFeAc8BYgHQAWYB8AFqAREBawERAW8BMQFvATEBbwGgAQIB4AESAeABIgH/AX8BIAEj 191 | AcABCgHAAQIEAAEqAWkBewFvAWUBUAFLAWUBbAFxAWwBcQGCAWgBogFsAUsBZQERAW4BZAFAAVoBawHI 192 | AWgEAAH/AX8B/wF/Ad4BewHeAXsB3gF7Ad4BewFPAR0BVgE+AZgBQgG5AUYBuQFGAZgBQgF3AT4BVgE6 193 | ATcBNgIAAf8BfwH/AX8B3gF7Ad4BewHeAXsBOwFfAbIBKQFWAToBdwE+AZkBQgGZAUIBmQFCAXcBPgE1 194 | ATYEAAGvAV4BzwFiAfABZgERAWsBEQFvATIBcwEyAXMBgAECAcABAgEgAQ4BAAEaAf8BfwEgARoBAAEK 195 | AcABAgQAAd4BfwH/AX8BZAFEAREBagERAW4BjwF+AaMBbAFRAXoBEQFqAfABYQEpAT0BewFvAcgBZAQA 196 | Af8BfwH/AX8BvQF3Ad4BewHeAXsB3gF7AbgBTgEvAREB7AEQAZgBRgHaAU4B2gFKAdkBTgGcAXMEAAH/ 197 | AX8B/wF/Ab0BdwHeAXsB3gF7Ad4BewHeAXsBmAFCAbkBRgG5AUoB2QFKAdkBSgG5AUoBuAFGBAABQgEI 198 | AUIBCAFCAQgBQgEIAWMBDAFjAQwBYwEMAUABAgFgAQIB/wF/Af8BfwH/AX8B/wF/Af8BfwHAAQIGAAF0 199 | AXIB/wF/AYYBSAHXAXIB0QF6ARcBewHXAXIB1gFuAccBPAGcAXMByAFgBgAB/wF/Af8BfwG9AXcBvQF3 200 | Ad4BewHeAXsB3gF7Ad4BewHeAXsBGwFbATwBVwExAREB/wF/AZwBcwQAAf8BfwH/AX8BvQF3Ab0BdwHe 201 | AXsB3gF7Ad4BewHeAXsBcwEVARsBUwEbAVMBTwEdAf8BfwGcAXMGAAFKASkBSgEpAUoBKQFKASkBSgEp 202 | AQgBIQH/AX8BBgEbAWgBMwEGATcB/wF/AYgBQwFIAS8BoAECBgAB/wF/AXQBcgH/AX8BewFzAYwBSQGE 203 | AUABzwFNAXsBbwHeAXsByAFgCAAB/wF/Af8BfwG9AXcBvQF3Ab0BdwHeAXsB3gF7Ad4BewHeAXsBGgFb 204 | ARsBXwHeAXsB3gF7AZwBcwQAAf8BfwH/AX8BvQF3Ab0BdwG9AXcB3gF7Ad4BewHeAXsB3gF7Ad4BewGe 205 | AWMBkwEdAd4BewGcAXMUAAFgAQIBcAFDAU4BQwH/AX8BkAFHAXABQwFiAQoIAAH/AX8B/wF/ASoBYQEq 206 | AV0BlQFuAekBXAHoAVwB6AFcCgAB/wF/Af8BfwG9AXcBvQF3Ab0BdwG9AXcBvQF3Ad4BewHeAXsB3gF7 207 | Ad4BewHeAXsB3gF7AZwBcwQAAf8BfwH/AX8BvQF3Ab0BdwG9AXcBvQF3Ab0BdwHeAXsB3gF7Ad4BewHe 208 | AXsB3gF7Ad4BewGcAXMWAAEgAQIBlAFTAbgBYwGAAQIBVAFTEAAB/wF/ATkBcwH/AX8OAAH/AX8B/wF/ 209 | Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8BvQF3BAAB/wF/Af8BfwH/ 210 | AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Af8BfwH/AX8B/wF/Ab0Bd4IAAUIBTQE+BwABPgMA 211 | ASgDAAFAAwABIAMAAQEBAAEBBgABARYAA/8BAAT/BAAB8AEPAv8EAAHgAQMBgAUAAcABAQGABQABgAEA 212 | AYAFAAGAAQABgAUAAYABAAGABQABgAEBAYAFAAGAAQEGAAGAAQEGAAGAAQEBwAEBBAABwAEHAcABAQQA 213 | AeABPwHAAQEEAAH8AT8BwAEBBAAC/wHHAf8EAAT/BAAC/wHAAQEBgAEfAYABHwGAAQAB+AEPAYABDwGA 214 | AQ8CAAHwAQcBgAEHAYABBwGAAQAB4AEDAYABAwGAAQMBgAEAAcABAQGAAQEBgAEBAYABAAHAAQEBgAEB 215 | AYABAQGAAQABgAEBAYABAQGAAQEBgAEAAYABAQGAAQEBgAEBAYABAAGAAQEBgAEAAYABAQGAAQABwAEB 216 | AYABAAGAAQEBgAEAAcABAQGAAQEBgAEBAYABAAHgAQMBgAEBAYABAQHAAQAB4AEHAYABAQGAAQEB/wGA 217 | AfABDwGAAQEBgAEBAf8BwQH+AT8BgAEBAYABAQj/Cw== 218 | 219 | 220 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Allgemeine Informationen über eine Assembly werden über die folgenden 6 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 7 | // die einer Assembly zugeordnet sind. 8 | [assembly: AssemblyTitle("ESP tools GUI")] 9 | [assembly: AssemblyDescription("Windows GUI for the ESP tools")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("-")] 12 | [assembly: AssemblyProduct("ESP Tools")] 13 | [assembly: AssemblyCopyright("Adriano")] 14 | [assembly: AssemblyTrademark("-")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar 18 | // für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von 19 | // COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. 20 | [assembly: ComVisible(false)] 21 | 22 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird 23 | [assembly: Guid("a5894196-3790-42a7-82f7-f7cc926368bd")] 24 | 25 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 26 | // 27 | // Hauptversion 28 | // Nebenversion 29 | // Buildnummer 30 | // Revision 31 | // 32 | [assembly: AssemblyVersion("0.3.0.0")] 33 | [assembly: AssemblyFileVersion("0.3.0.0")] 34 | -------------------------------------------------------------------------------- /Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Dieser Code wurde von einem Tool generiert. 4 | // Laufzeitversion:4.0.30319.42000 5 | // 6 | // Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn 7 | // der Code erneut generiert wird. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace esp_tools_gui.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. 17 | /// 18 | // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert 19 | // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. 20 | // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen 21 | // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | public 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 | /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | public 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("esp_tools_gui.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle 51 | /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | public static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. 65 | /// 66 | public static System.Drawing.Bitmap add { 67 | get { 68 | object obj = ResourceManager.GetObject("add", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. 75 | /// 76 | public static System.Drawing.Bitmap add32 { 77 | get { 78 | object obj = ResourceManager.GetObject("add32", resourceCulture); 79 | return ((System.Drawing.Bitmap)(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. 85 | /// 86 | public static System.Drawing.Bitmap burn { 87 | get { 88 | object obj = ResourceManager.GetObject("burn", resourceCulture); 89 | return ((System.Drawing.Bitmap)(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. 95 | /// 96 | public static System.Drawing.Bitmap burn32 { 97 | get { 98 | object obj = ResourceManager.GetObject("burn32", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. 105 | /// 106 | public static System.Drawing.Bitmap export { 107 | get { 108 | object obj = ResourceManager.GetObject("export", resourceCulture); 109 | return ((System.Drawing.Bitmap)(obj)); 110 | } 111 | } 112 | 113 | /// 114 | /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. 115 | /// 116 | public static System.Drawing.Bitmap export32 { 117 | get { 118 | object obj = ResourceManager.GetObject("export32", resourceCulture); 119 | return ((System.Drawing.Bitmap)(obj)); 120 | } 121 | } 122 | 123 | /// 124 | /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. 125 | /// 126 | public static System.Drawing.Bitmap import { 127 | get { 128 | object obj = ResourceManager.GetObject("import", resourceCulture); 129 | return ((System.Drawing.Bitmap)(obj)); 130 | } 131 | } 132 | 133 | /// 134 | /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. 135 | /// 136 | public static System.Drawing.Bitmap import32 { 137 | get { 138 | object obj = ResourceManager.GetObject("import32", resourceCulture); 139 | return ((System.Drawing.Bitmap)(obj)); 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /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 | ..\images\export.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | ..\images\add.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | 128 | ..\images\import.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 129 | 130 | 131 | ..\images\burn.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 132 | 133 | 134 | ..\images\add32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 135 | 136 | 137 | ..\images\burn32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 138 | 139 | 140 | ..\images\export32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 141 | 142 | 143 | ..\images\import32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 144 | 145 | -------------------------------------------------------------------------------- /Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Dieser Code wurde von einem Tool generiert. 4 | // Laufzeitversion:4.0.30319.42000 5 | // 6 | // Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn 7 | // der Code erneut generiert wird. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace esp_tools_gui.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.3.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.UserScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("")] 29 | public string comport { 30 | get { 31 | return ((string)(this["comport"])); 32 | } 33 | set { 34 | this["comport"] = value; 35 | } 36 | } 37 | 38 | [global::System.Configuration.UserScopedSettingAttribute()] 39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 40 | [global::System.Configuration.DefaultSettingValueAttribute("115200")] 41 | public string combaud { 42 | get { 43 | return ((string)(this["combaud"])); 44 | } 45 | set { 46 | this["combaud"] = value; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 115200 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESPToolsGUI (beta) 2 | ESP Tools GUI for Windows 3 | This is just a GUI interface for the espressif python scripts. 4 | 5 | The scripts are converted to exe and the GUI just calls them over the console. 6 | 7 | ![Info](docs/screen_info.jpg) 8 | 9 | This is the first version, just to test and get some data... So the todo list is really big! 10 | 11 | In future, it should be possible to write efuses and change partition size. 12 | 13 | You can compile it by yourself (as it is not signed) or download it from the releases. 14 | 15 | | | | 16 | |--------|--------| 17 | | ![Partitions](docs/screen_partition.jpg) | ![eFuses](docs/screen_fuse.jpg) | 18 | | ![Partitions](docs/screen_flash.jpg) | ![eFuses](docs/screen_expert.jpg) | 19 | 20 | ## Links 21 | ESP Tools - all Python scripts: 22 | https://github.com/espressif/esptool/wiki 23 | 24 | CX Freeze - converter to catch console output to GUI: 25 | https://github.com/anthony-tuininga/cx_Freeze 26 | 27 | -------------------------------------------------------------------------------- /docs/screen_copy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/docs/screen_copy.jpg -------------------------------------------------------------------------------- /docs/screen_expert.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/docs/screen_expert.jpg -------------------------------------------------------------------------------- /docs/screen_flash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/docs/screen_flash.jpg -------------------------------------------------------------------------------- /docs/screen_fuse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/docs/screen_fuse.jpg -------------------------------------------------------------------------------- /docs/screen_info.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/docs/screen_info.jpg -------------------------------------------------------------------------------- /docs/screen_partition.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/docs/screen_partition.jpg -------------------------------------------------------------------------------- /esp_tools_gui.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C01973FB-BEF4-4DBA-AB73-E2804C840489} 8 | WinExe 9 | esp_tools_gui 10 | esp_tools_gui 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | publish\ 16 | true 17 | Disk 18 | false 19 | Foreground 20 | 7 21 | Days 22 | false 23 | false 24 | true 25 | 0 26 | 1.0.0.%2a 27 | false 28 | false 29 | true 30 | 31 | 32 | AnyCPU 33 | true 34 | full 35 | false 36 | bin\Debug\ 37 | DEBUG;TRACE 38 | prompt 39 | 4 40 | 41 | 42 | AnyCPU 43 | pdbonly 44 | true 45 | bin\Release\ 46 | TRACE 47 | prompt 48 | 4 49 | 50 | 51 | esp_tools_gui.App 52 | 53 | 54 | src\ESP32.ico 55 | 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | 62 | SettingsSingleFileGenerator 63 | Settings.Designer.cs 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | Form 79 | 80 | 81 | PartTool.cs 82 | 83 | 84 | 85 | Form 86 | 87 | 88 | Connecting.cs 89 | 90 | 91 | Form 92 | 93 | 94 | MainPage.cs 95 | 96 | 97 | 98 | True 99 | True 100 | Resources.resx 101 | 102 | 103 | True 104 | True 105 | Settings.settings 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | PartTool.cs 117 | 118 | 119 | Connecting.cs 120 | Designer 121 | 122 | 123 | MainPage.cs 124 | 125 | 126 | PublicResXFileCodeGenerator 127 | Resources.Designer.cs 128 | Designer 129 | 130 | 131 | 132 | 133 | False 134 | Microsoft .NET Framework 4.7.2 %28x86 und x64%29 135 | true 136 | 137 | 138 | False 139 | .NET Framework 3.5 SP1 140 | false 141 | 142 | 143 | 144 | 145 | PreserveNewest 146 | 147 | 148 | PreserveNewest 149 | 150 | 151 | PreserveNewest 152 | 153 | 154 | PreserveNewest 155 | 156 | 157 | 158 | 159 | PreserveNewest 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | PreserveNewest 171 | 172 | 173 | PreserveNewest 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /esp_tools_gui.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29326.143 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "esp_tools_gui", "esp_tools_gui.csproj", "{C01973FB-BEF4-4DBA-AB73-E2804C840489}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C01973FB-BEF4-4DBA-AB73-E2804C840489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {C01973FB-BEF4-4DBA-AB73-E2804C840489}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {C01973FB-BEF4-4DBA-AB73-E2804C840489}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {C01973FB-BEF4-4DBA-AB73-E2804C840489}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {67AACDBD-4391-44A8-A76D-C26D13AAACC4} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /exes/ESP32py.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/exes/ESP32py.ico -------------------------------------------------------------------------------- /exes/cxfreeze.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/exes/cxfreeze.zip -------------------------------------------------------------------------------- /exes/espefuse.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/exes/espefuse.exe -------------------------------------------------------------------------------- /exes/espefuse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, 4 | # Espressif Systems (Shanghai) CO LTD, other contributors as noted. 5 | # 6 | # SPDX-License-Identifier: GPL-2.0-or-later 7 | 8 | # This executable script is a thin wrapper around the main functionality 9 | # in the espefuse Python package 10 | 11 | # When updating this script, please also update esptool.py and espsecure.py 12 | 13 | import contextlib 14 | import os 15 | import sys 16 | 17 | if os.name != "nt": 18 | # Linux/macOS: remove current script directory to avoid importing this file 19 | # as a module; we want to import the installed espefuse module instead 20 | with contextlib.suppress(ValueError): 21 | if sys.path[0].endswith("/bin"): 22 | sys.path.pop(0) 23 | sys.path.remove(os.path.dirname(sys.executable)) 24 | 25 | # Linux/macOS: delete imported module entry to force Python to load 26 | # the module from scratch; this enables importing espefuse module in 27 | # other Python scripts 28 | with contextlib.suppress(KeyError): 29 | del sys.modules["espefuse"] 30 | 31 | import espefuse 32 | 33 | if __name__ == "__main__": 34 | espefuse._main() 35 | -------------------------------------------------------------------------------- /exes/espefuse.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | 3 | block_cipher = None 4 | 5 | 6 | a = Analysis(['espefuse.py'], 7 | pathex=['C:\\Users\\apetrucci.GG.000\\Source\\Repos\\esp_tools_gui\\ESPToolsGUI\\exes'], 8 | binaries=[], 9 | datas=[], 10 | hiddenimports=[], 11 | hookspath=[], 12 | runtime_hooks=[], 13 | excludes=[], 14 | win_no_prefer_redirects=False, 15 | win_private_assemblies=False, 16 | cipher=block_cipher, 17 | noarchive=False) 18 | pyz = PYZ(a.pure, a.zipped_data, 19 | cipher=block_cipher) 20 | exe = EXE(pyz, 21 | a.scripts, 22 | a.binaries, 23 | a.zipfiles, 24 | a.datas, 25 | [], 26 | name='espefuse', 27 | debug=False, 28 | bootloader_ignore_signals=False, 29 | strip=False, 30 | upx=True, 31 | upx_exclude=[], 32 | runtime_tmpdir=None, 33 | console=True ) 34 | -------------------------------------------------------------------------------- /exes/espsecure.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/exes/espsecure.exe -------------------------------------------------------------------------------- /exes/espsecure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, 4 | # Espressif Systems (Shanghai) CO LTD, other contributors as noted. 5 | # 6 | # SPDX-License-Identifier: GPL-2.0-or-later 7 | 8 | # This executable script is a thin wrapper around the main functionality 9 | # in the espsecure Python package 10 | 11 | # When updating this script, please also update esptool.py and espefuse.py 12 | 13 | import contextlib 14 | import os 15 | import sys 16 | 17 | if os.name != "nt": 18 | # Linux/macOS: remove current script directory to avoid importing this file 19 | # as a module; we want to import the installed espsecure module instead 20 | with contextlib.suppress(ValueError): 21 | if sys.path[0].endswith("/bin"): 22 | sys.path.pop(0) 23 | sys.path.remove(os.path.dirname(sys.executable)) 24 | 25 | # Linux/macOS: delete imported module entry to force Python to load 26 | # the module from scratch; this enables importing espsecure module in 27 | # other Python scripts 28 | with contextlib.suppress(KeyError): 29 | del sys.modules["espsecure"] 30 | 31 | import espsecure 32 | 33 | if __name__ == "__main__": 34 | espsecure._main() 35 | -------------------------------------------------------------------------------- /exes/esptool.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/exes/esptool.exe -------------------------------------------------------------------------------- /exes/esptool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, 4 | # Espressif Systems (Shanghai) CO LTD, other contributors as noted. 5 | # 6 | # SPDX-License-Identifier: GPL-2.0-or-later 7 | 8 | # This executable script is a thin wrapper around the main functionality 9 | # in the esptool Python package 10 | 11 | # When updating this script, please also update espefuse.py and espsecure.py 12 | 13 | import contextlib 14 | import os 15 | import sys 16 | 17 | if os.name != "nt": 18 | # Linux/macOS: remove current script directory to avoid importing this file 19 | # as a module; we want to import the installed esptool module instead 20 | with contextlib.suppress(ValueError): 21 | if sys.path[0].endswith("/bin"): 22 | sys.path.pop(0) 23 | sys.path.remove(os.path.dirname(sys.executable)) 24 | 25 | # Linux/macOS: delete imported module entry to force Python to load 26 | # the module from scratch; this enables importing esptool module in 27 | # other Python scripts 28 | with contextlib.suppress(KeyError): 29 | del sys.modules["esptool"] 30 | 31 | import esptool 32 | 33 | if __name__ == "__main__": 34 | esptool._main() 35 | -------------------------------------------------------------------------------- /exes/gen_esp32part.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/exes/gen_esp32part.exe -------------------------------------------------------------------------------- /exes/gen_esp32part.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ESP32 partition table generation tool 4 | # 5 | # Converts partition tables to/from CSV and binary formats. 6 | # 7 | # See https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/partition-tables.html 8 | # for explanation of partition table structure and uses. 9 | # 10 | # SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD 11 | # SPDX-License-Identifier: Apache-2.0 12 | 13 | from __future__ import division, print_function, unicode_literals 14 | 15 | import argparse 16 | import binascii 17 | import errno 18 | import hashlib 19 | import os 20 | import re 21 | import struct 22 | import sys 23 | 24 | MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature 25 | MD5_PARTITION_BEGIN = b'\xEB\xEB' + b'\xFF' * 14 # The first 2 bytes are like magic numbers for MD5 sum 26 | PARTITION_TABLE_SIZE = 0x1000 # Size of partition table 27 | 28 | MIN_PARTITION_SUBTYPE_APP_OTA = 0x10 29 | NUM_PARTITION_SUBTYPE_APP_OTA = 16 30 | 31 | __version__ = '1.2' 32 | 33 | APP_TYPE = 0x00 34 | DATA_TYPE = 0x01 35 | 36 | TYPES = { 37 | 'app': APP_TYPE, 38 | 'data': DATA_TYPE, 39 | } 40 | 41 | 42 | def get_ptype_as_int(ptype): 43 | """ Convert a string which might be numeric or the name of a partition type to an integer """ 44 | try: 45 | return TYPES[ptype] 46 | except KeyError: 47 | try: 48 | return int(ptype, 0) 49 | except TypeError: 50 | return ptype 51 | 52 | 53 | # Keep this map in sync with esp_partition_subtype_t enum in esp_partition.h 54 | SUBTYPES = { 55 | APP_TYPE: { 56 | 'factory': 0x00, 57 | 'test': 0x20, 58 | }, 59 | DATA_TYPE: { 60 | 'ota': 0x00, 61 | 'phy': 0x01, 62 | 'nvs': 0x02, 63 | 'coredump': 0x03, 64 | 'nvs_keys': 0x04, 65 | 'efuse': 0x05, 66 | 'undefined': 0x06, 67 | 'esphttpd': 0x80, 68 | 'fat': 0x81, 69 | 'spiffs': 0x82, 70 | }, 71 | } 72 | 73 | 74 | def get_subtype_as_int(ptype, subtype): 75 | """ Convert a string which might be numeric or the name of a partition subtype to an integer """ 76 | try: 77 | return SUBTYPES[get_ptype_as_int(ptype)][subtype] 78 | except KeyError: 79 | try: 80 | return int(subtype, 0) 81 | except TypeError: 82 | return subtype 83 | 84 | 85 | ALIGNMENT = { 86 | APP_TYPE: 0x10000, 87 | DATA_TYPE: 0x1000, 88 | } 89 | 90 | 91 | def get_alignment_for_type(ptype): 92 | return ALIGNMENT.get(ptype, ALIGNMENT[DATA_TYPE]) 93 | 94 | 95 | def get_partition_type(ptype): 96 | if ptype == 'app': 97 | return APP_TYPE 98 | if ptype == 'data': 99 | return DATA_TYPE 100 | raise InputError('Invalid partition type') 101 | 102 | 103 | def add_extra_subtypes(csv): 104 | for line_no in csv: 105 | try: 106 | fields = [line.strip() for line in line_no.split(',')] 107 | for subtype, subtype_values in SUBTYPES.items(): 108 | if (int(fields[2], 16) in subtype_values.values() and subtype == get_partition_type(fields[0])): 109 | raise ValueError('Found duplicate value in partition subtype') 110 | SUBTYPES[TYPES[fields[0]]][fields[1]] = int(fields[2], 16) 111 | except InputError as err: 112 | raise InputError('Error parsing custom subtypes: %s' % err) 113 | 114 | 115 | quiet = False 116 | md5sum = True 117 | secure = False 118 | offset_part_table = 0 119 | 120 | 121 | def status(msg): 122 | """ Print status message to stderr """ 123 | if not quiet: 124 | critical(msg) 125 | 126 | 127 | def critical(msg): 128 | """ Print critical message to stderr """ 129 | sys.stderr.write(msg) 130 | sys.stderr.write('\n') 131 | 132 | 133 | class PartitionTable(list): 134 | def __init__(self): 135 | super(PartitionTable, self).__init__(self) 136 | 137 | @classmethod 138 | def from_file(cls, f): 139 | data = f.read() 140 | data_is_binary = data[0:2] == PartitionDefinition.MAGIC_BYTES 141 | if data_is_binary: 142 | status('Parsing binary partition input...') 143 | return cls.from_binary(data), True 144 | 145 | data = data.decode() 146 | status('Parsing CSV input...') 147 | return cls.from_csv(data), False 148 | 149 | @classmethod 150 | def from_csv(cls, csv_contents): 151 | res = PartitionTable() 152 | lines = csv_contents.splitlines() 153 | 154 | def expand_vars(f): 155 | f = os.path.expandvars(f) 156 | m = re.match(r'(? 1) 233 | 234 | # print sorted duplicate partitions by name 235 | if len(duplicates) != 0: 236 | critical('A list of partitions that have the same name:') 237 | for p in sorted(self, key=lambda x:x.name): 238 | if len(duplicates.intersection([p.name])) != 0: 239 | critical('%s' % (p.to_csv())) 240 | raise InputError('Partition names must be unique') 241 | 242 | # check for overlaps 243 | last = None 244 | for p in sorted(self, key=lambda x:x.offset): 245 | if p.offset < offset_part_table + PARTITION_TABLE_SIZE: 246 | raise InputError('Partition offset 0x%x is below 0x%x' % (p.offset, offset_part_table + PARTITION_TABLE_SIZE)) 247 | if last is not None and p.offset < last.offset + last.size: 248 | raise InputError('Partition at 0x%x overlaps 0x%x-0x%x' % (p.offset, last.offset, last.offset + last.size - 1)) 249 | last = p 250 | 251 | # check that otadata should be unique 252 | otadata_duplicates = [p for p in self if p.type == TYPES['data'] and p.subtype == SUBTYPES[DATA_TYPE]['ota']] 253 | if len(otadata_duplicates) > 1: 254 | for p in otadata_duplicates: 255 | critical('%s' % (p.to_csv())) 256 | raise InputError('Found multiple otadata partitions. Only one partition can be defined with type="data"(1) and subtype="ota"(0).') 257 | 258 | if len(otadata_duplicates) == 1 and otadata_duplicates[0].size != 0x2000: 259 | p = otadata_duplicates[0] 260 | critical('%s' % (p.to_csv())) 261 | raise InputError('otadata partition must have size = 0x2000') 262 | 263 | def flash_size(self): 264 | """ Return the size that partitions will occupy in flash 265 | (ie the offset the last partition ends at) 266 | """ 267 | try: 268 | last = sorted(self, reverse=True)[0] 269 | except IndexError: 270 | return 0 # empty table! 271 | return last.offset + last.size 272 | 273 | def verify_size_fits(self, flash_size_bytes: int) -> None: 274 | """ Check that partition table fits into the given flash size. 275 | Raises InputError otherwise. 276 | """ 277 | table_size = self.flash_size() 278 | if flash_size_bytes < table_size: 279 | mb = 1024 * 1024 280 | raise InputError('Partitions tables occupies %.1fMB of flash (%d bytes) which does not fit in configured ' 281 | "flash size %dMB. Change the flash size in menuconfig under the 'Serial Flasher Config' menu." % 282 | (table_size / mb, table_size, flash_size_bytes / mb)) 283 | 284 | @classmethod 285 | def from_binary(cls, b): 286 | md5 = hashlib.md5() 287 | result = cls() 288 | for o in range(0,len(b),32): 289 | data = b[o:o + 32] 290 | if len(data) != 32: 291 | raise InputError('Partition table length must be a multiple of 32 bytes') 292 | if data == b'\xFF' * 32: 293 | return result # got end marker 294 | if md5sum and data[:2] == MD5_PARTITION_BEGIN[:2]: # check only the magic number part 295 | if data[16:] == md5.digest(): 296 | continue # the next iteration will check for the end marker 297 | else: 298 | raise InputError("MD5 checksums don't match! (computed: 0x%s, parsed: 0x%s)" % (md5.hexdigest(), binascii.hexlify(data[16:]))) 299 | else: 300 | md5.update(data) 301 | result.append(PartitionDefinition.from_binary(data)) 302 | raise InputError('Partition table is missing an end-of-table marker') 303 | 304 | def to_binary(self): 305 | result = b''.join(e.to_binary() for e in self) 306 | if md5sum: 307 | result += MD5_PARTITION_BEGIN + hashlib.md5(result).digest() 308 | if len(result) >= MAX_PARTITION_LENGTH: 309 | raise InputError('Binary partition table length (%d) longer than max' % len(result)) 310 | result += b'\xFF' * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing 311 | return result 312 | 313 | def to_csv(self, simple_formatting=False): 314 | rows = ['# ESP-IDF Partition Table', 315 | '# Name, Type, SubType, Offset, Size, Flags'] 316 | rows += [x.to_csv(simple_formatting) for x in self] 317 | return '\n'.join(rows) + '\n' 318 | 319 | 320 | class PartitionDefinition(object): 321 | MAGIC_BYTES = b'\xAA\x50' 322 | 323 | # dictionary maps flag name (as used in CSV flags list, property name) 324 | # to bit set in flags words in binary format 325 | FLAGS = { 326 | 'encrypted': 0 327 | } 328 | 329 | # add subtypes for the 16 OTA slot values ("ota_XX, etc.") 330 | for ota_slot in range(NUM_PARTITION_SUBTYPE_APP_OTA): 331 | SUBTYPES[TYPES['app']]['ota_%d' % ota_slot] = MIN_PARTITION_SUBTYPE_APP_OTA + ota_slot 332 | 333 | def __init__(self): 334 | self.name = '' 335 | self.type = None 336 | self.subtype = None 337 | self.offset = None 338 | self.size = None 339 | self.encrypted = False 340 | 341 | @classmethod 342 | def from_csv(cls, line, line_no): 343 | """ Parse a line from the CSV """ 344 | line_w_defaults = line + ',,,,' # lazy way to support default fields 345 | fields = [f.strip() for f in line_w_defaults.split(',')] 346 | 347 | res = PartitionDefinition() 348 | res.line_no = line_no 349 | res.name = fields[0] 350 | res.type = res.parse_type(fields[1]) 351 | res.subtype = res.parse_subtype(fields[2]) 352 | res.offset = res.parse_address(fields[3]) 353 | res.size = res.parse_address(fields[4]) 354 | if res.size is None: 355 | raise InputError("Size field can't be empty") 356 | 357 | flags = fields[5].split(':') 358 | for flag in flags: 359 | if flag in cls.FLAGS: 360 | setattr(res, flag, True) 361 | elif len(flag) > 0: 362 | raise InputError("CSV flag column contains unknown flag '%s'" % (flag)) 363 | 364 | return res 365 | 366 | def __eq__(self, other): 367 | return self.name == other.name and self.type == other.type \ 368 | and self.subtype == other.subtype and self.offset == other.offset \ 369 | and self.size == other.size 370 | 371 | def __repr__(self): 372 | def maybe_hex(x): 373 | return '0x%x' % x if x is not None else 'None' 374 | return "PartitionDefinition('%s', 0x%x, 0x%x, %s, %s)" % (self.name, self.type, self.subtype or 0, 375 | maybe_hex(self.offset), maybe_hex(self.size)) 376 | 377 | def __str__(self): 378 | return "Part '%s' %d/%d @ 0x%x size 0x%x" % (self.name, self.type, self.subtype, self.offset or -1, self.size or -1) 379 | 380 | def __cmp__(self, other): 381 | return self.offset - other.offset 382 | 383 | def __lt__(self, other): 384 | return self.offset < other.offset 385 | 386 | def __gt__(self, other): 387 | return self.offset > other.offset 388 | 389 | def __le__(self, other): 390 | return self.offset <= other.offset 391 | 392 | def __ge__(self, other): 393 | return self.offset >= other.offset 394 | 395 | def parse_type(self, strval): 396 | if strval == '': 397 | raise InputError("Field 'type' can't be left empty.") 398 | return parse_int(strval, TYPES) 399 | 400 | def parse_subtype(self, strval): 401 | if strval == '': 402 | if self.type == TYPES['app']: 403 | raise InputError('App partition cannot have an empty subtype') 404 | return SUBTYPES[DATA_TYPE]['undefined'] 405 | return parse_int(strval, SUBTYPES.get(self.type, {})) 406 | 407 | def parse_address(self, strval): 408 | if strval == '': 409 | return None # PartitionTable will fill in default 410 | return parse_int(strval) 411 | 412 | def verify(self): 413 | if self.type is None: 414 | raise ValidationError(self, 'Type field is not set') 415 | if self.subtype is None: 416 | raise ValidationError(self, 'Subtype field is not set') 417 | if self.offset is None: 418 | raise ValidationError(self, 'Offset field is not set') 419 | align = get_alignment_for_type(self.type) 420 | if self.offset % align: 421 | raise ValidationError(self, 'Offset 0x%x is not aligned to 0x%x' % (self.offset, align)) 422 | if self.size % align and secure and self.type == APP_TYPE: 423 | raise ValidationError(self, 'Size 0x%x is not aligned to 0x%x' % (self.size, align)) 424 | if self.size is None: 425 | raise ValidationError(self, 'Size field is not set') 426 | 427 | if self.name in TYPES and TYPES.get(self.name, '') != self.type: 428 | critical("WARNING: Partition has name '%s' which is a partition type, but does not match this partition's " 429 | 'type (0x%x). Mistake in partition table?' % (self.name, self.type)) 430 | all_subtype_names = [] 431 | for names in (t.keys() for t in SUBTYPES.values()): 432 | all_subtype_names += names 433 | if self.name in all_subtype_names and SUBTYPES.get(self.type, {}).get(self.name, '') != self.subtype: 434 | critical("WARNING: Partition has name '%s' which is a partition subtype, but this partition has " 435 | 'non-matching type 0x%x and subtype 0x%x. Mistake in partition table?' % (self.name, self.type, self.subtype)) 436 | 437 | STRUCT_FORMAT = b'<2sBBLL16sL' 438 | 439 | @classmethod 440 | def from_binary(cls, b): 441 | if len(b) != 32: 442 | raise InputError('Partition definition length must be exactly 32 bytes. Got %d bytes.' % len(b)) 443 | res = cls() 444 | (magic, res.type, res.subtype, res.offset, 445 | res.size, res.name, flags) = struct.unpack(cls.STRUCT_FORMAT, b) 446 | if b'\x00' in res.name: # strip null byte padding from name string 447 | res.name = res.name[:res.name.index(b'\x00')] 448 | res.name = res.name.decode() 449 | if magic != cls.MAGIC_BYTES: 450 | raise InputError('Invalid magic bytes (%r) for partition definition' % magic) 451 | for flag,bit in cls.FLAGS.items(): 452 | if flags & (1 << bit): 453 | setattr(res, flag, True) 454 | flags &= ~(1 << bit) 455 | if flags != 0: 456 | critical('WARNING: Partition definition had unknown flag(s) 0x%08x. Newer binary format?' % flags) 457 | return res 458 | 459 | def get_flags_list(self): 460 | return [flag for flag in self.FLAGS.keys() if getattr(self, flag)] 461 | 462 | def to_binary(self): 463 | flags = sum((1 << self.FLAGS[flag]) for flag in self.get_flags_list()) 464 | return struct.pack(self.STRUCT_FORMAT, 465 | self.MAGIC_BYTES, 466 | self.type, self.subtype, 467 | self.offset, self.size, 468 | self.name.encode(), 469 | flags) 470 | 471 | def to_csv(self, simple_formatting=False): 472 | def addr_format(a, include_sizes): 473 | if not simple_formatting and include_sizes: 474 | for (val, suffix) in [(0x100000, 'M'), (0x400, 'K')]: 475 | if a % val == 0: 476 | return '%d%s' % (a // val, suffix) 477 | return '0x%x' % a 478 | 479 | def lookup_keyword(t, keywords): 480 | for k,v in keywords.items(): 481 | if simple_formatting is False and t == v: 482 | return k 483 | return '%d' % t 484 | 485 | def generate_text_flags(): 486 | """ colon-delimited list of flags """ 487 | return ':'.join(self.get_flags_list()) 488 | 489 | return ','.join([self.name, 490 | lookup_keyword(self.type, TYPES), 491 | lookup_keyword(self.subtype, SUBTYPES.get(self.type, {})), 492 | addr_format(self.offset, False), 493 | addr_format(self.size, True), 494 | generate_text_flags()]) 495 | 496 | 497 | def parse_int(v, keywords={}): 498 | """Generic parser for integer fields - int(x,0) with provision for 499 | k/m/K/M suffixes and 'keyword' value lookup. 500 | """ 501 | try: 502 | for letter, multiplier in [('k', 1024), ('m', 1024 * 1024)]: 503 | if v.lower().endswith(letter): 504 | return parse_int(v[:-1], keywords) * multiplier 505 | return int(v, 0) 506 | except ValueError: 507 | if len(keywords) == 0: 508 | raise InputError('Invalid field value %s' % v) 509 | try: 510 | return keywords[v.lower()] 511 | except KeyError: 512 | raise InputError("Value '%s' is not valid. Known keywords: %s" % (v, ', '.join(keywords))) 513 | 514 | 515 | def main(): 516 | global quiet 517 | global md5sum 518 | global offset_part_table 519 | global secure 520 | parser = argparse.ArgumentParser(description='ESP32 partition table utility') 521 | 522 | parser.add_argument('--flash-size', help='Optional flash size limit, checks partition table fits in flash', 523 | nargs='?', choices=['1MB', '2MB', '4MB', '8MB', '16MB', '32MB', '64MB', '128MB']) 524 | parser.add_argument('--disable-md5sum', help='Disable md5 checksum for the partition table', default=False, action='store_true') 525 | parser.add_argument('--no-verify', help="Don't verify partition table fields", action='store_true') 526 | parser.add_argument('--verify', '-v', help='Verify partition table fields (deprecated, this behaviour is ' 527 | 'enabled by default and this flag does nothing.', action='store_true') 528 | parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') 529 | parser.add_argument('--offset', '-o', help='Set offset partition table', default='0x8000') 530 | parser.add_argument('--secure', help='Require app partitions to be suitable for secure boot', action='store_true') 531 | parser.add_argument('--extra-partition-subtypes', help='Extra partition subtype entries', nargs='*') 532 | parser.add_argument('input', help='Path to CSV or binary file to parse.', type=argparse.FileType('rb')) 533 | parser.add_argument('output', help='Path to output converted binary or CSV file. Will use stdout if omitted.', 534 | nargs='?', default='-') 535 | 536 | args = parser.parse_args() 537 | 538 | quiet = args.quiet 539 | md5sum = not args.disable_md5sum 540 | secure = args.secure 541 | offset_part_table = int(args.offset, 0) 542 | if args.extra_partition_subtypes: 543 | add_extra_subtypes(args.extra_partition_subtypes) 544 | 545 | table, input_is_binary = PartitionTable.from_file(args.input) 546 | 547 | if not args.no_verify: 548 | status('Verifying table...') 549 | table.verify() 550 | 551 | if args.flash_size: 552 | size_mb = int(args.flash_size.replace('MB', '')) 553 | table.verify_size_fits(size_mb * 1024 * 1024) 554 | 555 | # Make sure that the output directory is created 556 | output_dir = os.path.abspath(os.path.dirname(args.output)) 557 | 558 | if not os.path.exists(output_dir): 559 | try: 560 | os.makedirs(output_dir) 561 | except OSError as exc: 562 | if exc.errno != errno.EEXIST: 563 | raise 564 | 565 | if input_is_binary: 566 | output = table.to_csv() 567 | with sys.stdout if args.output == '-' else open(args.output, 'w') as f: 568 | f.write(output) 569 | else: 570 | output = table.to_binary() 571 | try: 572 | stdout_binary = sys.stdout.buffer # Python 3 573 | except AttributeError: 574 | stdout_binary = sys.stdout 575 | with stdout_binary if args.output == '-' else open(args.output, 'wb') as f: 576 | f.write(output) 577 | 578 | 579 | class InputError(RuntimeError): 580 | def __init__(self, e): 581 | super(InputError, self).__init__(e) 582 | 583 | 584 | class ValidationError(InputError): 585 | def __init__(self, partition, message): 586 | super(ValidationError, self).__init__( 587 | 'Partition %s invalid: %s' % (partition.name, message)) 588 | 589 | 590 | if __name__ == '__main__': 591 | try: 592 | main() 593 | except InputError as e: 594 | print(e, file=sys.stderr) 595 | sys.exit(2) -------------------------------------------------------------------------------- /exes/parttool.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/exes/parttool.exe -------------------------------------------------------------------------------- /exes/parttool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # parttool is used to perform partition level operations - reading, 4 | # writing, erasing and getting info about the partition. 5 | # 6 | # SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD 7 | # SPDX-License-Identifier: Apache-2.0 8 | from __future__ import division, print_function 9 | 10 | import argparse 11 | import os 12 | import re 13 | import subprocess 14 | import sys 15 | import tempfile 16 | 17 | import gen_esp32part as gen 18 | 19 | __version__ = '2.0' 20 | 21 | COMPONENTS_PATH = os.path.expandvars(os.path.join('$IDF_PATH', 'components')) 22 | ESPTOOL_PY = os.path.join(COMPONENTS_PATH, 'esptool_py', 'esptool', 'esptool.py') 23 | 24 | PARTITION_TABLE_OFFSET = 0x8000 25 | 26 | 27 | quiet = False 28 | 29 | 30 | def status(msg): 31 | if not quiet: 32 | print(msg) 33 | 34 | 35 | class _PartitionId(): 36 | 37 | def __init__(self, name=None, p_type=None, subtype=None, part_list=None): 38 | self.name = name 39 | self.type = p_type 40 | self.subtype = subtype 41 | self.part_list = part_list 42 | 43 | 44 | class PartitionName(_PartitionId): 45 | 46 | def __init__(self, name): 47 | _PartitionId.__init__(self, name=name) 48 | 49 | 50 | class PartitionType(_PartitionId): 51 | 52 | def __init__(self, p_type, subtype, part_list=None): 53 | _PartitionId.__init__(self, p_type=p_type, subtype=subtype, part_list=part_list) 54 | 55 | 56 | PARTITION_BOOT_DEFAULT = _PartitionId() 57 | 58 | 59 | class ParttoolTarget(): 60 | 61 | def __init__(self, port=None, baud=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None, 62 | esptool_args=[], esptool_write_args=[], esptool_read_args=[], esptool_erase_args=[]): 63 | self.port = port 64 | self.baud = baud 65 | 66 | gen.offset_part_table = partition_table_offset 67 | 68 | def parse_esptool_args(esptool_args): 69 | results = list() 70 | for arg in esptool_args: 71 | pattern = re.compile(r'(.+)=(.+)') 72 | result = pattern.match(arg) 73 | try: 74 | key = result.group(1) 75 | value = result.group(2) 76 | results.extend(['--' + key, value]) 77 | except AttributeError: 78 | results.extend(['--' + arg]) 79 | return results 80 | 81 | self.esptool_args = parse_esptool_args(esptool_args) 82 | self.esptool_write_args = parse_esptool_args(esptool_write_args) 83 | self.esptool_read_args = parse_esptool_args(esptool_read_args) 84 | self.esptool_erase_args = parse_esptool_args(esptool_erase_args) 85 | 86 | if partition_table_file: 87 | partition_table = None 88 | with open(partition_table_file, 'rb') as f: 89 | input_is_binary = (f.read(2) == gen.PartitionDefinition.MAGIC_BYTES) 90 | f.seek(0) 91 | if input_is_binary: 92 | partition_table = gen.PartitionTable.from_binary(f.read()) 93 | 94 | if partition_table is None: 95 | with open(partition_table_file, 'r') as f: 96 | f.seek(0) 97 | partition_table = gen.PartitionTable.from_csv(f.read()) 98 | else: 99 | temp_file = tempfile.NamedTemporaryFile(delete=False) 100 | temp_file.close() 101 | 102 | try: 103 | self._call_esptool(['read_flash', str(partition_table_offset), str(gen.MAX_PARTITION_LENGTH), temp_file.name]) 104 | with open(temp_file.name, 'rb') as f: 105 | partition_table = gen.PartitionTable.from_binary(f.read()) 106 | finally: 107 | os.unlink(temp_file.name) 108 | 109 | self.partition_table = partition_table 110 | 111 | # set `out` to None to redirect the output to the STDOUT 112 | # otherwise set `out` to file descriptor 113 | # beware that the method does not close the file descriptor 114 | def _call_esptool(self, args, out=None): 115 | esptool_args = [sys.executable, ESPTOOL_PY] + self.esptool_args 116 | 117 | if self.port: 118 | esptool_args += ['--port', self.port] 119 | 120 | if self.baud: 121 | esptool_args += ['--baud', str(self.baud)] 122 | 123 | esptool_args += args 124 | 125 | print('Running %s...' % (' '.join(esptool_args))) 126 | try: 127 | subprocess.check_call(esptool_args, stdout=out, stderr=subprocess.STDOUT) 128 | except subprocess.CalledProcessError as e: 129 | print('An exception: **', str(e), '** occurred in _call_esptool.', file=out) 130 | raise e 131 | 132 | def get_partition_info(self, partition_id): 133 | partition = None 134 | 135 | if partition_id.name: 136 | partition = self.partition_table.find_by_name(partition_id.name) 137 | elif partition_id.type and partition_id.subtype: 138 | partition = list(self.partition_table.find_by_type(partition_id.type, partition_id.subtype)) 139 | if not partition_id.part_list: 140 | partition = partition[0] 141 | else: # default boot partition 142 | search = ['factory'] + ['ota_{}'.format(d) for d in range(16)] 143 | for subtype in search: 144 | partition = next(self.partition_table.find_by_type('app', subtype), None) 145 | if partition: 146 | break 147 | 148 | if not partition: 149 | raise Exception('Partition does not exist') 150 | 151 | return partition 152 | 153 | def erase_partition(self, partition_id): 154 | partition = self.get_partition_info(partition_id) 155 | self._call_esptool(['erase_region', str(partition.offset), str(partition.size)] + self.esptool_erase_args) 156 | 157 | def read_partition(self, partition_id, output): 158 | partition = self.get_partition_info(partition_id) 159 | self._call_esptool(['read_flash', str(partition.offset), str(partition.size), output] + self.esptool_read_args) 160 | 161 | def write_partition(self, partition_id, input): 162 | self.erase_partition(partition_id) 163 | 164 | partition = self.get_partition_info(partition_id) 165 | 166 | with open(input, 'rb') as input_file: 167 | content_len = len(input_file.read()) 168 | 169 | if content_len > partition.size: 170 | raise Exception('Input file size exceeds partition size') 171 | 172 | self._call_esptool(['write_flash', str(partition.offset), input] + self.esptool_write_args) 173 | 174 | 175 | def _write_partition(target, partition_id, input): 176 | target.write_partition(partition_id, input) 177 | partition = target.get_partition_info(partition_id) 178 | status("Written contents of file '{}' at offset 0x{:x}".format(input, partition.offset)) 179 | 180 | 181 | def _read_partition(target, partition_id, output): 182 | target.read_partition(partition_id, output) 183 | partition = target.get_partition_info(partition_id) 184 | status("Read partition '{}' contents from device at offset 0x{:x} to file '{}'" 185 | .format(partition.name, partition.offset, output)) 186 | 187 | 188 | def _erase_partition(target, partition_id): 189 | target.erase_partition(partition_id) 190 | partition = target.get_partition_info(partition_id) 191 | status("Erased partition '{}' at offset 0x{:x}".format(partition.name, partition.offset)) 192 | 193 | 194 | def _get_partition_info(target, partition_id, info): 195 | try: 196 | partitions = target.get_partition_info(partition_id) 197 | if not isinstance(partitions, list): 198 | partitions = [partitions] 199 | except Exception: 200 | return 201 | 202 | infos = [] 203 | 204 | try: 205 | for p in partitions: 206 | info_dict = { 207 | 'name': '{}'.format(p.name), 208 | 'type': '{}'.format(p.type), 209 | 'subtype': '{}'.format(p.subtype), 210 | 'offset': '0x{:x}'.format(p.offset), 211 | 'size': '0x{:x}'.format(p.size), 212 | 'encrypted': '{}'.format(p.encrypted) 213 | } 214 | for i in info: 215 | infos += [info_dict[i]] 216 | except KeyError: 217 | raise RuntimeError('Request for unknown partition info {}'.format(i)) 218 | 219 | print(' '.join(infos)) 220 | 221 | 222 | def main(): 223 | global quiet 224 | 225 | parser = argparse.ArgumentParser('ESP-IDF Partitions Tool') 226 | 227 | parser.add_argument('--quiet', '-q', help='suppress stderr messages', action='store_true') 228 | parser.add_argument('--esptool-args', help='additional main arguments for esptool', nargs='+') 229 | parser.add_argument('--esptool-write-args', help='additional subcommand arguments when writing to flash', nargs='+') 230 | parser.add_argument('--esptool-read-args', help='additional subcommand arguments when reading flash', nargs='+') 231 | parser.add_argument('--esptool-erase-args', help='additional subcommand arguments when erasing regions of flash', nargs='+') 232 | 233 | # By default the device attached to the specified port is queried for the partition table. If a partition table file 234 | # is specified, that is used instead. 235 | parser.add_argument('--port', '-p', help='port where the target device of the command is connected to; the partition table is sourced from this device \ 236 | when the partition table file is not defined') 237 | parser.add_argument('--baud', '-b', help='baudrate to use', type=int) 238 | 239 | parser.add_argument('--partition-table-offset', '-o', help='offset to read the partition table from', type=str) 240 | parser.add_argument('--partition-table-file', '-f', help='file (CSV/binary) to read the partition table from; \ 241 | overrides device attached to specified port as the partition table source when defined') 242 | 243 | partition_selection_parser = argparse.ArgumentParser(add_help=False) 244 | 245 | # Specify what partition to perform the operation on. This can either be specified using the 246 | # partition name or the first partition that matches the specified type/subtype 247 | partition_selection_args = partition_selection_parser.add_mutually_exclusive_group() 248 | 249 | partition_selection_args.add_argument('--partition-name', '-n', help='name of the partition') 250 | partition_selection_args.add_argument('--partition-type', '-t', help='type of the partition') 251 | partition_selection_args.add_argument('--partition-boot-default', '-d', help='select the default boot partition \ 252 | using the same fallback logic as the IDF bootloader', action='store_true') 253 | 254 | partition_selection_parser.add_argument('--partition-subtype', '-s', help='subtype of the partition') 255 | partition_selection_parser.add_argument('--extra-partition-subtypes', help='Extra partition subtype entries', nargs='*') 256 | 257 | subparsers = parser.add_subparsers(dest='operation', help='run parttool -h for additional help') 258 | 259 | # Specify the supported operations 260 | read_part_subparser = subparsers.add_parser('read_partition', help='read partition from device and dump contents into a file', 261 | parents=[partition_selection_parser]) 262 | read_part_subparser.add_argument('--output', help='file to dump the read partition contents to') 263 | 264 | write_part_subparser = subparsers.add_parser('write_partition', help='write contents of a binary file to partition on device', 265 | parents=[partition_selection_parser]) 266 | write_part_subparser.add_argument('--input', help='file whose contents are to be written to the partition offset') 267 | 268 | subparsers.add_parser('erase_partition', help='erase the contents of a partition on the device', parents=[partition_selection_parser]) 269 | 270 | print_partition_info_subparser = subparsers.add_parser('get_partition_info', help='get partition information', parents=[partition_selection_parser]) 271 | print_partition_info_subparser.add_argument('--info', help='type of partition information to get', 272 | choices=['name', 'type', 'subtype', 'offset', 'size', 'encrypted'], default=['offset', 'size'], nargs='+') 273 | print_partition_info_subparser.add_argument('--part_list', help='Get a list of partitions suitable for a given type', action='store_true') 274 | 275 | args = parser.parse_args() 276 | quiet = args.quiet 277 | 278 | # No operation specified, display help and exit 279 | if args.operation is None: 280 | if not quiet: 281 | parser.print_help() 282 | sys.exit(1) 283 | 284 | # Prepare the partition to perform operation on 285 | if args.partition_name: 286 | partition_id = PartitionName(args.partition_name) 287 | elif args.partition_type: 288 | if not args.partition_subtype: 289 | raise RuntimeError('--partition-subtype should be defined when --partition-type is defined') 290 | partition_id = PartitionType(args.partition_type, args.partition_subtype, getattr(args, 'part_list', None)) 291 | elif args.partition_boot_default: 292 | partition_id = PARTITION_BOOT_DEFAULT 293 | else: 294 | raise RuntimeError('Partition to operate on should be defined using --partition-name OR \ 295 | partition-type,--partition-subtype OR partition-boot-default') 296 | 297 | # Prepare the device to perform operation on 298 | target_args = {} 299 | 300 | if args.port: 301 | target_args['port'] = args.port 302 | 303 | if args.baud: 304 | target_args['baud'] = args.baud 305 | 306 | if args.partition_table_file: 307 | target_args['partition_table_file'] = args.partition_table_file 308 | 309 | if args.partition_table_offset: 310 | target_args['partition_table_offset'] = int(args.partition_table_offset, 0) 311 | 312 | if args.esptool_args: 313 | target_args['esptool_args'] = args.esptool_args 314 | 315 | if args.esptool_write_args: 316 | target_args['esptool_write_args'] = args.esptool_write_args 317 | 318 | if args.esptool_read_args: 319 | target_args['esptool_read_args'] = args.esptool_read_args 320 | 321 | if args.esptool_erase_args: 322 | target_args['esptool_erase_args'] = args.esptool_erase_args 323 | 324 | if args.extra_partition_subtypes: 325 | gen.add_extra_subtypes(args.extra_partition_subtypes) 326 | 327 | target = ParttoolTarget(**target_args) 328 | 329 | # Create the operation table and execute the operation 330 | common_args = {'target':target, 'partition_id':partition_id} 331 | parttool_ops = { 332 | 'erase_partition':(_erase_partition, []), 333 | 'read_partition':(_read_partition, ['output']), 334 | 'write_partition':(_write_partition, ['input']), 335 | 'get_partition_info':(_get_partition_info, ['info']) 336 | } 337 | 338 | (op, op_args) = parttool_ops[args.operation] 339 | 340 | for op_arg in op_args: 341 | common_args.update({op_arg:vars(args)[op_arg]}) 342 | 343 | if quiet: 344 | # If exceptions occur, suppress and exit quietly 345 | try: 346 | op(**common_args) 347 | except Exception: 348 | sys.exit(2) 349 | else: 350 | try: 351 | op(**common_args) 352 | except gen.InputError as e: 353 | print(e, file=sys.stderr) 354 | sys.exit(2) 355 | 356 | 357 | if __name__ == '__main__': 358 | main() -------------------------------------------------------------------------------- /exes/python3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/exes/python3.dll -------------------------------------------------------------------------------- /exes/python310.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/exes/python310.dll -------------------------------------------------------------------------------- /exes/setup_esp.py: -------------------------------------------------------------------------------- 1 | from cx_Freeze import setup, Executable 2 | 3 | executables = [ 4 | Executable("gen_esp32part.py", base="Console", icon="ESP32py.ico"), 5 | Executable("parttool.py", base="Console", icon="ESP32py.ico") 6 | ] 7 | 8 | packages = ["idna", "encodings"] 9 | options = { 10 | 'build_exe': { 11 | 'packages':packages, 12 | 'include_files': ['ESP32py.ico'] 13 | }, 14 | } 15 | 16 | setup( 17 | name = "Esp32 Tool", 18 | options = options, 19 | version = "1.0", 20 | description = 'Espressif ESP32 tool', 21 | executables = executables 22 | ) -------------------------------------------------------------------------------- /images/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/add.png -------------------------------------------------------------------------------- /images/add32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/add32.png -------------------------------------------------------------------------------- /images/burn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/burn.png -------------------------------------------------------------------------------- /images/burn32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/burn32.png -------------------------------------------------------------------------------- /images/esp32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/esp32.jpg -------------------------------------------------------------------------------- /images/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/export.png -------------------------------------------------------------------------------- /images/export32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/export32.png -------------------------------------------------------------------------------- /images/import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/import.png -------------------------------------------------------------------------------- /images/import32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/import32.png -------------------------------------------------------------------------------- /images/kchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/kchart.png -------------------------------------------------------------------------------- /images/kde-folder-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/images/kde-folder-open.png -------------------------------------------------------------------------------- /src/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 115200 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/App.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace esp_tools_gui 8 | { 9 | class App 10 | { 11 | public static MainPage form; 12 | 13 | [STAThread] 14 | static void Main() { 15 | 16 | form = new MainPage(); 17 | form.ShowDialog(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Connecting.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace esp_tools_gui 2 | { 3 | partial class Connecting 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Connecting)); 33 | this.TitleLabel = new System.Windows.Forms.Label(); 34 | this.progressBar1 = new System.Windows.Forms.ProgressBar(); 35 | this.label2 = new System.Windows.Forms.Label(); 36 | this.ConnectionLabel = new System.Windows.Forms.Label(); 37 | this.timer1 = new System.Windows.Forms.Timer(this.components); 38 | this.linkLabel1 = new System.Windows.Forms.LinkLabel(); 39 | this.SuspendLayout(); 40 | // 41 | // TitleLabel 42 | // 43 | this.TitleLabel.AutoSize = true; 44 | this.TitleLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 21.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 45 | this.TitleLabel.Location = new System.Drawing.Point(145, 9); 46 | this.TitleLabel.Name = "TitleLabel"; 47 | this.TitleLabel.Size = new System.Drawing.Size(172, 33); 48 | this.TitleLabel.TabIndex = 0; 49 | this.TitleLabel.Text = "Connecting"; 50 | // 51 | // progressBar1 52 | // 53 | this.progressBar1.Location = new System.Drawing.Point(28, 54); 54 | this.progressBar1.Name = "progressBar1"; 55 | this.progressBar1.Size = new System.Drawing.Size(405, 14); 56 | this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Continuous; 57 | this.progressBar1.TabIndex = 1; 58 | this.progressBar1.Value = 100; 59 | // 60 | // label2 61 | // 62 | this.label2.AutoSize = true; 63 | this.label2.Location = new System.Drawing.Point(189, 82); 64 | this.label2.Name = "label2"; 65 | this.label2.Size = new System.Drawing.Size(85, 13); 66 | this.label2.TabIndex = 2; 67 | this.label2.Text = "Request started:"; 68 | // 69 | // ConnectionLabel 70 | // 71 | this.ConnectionLabel.Location = new System.Drawing.Point(28, 95); 72 | this.ConnectionLabel.Name = "ConnectionLabel"; 73 | this.ConnectionLabel.Size = new System.Drawing.Size(405, 37); 74 | this.ConnectionLabel.TabIndex = 3; 75 | this.ConnectionLabel.Text = "-"; 76 | this.ConnectionLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 77 | // 78 | // timer1 79 | // 80 | this.timer1.Interval = 30; 81 | this.timer1.Tick += new System.EventHandler(this.timer1_Tick); 82 | // 83 | // linkLabel1 84 | // 85 | this.linkLabel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 86 | this.linkLabel1.AutoSize = true; 87 | this.linkLabel1.LinkColor = System.Drawing.Color.Navy; 88 | this.linkLabel1.Location = new System.Drawing.Point(422, 4); 89 | this.linkLabel1.Name = "linkLabel1"; 90 | this.linkLabel1.Size = new System.Drawing.Size(32, 13); 91 | this.linkLabel1.TabIndex = 4; 92 | this.linkLabel1.TabStop = true; 93 | this.linkLabel1.Text = "Abort"; 94 | this.linkLabel1.Visible = false; 95 | this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); 96 | // 97 | // Connecting 98 | // 99 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 100 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 101 | this.BackColor = System.Drawing.SystemColors.InactiveCaption; 102 | this.ClientSize = new System.Drawing.Size(458, 141); 103 | this.Controls.Add(this.linkLabel1); 104 | this.Controls.Add(this.ConnectionLabel); 105 | this.Controls.Add(this.label2); 106 | this.Controls.Add(this.progressBar1); 107 | this.Controls.Add(this.TitleLabel); 108 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; 109 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 110 | this.Name = "Connecting"; 111 | this.Opacity = 0.9D; 112 | this.ShowIcon = false; 113 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 114 | this.Text = "Request"; 115 | this.TopMost = true; 116 | this.Load += new System.EventHandler(this.Connecting_Load); 117 | this.ResumeLayout(false); 118 | this.PerformLayout(); 119 | 120 | } 121 | 122 | #endregion 123 | 124 | private System.Windows.Forms.Label TitleLabel; 125 | private System.Windows.Forms.ProgressBar progressBar1; 126 | private System.Windows.Forms.Label label2; 127 | private System.Windows.Forms.Label ConnectionLabel; 128 | private System.Windows.Forms.Timer timer1; 129 | private System.Windows.Forms.LinkLabel linkLabel1; 130 | } 131 | } -------------------------------------------------------------------------------- /src/Connecting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace esp_tools_gui 12 | { 13 | public partial class Connecting : Form 14 | { 15 | private static bool Stop = false; 16 | public Connecting(string tool, string text) 17 | { 18 | InitializeComponent(); 19 | 20 | Opacity = 0.0; 21 | TitleLabel.Text = tool; 22 | ConnectionLabel.Text = text; 23 | progressBar1.Value = 0; 24 | timer1.Enabled = true; 25 | Stop = false; 26 | } 27 | 28 | private void timer1_Tick(object sender, EventArgs e) 29 | { 30 | if (Opacity < 1.0) Opacity += 0.05; 31 | if (progressBar1.Value < progressBar1.Maximum) progressBar1.Value++; 32 | else if (linkLabel1.Visible == false) linkLabel1.Visible = true; 33 | if (Stop) 34 | { 35 | timer1.Enabled = false; 36 | this.Close(); 37 | } 38 | } 39 | 40 | public static void Terminate() 41 | { 42 | Stop = true; 43 | } 44 | 45 | private void Connecting_Load(object sender, EventArgs e) 46 | { 47 | Top -= 200; 48 | } 49 | 50 | private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 51 | { 52 | Stop = true; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/ESP32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adrianotiger/ESPToolsGUI/68f96feab419b5950a8643faa6f8b4c7992c05be/src/ESP32.ico -------------------------------------------------------------------------------- /src/MainPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Diagnostics; 6 | using System.Drawing; 7 | using System.IO; 8 | using System.IO.Ports; 9 | using System.Linq; 10 | using System.Management; 11 | using System.Reflection; 12 | using System.Text; 13 | using System.Text.RegularExpressions; 14 | using System.Threading.Tasks; 15 | using System.Windows.Forms; 16 | 17 | namespace esp_tools_gui 18 | { 19 | public partial class MainPage : Form 20 | { 21 | private static StringBuilder outStr; 22 | private ToolEfuse efuse; 23 | private ToolTool tool; 24 | private ToolSecure secure; 25 | private ToolPartition partition; 26 | private ToolPart partition2; 27 | private bool HasError = false; 28 | private bool isScrolling = false; 29 | 30 | private delegate void SafeCallDelegate(object sender, CustomEventArgs a); 31 | 32 | public MainPage() 33 | { 34 | InitializeComponent(); 35 | 36 | outStr = new StringBuilder(); 37 | richTextBox1.Text = ""; 38 | 39 | efuse = new ToolEfuse(); 40 | tool = new ToolTool(); 41 | secure = new ToolSecure(); 42 | partition = new ToolPartition(); 43 | partition2 = new ToolPart(); 44 | 45 | efuse.ConsoleEvent += HandleCustomEvent; 46 | tool.ConsoleEvent += HandleCustomEvent; 47 | secure.ConsoleEvent += HandleCustomEvent; 48 | partition.ConsoleEvent += HandleCustomEvent; 49 | partition2.ConsoleEvent += HandleCustomEvent; 50 | 51 | richTextBoxFlashHex.MouseWheel += RichTextBox_MouseWheel; 52 | richTextBoxFlashLine.MouseWheel += RichTextBox_MouseWheel; 53 | richTextBoxFlashData.MouseWheel += RichTextBox_MouseWheel; 54 | 55 | ExpertComboboxTool.SelectedIndex = 0; 56 | } 57 | 58 | protected override void OnLoad(EventArgs e) 59 | { 60 | base.OnLoad(e); 61 | this.Text += " - (v." + Application.ProductVersion + ")"; 62 | } 63 | 64 | private void MainPage_Load(object sender, EventArgs e) 65 | { 66 | using (var searcher = new ManagementObjectSearcher("SELECT * FROM WIN32_SerialPort")) 67 | { 68 | string[] portnames = SerialPort.GetPortNames(); 69 | var ports2 = searcher.Get().Cast().ToList(); 70 | var tList = (from n in portnames 71 | join p in ports2 on n equals p["DeviceID"].ToString() into joinedList 72 | from sub in joinedList.DefaultIfEmpty() 73 | select new ComPort{ PortId=n, Info=sub==null?"":sub["Caption"].ToString() }).ToList(); 74 | 75 | tList.ForEach((t)=> { comboBox1.Items.Add(t); }); 76 | } 77 | comboBox1.SelectedIndex = 0; 78 | if(comboBox1.Items.Count > 0) Tool._com = ((ComPort)comboBox1.Items[0]).PortId; 79 | foreach (ComPort i in comboBox1.Items) 80 | { 81 | if(Properties.Settings.Default.comport == i.ToString()) 82 | { 83 | comboBox1.SelectedItem = i; 84 | Tool._com = i.PortId; 85 | break; 86 | } 87 | } 88 | comboBox2.Text = Properties.Settings.Default.combaud; 89 | 90 | Tool._baud = Properties.Settings.Default.combaud; 91 | 92 | Application.DoEvents(); 93 | 94 | comboBox1.TextChanged += (s, ev) => 95 | { 96 | Tool._com = ((s as ComboBox).SelectedItem as ComPort).PortId; 97 | Properties.Settings.Default.comport = (s as ComboBox).Text; 98 | Properties.Settings.Default.Save(); 99 | }; 100 | comboBox2.TextChanged += (s, ev) => 101 | { 102 | Tool._baud = Properties.Settings.Default.combaud; 103 | Properties.Settings.Default.combaud = (s as ComboBox).Text; 104 | Properties.Settings.Default.Save(); 105 | }; 106 | } 107 | 108 | public class ComPort 109 | { 110 | public string PortId { get; set; } 111 | public string Info { get; set; } 112 | public override string ToString() 113 | { 114 | if (Info.Length > 1) 115 | { 116 | return PortId + " - " + Info; 117 | } 118 | else 119 | { 120 | return PortId; 121 | } 122 | } 123 | } 124 | 125 | private void button1_Click(object sender, EventArgs e) 126 | { 127 | HasError = false; 128 | splitContainer3.Panel2Collapsed = false; 129 | progressBar1.Value = 20; 130 | progressBar1.Visible = true; 131 | FillInfoTab(); 132 | if (HasError) 133 | { 134 | return; 135 | } 136 | tabControl1.SelectedIndex = 0; 137 | progressBar1.Value = 50; 138 | Application.DoEvents(); 139 | FillPartitionTab(); 140 | if (HasError) 141 | { 142 | return; 143 | } 144 | progressBar1.Value = 80; 145 | tabControl1.SelectedIndex++; 146 | Application.DoEvents(); 147 | FillEFuseTab(); 148 | if (HasError) 149 | { 150 | return; 151 | } 152 | progressBar1.Value = 100; 153 | tabControl1.SelectedIndex++; 154 | Application.DoEvents(); 155 | // todo: read something... 156 | progressBar1.Value = 100; 157 | Application.DoEvents(); 158 | progressBar1.Visible = false; 159 | tabControl1.Enabled = true; 160 | } 161 | 162 | private void FillInfoTab() 163 | { 164 | tool.Parse("--after no_reset flash_id"); 165 | infoTextboxChipType.Text = tool.ChipType; 166 | infoTextboxChip.Text = tool.Chip; 167 | infoTextboxFeature.Text = tool.Features; 168 | infoTextboxCrystal.Text = tool.Crystal; 169 | infoTextboxMac.Text = tool.MAC; 170 | infoTextboxFlash.Text = tool.Flash; 171 | } 172 | 173 | private void FillPartitionTab() 174 | { 175 | tool.ReadPartitionTable(); 176 | partitionChart.Series[0].Points.Clear(); 177 | partitionListview.Items.Clear(); 178 | foreach (var p in tool.Partitions) 179 | { 180 | var lv = partitionListview.Items.Add(p.Name); 181 | lv.SubItems.Add(p.GetTypeName()); 182 | lv.SubItems.Add(p.GetSubTypeName()); 183 | lv.SubItems.Add("0x" + p.Offset.ToString("X")); 184 | lv.SubItems.Add(p.GetSize()); 185 | lv.SubItems.Add("0x" + p.Flags.ToString("X")); 186 | 187 | var point = new System.Windows.Forms.DataVisualization.Charting.DataPoint(0.0, p.Size); 188 | point.AxisLabel = p.Name; 189 | partitionChart.Series[0].Points.Add(point); 190 | } 191 | } 192 | 193 | private void FillEFuseTab() 194 | { 195 | efuse.Parse("summary"); 196 | tableLayoutPanel1.RowCount = 11; 197 | tableLayoutPanel1.Controls.Clear(); 198 | int row = 0; 199 | foreach (var f in efuse.Fuses) 200 | { 201 | if (row > 10) tableLayoutPanel1.RowCount++; 202 | var l = new Label { Text = f.Key + ":", Parent = tableLayoutPanel1, Dock = DockStyle.Fill, BackColor = Color.AliceBlue }; 203 | tableLayoutPanel1.SetRow(l, row); 204 | tableLayoutPanel1.SetColumn(l, 0); 205 | tableLayoutPanel1.SetColumnSpan(l, 4); 206 | row++; 207 | foreach (var v in efuse.Fuses[f.Key]) 208 | { 209 | if (row > 10) tableLayoutPanel1.RowCount++; 210 | var l2 = new Label { Text = v.Title, Parent = tableLayoutPanel1, Dock = DockStyle.Fill }; 211 | tableLayoutPanel1.SetRow(l2, row); 212 | tableLayoutPanel1.SetColumn(l2, 0); 213 | l2 = new Label { Text = v.Description, Parent = tableLayoutPanel1, Dock = DockStyle.Fill }; 214 | tableLayoutPanel1.SetRow(l2, row); 215 | tableLayoutPanel1.SetColumn(l2, 1); 216 | var t2 = new TextBox { Text = v.Value, Parent = tableLayoutPanel1, Dock = DockStyle.Fill, ReadOnly = true }; 217 | tableLayoutPanel1.SetRow(t2, row); 218 | tableLayoutPanel1.SetColumn(t2, 2); 219 | l2 = new Label { Text = v.ReadWrite, Parent = tableLayoutPanel1, Dock = DockStyle.Fill }; 220 | tableLayoutPanel1.SetRow(l2, row); 221 | tableLayoutPanel1.SetColumn(l2, 3); 222 | row++; 223 | } 224 | } 225 | tableLayoutPanel1.RowStyles.Clear(); 226 | } 227 | 228 | 229 | private async void comboBox3_KeyPress(object sender, KeyPressEventArgs e) 230 | { 231 | if (e.KeyChar == '\r') 232 | { 233 | var text = (sender as ComboBox).Text; 234 | switch (ExpertComboboxTool.Text) 235 | { 236 | case "esptool": await tool.Execute(text); break; 237 | case "espefuse": await efuse.Execute(text); break; 238 | case "espsecure": await secure.Execute(text); break; 239 | case "gen_esp32part": await partition.Execute(text); break; 240 | case "parttool": await partition2.Execute(text); break; 241 | } 242 | 243 | for(var k=0;k 1) comboBox3.Items.Insert(0, text); 253 | } 254 | } 255 | 256 | void HandleCustomEvent(object sender, CustomEventArgs a) 257 | { 258 | if (richTextBox1.InvokeRequired) 259 | { 260 | this.BeginInvoke(new SafeCallDelegate(HandleCustomEvent), new object[] { sender, a }); 261 | return; 262 | } 263 | if (a.input.Length > 0) 264 | { 265 | string txt; 266 | txt = "\r\n > " + a.input + "\r\n"; 267 | richTextBox1.SelectionColor = Color.White; 268 | richTextBox1.AppendText(txt); 269 | richTextBox1.SelectionColor = richTextBox1.ForeColor; 270 | richTextBox1.ScrollToCaret(); 271 | } 272 | if(a.error.Length > 0) 273 | { 274 | string txt; 275 | txt = "\r\n [E] " + a.error + "\r\n"; 276 | richTextBox1.SelectionColor = Color.LightCoral; 277 | richTextBox1.AppendText(txt); 278 | richTextBox1.SelectionColor = richTextBox1.ForeColor; 279 | richTextBox1.ScrollToCaret(); 280 | HasError = true; 281 | } 282 | if(a.output.Length > 0) 283 | { 284 | string txt; 285 | txt = a.output; 286 | if (txt.Contains("fatal error")) HasError = true; 287 | //else txt = a.output + "\r\n"; 288 | richTextBox1.AppendText(txt); 289 | if(txt.Contains("\r\n")) richTextBox1.ScrollToCaret(); 290 | } 291 | } 292 | 293 | private void LinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 294 | { 295 | Process.Start((sender as LinkLabel).Text); 296 | } 297 | 298 | private void groupBox1_Enter(object sender, EventArgs e) 299 | { 300 | 301 | } 302 | 303 | private void button3_Click(object sender, EventArgs e) 304 | { 305 | 306 | } 307 | 308 | private void readFlashToolStripMenuItem_Click(object sender, EventArgs e) 309 | { 310 | if(partitionListview.SelectedIndices.Count == 1) 311 | { 312 | int index = partitionListview.SelectedIndices[0]; 313 | Regex re = new Regex(@"(\d+)(\.\d+)?\s*"); 314 | var m = re.Matches(partitionListview.Items[index].SubItems[4].Text); 315 | if (m.Count >= 1) 316 | { 317 | int address = Convert.ToInt32(partitionListview.Items[index].SubItems[3].Text, 16); 318 | int size = (int)(double.Parse(m[0].Value) * 1024); 319 | 320 | numericUpDownFlashAddr.Value = address; 321 | numericUpDownFlashCount.Value = size; 322 | 323 | tabControl1.SelectedIndex = 3; 324 | buttonReadFlash_Click(sender, e); 325 | } 326 | } 327 | } 328 | 329 | private void RichTextBox_MouseWheel(object sender, MouseEventArgs e) 330 | { 331 | if (e.Delta < 0) 332 | { 333 | if (vScrollBar1.Value < vScrollBar1.Maximum) vScrollBar1.Value++; 334 | } 335 | else if (e.Delta > 0) 336 | { 337 | if (vScrollBar1.Value > 0) vScrollBar1.Value--; 338 | } 339 | } 340 | 341 | private void vScrollBar1_Scroll(object sender, ScrollEventArgs e) 342 | { 343 | 344 | } 345 | 346 | private void vScrollBar1_ValueChanged(object sender, EventArgs e) 347 | { 348 | if (isScrolling) return; 349 | int line = richTextBoxFlashLine.GetFirstCharIndexFromLine(vScrollBar1.Value); 350 | if (line < 0) return; 351 | richTextBoxFlashLine.Select(line, 8); 352 | } 353 | 354 | private void richTextBoxFlashData_SelectionChanged(object sender, EventArgs e) 355 | { 356 | if (isScrolling) return; 357 | isScrolling = true; 358 | int line = richTextBoxFlashData.GetLineFromCharIndex(richTextBoxFlashData.SelectionStart); 359 | int charX0 = richTextBoxFlashData.GetFirstCharIndexFromLine(line); 360 | //if (richTextBoxFlashHex.SelectionStart > 2) charX0 += 1; 361 | int charSelection = (richTextBoxFlashData.SelectionStart - charX0); 362 | richTextBoxFlashLine.Select(richTextBoxFlashLine.GetFirstCharIndexFromLine(line), 8); 363 | richTextBoxFlashHex.Select(richTextBoxFlashHex.GetFirstCharIndexFromLine(line) + charSelection * 3 + 1, 2); 364 | vScrollBar1.Value = line; 365 | Application.DoEvents(); 366 | isScrolling = false; 367 | } 368 | 369 | private void richTextBoxFlashLine_SelectionChanged(object sender, EventArgs e) 370 | { 371 | if (isScrolling) return; 372 | isScrolling = true; 373 | int line = richTextBoxFlashLine.GetLineFromCharIndex(richTextBoxFlashLine.SelectionStart); 374 | int charX0 = richTextBoxFlashLine.GetFirstCharIndexFromLine(line); 375 | richTextBoxFlashData.SelectionStart = richTextBoxFlashData.GetFirstCharIndexFromLine(line); 376 | richTextBoxFlashHex.SelectionStart = richTextBoxFlashHex.GetFirstCharIndexFromLine(line); 377 | vScrollBar1.Value = line; 378 | Application.DoEvents(); 379 | isScrolling = false; 380 | } 381 | 382 | private void richTextBoxFlashHex_SelectionChanged(object sender, EventArgs e) 383 | { 384 | if (isScrolling) return; 385 | isScrolling = true; 386 | int line = richTextBoxFlashHex.GetLineFromCharIndex(richTextBoxFlashHex.SelectionStart); 387 | int charX0 = richTextBoxFlashHex.GetFirstCharIndexFromLine(line); 388 | if (richTextBoxFlashHex.SelectionStart > 2) charX0 += 1; 389 | int charSelection = (richTextBoxFlashHex.SelectionStart - charX0) / 3; 390 | richTextBoxFlashLine.Select(richTextBoxFlashLine.GetFirstCharIndexFromLine(line), 8); 391 | richTextBoxFlashData.Select(richTextBoxFlashData.GetFirstCharIndexFromLine(line) + charSelection, 1); 392 | vScrollBar1.Value = line; 393 | Application.DoEvents(); 394 | isScrolling = false; 395 | } 396 | 397 | private async void editPartitionTableToolStripMenuItem_Click(object sender, EventArgs e) 398 | { 399 | Regex re = new Regex(@"(\d+)(\.\d+)?\s*"); 400 | var m = re.Matches(tool.Flash); 401 | 402 | if (m.Count > 0) 403 | { 404 | PartTool pt = new PartTool(int.Parse(m[0].Value), partition); 405 | foreach (ListViewItem lv in partitionListview.Items) 406 | { 407 | m = re.Matches(lv.SubItems[4].Text); 408 | double size = double.Parse(m[0].Value); 409 | if (m.Count > 1) double.Parse(m[0].Value + "." + m[1].Value); 410 | if (lv.SubItems[4].Text.IndexOf("k") > 0) size *= 1024; 411 | if (lv.SubItems[4].Text.IndexOf("M") > 0) size *= 1024 * 1024; 412 | size = Convert.ToInt32(size); 413 | switch (lv.Text.Replace("\0", "").Trim()) 414 | { 415 | case "nvs": 416 | pt.SetNvs(int.Parse(size.ToString())); 417 | break; 418 | case "eeprom": 419 | pt.SetEeprom(int.Parse(size.ToString())); 420 | break; 421 | case "app0": 422 | pt.SetOta0(int.Parse(size.ToString()), null); 423 | break; 424 | case "app1": 425 | pt.SetOta1(int.Parse(size.ToString())); 426 | break; 427 | case "otadata": 428 | pt.SetOtaD(int.Parse(size.ToString())); 429 | break; 430 | case "ffat": 431 | pt.SetFfat(int.Parse(size.ToString())); 432 | break; 433 | case "spiffs": 434 | pt.SetSpiffs(int.Parse(size.ToString())); 435 | break; 436 | } 437 | } 438 | if (pt.ShowDialog() == DialogResult.Yes) 439 | { 440 | var res = partition.CreatePartition(PartTool.Nvs, PartTool.Ota0, PartTool.Ota1, PartTool.Eeprom, PartTool.Spiffs, PartTool.Ffat); 441 | await tool.Execute("--before default_reset --after hard_reset write_flash 0x8000 part.bin"); 442 | FillPartitionTab(); 443 | } 444 | } 445 | else 446 | { 447 | MessageBox.Show("Unable to get flash size. Connect device before execute this function.", "Error"); 448 | } 449 | } 450 | 451 | private void buttonReadFlash_Click(object sender, EventArgs e) 452 | { 453 | isScrolling = true; 454 | var startAddr = (int)numericUpDownFlashAddr.Value; 455 | var TotalRead = (int)numericUpDownFlashCount.Value; 456 | int ToRead = TotalRead; 457 | richTextBoxFlashHex.Clear(); 458 | richTextBoxFlashLine.Clear(); 459 | richTextBoxFlashData.Clear(); 460 | 461 | vScrollBar1.Value = 1; 462 | vScrollBar1.Maximum = TotalRead / 16; 463 | 464 | int voids = -(startAddr % 16); 465 | int lineNumber = startAddr + voids; 466 | char t; 467 | 468 | //do 469 | { 470 | String s1 = "", s2 = "", s3 = ""; 471 | if (ToRead > 0x10000) ToRead = 0x8000; 472 | var bytes = ReadFlashPart(startAddr, ToRead); 473 | TotalRead -= ToRead; 474 | if (voids > 0) voids = 0; 475 | int lines = ToRead / 16; 476 | 477 | for (var j = 0; j < lines; j++) 478 | { 479 | s1 += "0x" + lineNumber.ToString("X6") + "\n"; 480 | 481 | for (var k = 0; k < 16; k++) 482 | { 483 | s2 += " "; 484 | if (voids < 0) 485 | { 486 | s2 += " "; 487 | } 488 | else if (voids > bytes.Length) 489 | { 490 | s2 += " "; 491 | } 492 | else 493 | { 494 | s2 += bytes[voids].ToString("X2"); 495 | } 496 | voids++; 497 | } 498 | s2 += "\n"; 499 | 500 | voids -= 16; 501 | for (var k = 0; k < 16; k++) 502 | { 503 | if (voids < 0) 504 | { 505 | s3 += " "; 506 | } 507 | else if (voids > bytes.Length) 508 | { 509 | s3 += " "; 510 | } 511 | else 512 | { 513 | t = ((char)bytes[voids]); 514 | if (t >= 0x20) 515 | s3 += ((char)bytes[voids]).ToString(); 516 | else 517 | s3 += "."; 518 | } 519 | voids++; 520 | } 521 | s3 += "\n"; 522 | lineNumber += 16; 523 | } 524 | 525 | richTextBoxFlashLine.AppendText(s1); 526 | richTextBoxFlashHex.AppendText(s2); 527 | richTextBoxFlashData.AppendText(s3); 528 | 529 | startAddr += ToRead; 530 | ToRead = TotalRead; 531 | }// while (ToRead > 0); 532 | 533 | int totalLines = richTextBoxFlashData.Lines.Length; 534 | double lineHeight = richTextBoxFlashData.PreferredSize.Height * 1.0 / totalLines; 535 | int visibleLines = (int)(richTextBoxFlashData.Height / lineHeight); 536 | vScrollBar1.Maximum = Math.Max(1, totalLines); 537 | isScrolling = false; 538 | vScrollBar1.Value = 0; 539 | } 540 | 541 | private Byte[] ReadFlashPart(int startAddr, int bytes) 542 | { 543 | return tool.ReadMemory(startAddr, bytes); 544 | } 545 | 546 | private async void ereasePartitionToolStripMenuItem_Click(object sender, EventArgs e) 547 | { 548 | if (partitionListview.SelectedIndices.Count == 1) 549 | { 550 | if(MessageBox.Show("Do you really want erease this partition? All data will be ereased.", "Clear partition", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes) 551 | { 552 | int index = partitionListview.SelectedIndices[0]; 553 | Regex re = new Regex(@"(\d+)(\.\d+)?\s*"); 554 | var m = re.Matches(partitionListview.Items[index].SubItems[4].Text); 555 | if (m.Count >= 1) 556 | { 557 | int address = Convert.ToInt32(partitionListview.Items[index].SubItems[3].Text, 16); 558 | int size = (int)(double.Parse(m[0].Value) * 1024); 559 | 560 | await tool.Execute("erase_region 0x" + address.ToString("X") + " 0x" + size.ToString("X")); 561 | } 562 | } 563 | } 564 | } 565 | 566 | private void contextMenuStripPartition_Opening(object sender, CancelEventArgs e) 567 | { 568 | 569 | } 570 | 571 | private void button2_Click(object sender, EventArgs e) 572 | { 573 | editPartitionTableToolStripMenuItem_Click(sender, e); 574 | } 575 | } 576 | 577 | public class CustomEventArgs 578 | { 579 | public string input { get; set; } = ""; 580 | public string output { get; set; } = ""; 581 | public string error { get; set; } = ""; 582 | } 583 | } 584 | -------------------------------------------------------------------------------- /src/Tool.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.Reflection; 8 | using System.Text; 9 | using System.Text.RegularExpressions; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using System.Windows.Forms.DataVisualization.Charting; 13 | 14 | namespace esp_tools_gui 15 | { 16 | public class Tool 17 | { 18 | private string _exe; 19 | 20 | public static string _com = ""; 21 | public static string _baud = ""; 22 | 23 | private StringBuilder _outStr = new StringBuilder(); 24 | protected readonly static string ExePath = Path.Combine(Directory.GetCurrentDirectory(), "exes"); 25 | protected readonly static string PythonDll = "python310.dll"; 26 | private bool _useComArgs = true; 27 | 28 | public event EventHandler ConsoleEvent; 29 | 30 | public Tool(string executable, bool AddComArgs) 31 | { 32 | _exe = executable; 33 | _useComArgs = AddComArgs; 34 | } 35 | private String GetComParam() 36 | { 37 | if (_useComArgs) 38 | return "--port " + _com + " --baud " + _baud + " "; 39 | else 40 | return ""; 41 | } 42 | 43 | public async Task Execute(string args) 44 | { 45 | Connecting conn = new Connecting(_exe, GetComParam() + args); 46 | CancellationTokenSource cts = new CancellationTokenSource(); 47 | 48 | var t = Task.Run(() => 49 | { 50 | string tempExeName = Path.Combine(ExePath, _exe); 51 | 52 | if (!File.Exists(Path.Combine(ExePath, PythonDll)) || !Directory.Exists(Path.Combine(ExePath, "lib"))) 53 | { 54 | if (File.Exists(Path.Combine(ExePath, PythonDll))) 55 | File.Delete(Path.Combine(ExePath, PythonDll)); 56 | if (Directory.Exists(Path.Combine(ExePath, "lib"))) 57 | Directory.Delete(Path.Combine(ExePath, "lib"), true); 58 | ZipFile.ExtractToDirectory(Path.Combine(ExePath, "cxfreeze.zip"), ExePath); 59 | } 60 | 61 | if (!File.Exists(Path.Combine(ExePath, PythonDll))) 62 | { 63 | ConsoleEvent.Invoke(this, new CustomEventArgs { error = "Python DLL is not loaded." }); 64 | } 65 | else if (!File.Exists(tempExeName)) 66 | { 67 | var errMsg = "[" + _exe + "] File '" + _exe + "' not found in directory " + ExePath + "! Unable to start request."; 68 | ConsoleEvent.Invoke(this, new CustomEventArgs { error = errMsg }); 69 | } 70 | else if (_com.Length < 3) 71 | { 72 | var errMsg = "[" + _exe + "] COM port is invalid (" + _com + ") - please select the right port and try again."; 73 | ConsoleEvent.Invoke(this, new CustomEventArgs { error = errMsg }); 74 | } 75 | else 76 | { 77 | int procId = 0; 78 | var stopwatch = new Stopwatch(); 79 | stopwatch.Start(); 80 | using (var p = new Process()) 81 | { 82 | try 83 | { 84 | using (cts.Token.Register(()=> { p.Kill(); p.WaitForExit(500); p.Close(); p.Dispose(); })) 85 | { 86 | _outStr.Clear(); 87 | _outStr.Append(" >>> " + _exe + " " + GetComParam() + args + "\r\n"); 88 | ConsoleEvent.Invoke(this, new CustomEventArgs { input = _exe + " " + GetComParam() + args }); 89 | p.StartInfo = new ProcessStartInfo 90 | { 91 | FileName = tempExeName, 92 | UseShellExecute = false, 93 | WorkingDirectory = ExePath, 94 | WindowStyle = ProcessWindowStyle.Hidden, 95 | CreateNoWindow = true, 96 | Arguments = GetComParam() + args, 97 | RedirectStandardOutput = true, 98 | RedirectStandardError = true 99 | }; 100 | 101 | //p.StartInfo.RedirectStandardError = true; 102 | //p.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); 103 | p.ErrorDataReceived += new DataReceivedEventHandler(ErrorHandler); 104 | p.Start(); 105 | //p.BeginOutputReadLine(); 106 | p.BeginErrorReadLine(); 107 | procId = p.Id; 108 | 109 | int dataReceived = 0; 110 | var sTemp = ""; 111 | var outputReadTask = Task.Run(() => 112 | { 113 | int iCh = 0; 114 | var s2 = ""; 115 | var s3 = ""; 116 | try 117 | { 118 | do 119 | { 120 | iCh = p.StandardOutput.Read(); 121 | if (iCh >= 0) 122 | { 123 | if (iCh == 8) 124 | { 125 | s3 = "\r\n"; 126 | s2 = " "; 127 | } 128 | else 129 | { 130 | s2 = s3 + char.ConvertFromUtf32(iCh); 131 | if (s3.Length > 0) s3 = ""; 132 | } 133 | sTemp += s2; 134 | } 135 | } while (iCh >= 0); 136 | } 137 | catch (Exception e) 138 | { 139 | var errMsg = "[" + _exe + "] Exception: " + e.Message; 140 | ConsoleEvent.Invoke(this, new CustomEventArgs { error = errMsg }); 141 | } 142 | }); 143 | 144 | do 145 | { 146 | try 147 | { 148 | if (sTemp.Length > 0) 149 | { 150 | dataReceived++; 151 | var s = sTemp; 152 | sTemp = ""; 153 | _outStr.Append(s); 154 | ConsoleEvent.Invoke(this, new CustomEventArgs { output = s }); 155 | } 156 | else 157 | { 158 | p.WaitForExit(200); 159 | } 160 | } 161 | catch (Exception) { } 162 | 163 | if (dataReceived == 0 && stopwatch.ElapsedMilliseconds > 3000) 164 | { 165 | ConsoleEvent.Invoke(this, new CustomEventArgs { error = "Request timeout." }); 166 | break; 167 | } 168 | } while (!p.HasExited); 169 | if (sTemp.Length > 0) 170 | { 171 | _outStr.Append(sTemp); 172 | ConsoleEvent.Invoke(this, new CustomEventArgs { output = sTemp }); 173 | } 174 | } 175 | } 176 | catch(Exception ex) 177 | { 178 | ConsoleEvent.Invoke(this, new CustomEventArgs { error = ex.Message }); 179 | } 180 | try 181 | { 182 | p.Close(); 183 | } 184 | catch (Exception) { } 185 | } 186 | 187 | stopwatch.Stop(); 188 | long elapsed_time = stopwatch.ElapsedMilliseconds; 189 | ConsoleEvent.Invoke(this, new CustomEventArgs { input = " [ execution time ] " + (elapsed_time / 1000.0) + " s" }); 190 | 191 | try 192 | { 193 | if (Process.GetProcessesByName(_exe.Replace(".exe", "")).Length > 0) 194 | { 195 | Process.GetProcessesByName(_exe.Replace(".exe", ""))[0].Kill(); 196 | } 197 | } 198 | catch (Exception) { } 199 | } 200 | 201 | Connecting.Terminate(); 202 | }, cts.Token); 203 | 204 | conn.ShowDialog(); 205 | if(!t.IsCompleted) // was aborted 206 | { 207 | ConsoleEvent.Invoke(this, new CustomEventArgs { error = "Request aborted." }); 208 | cts.Cancel(); 209 | t.Wait(500); 210 | } 211 | 212 | return await Task.FromResult(_outStr.ToString()); 213 | } 214 | 215 | public string GetExePath() 216 | { 217 | return ExePath; 218 | } 219 | 220 | public string RegexSimple(string beginsWith, string txt) 221 | { 222 | var found = Regex.Match(txt, "(" + beginsWith + " )(.*]?)"); 223 | if (found.Groups.Count == 3) 224 | { 225 | return found.Groups[2].ToString().Trim(); 226 | } 227 | else return ""; 228 | } 229 | 230 | public List RegexFuse(string line) 231 | { 232 | List values = new List(); 233 | var found = Regex.Match(line, @"([a-zA-Z0-9_]*)[ ]*(.*)[\=](.*) ([R|W|\/]*) (.*)"); 234 | if(found.Groups.Count > 4) 235 | { 236 | values.Add(found.Groups[1].Value.Trim()); 237 | values.Add(found.Groups[2].Value.Trim()); 238 | values.Add(found.Groups[3].Value.Trim()); 239 | values.Add(found.Groups[4].Value.Trim()); 240 | } 241 | return values; 242 | //XPD_SDIO_FORCE Ignore MTDI pin (GPIO12) for VDD_SDIO on reset = 0 R/W (0x0) 243 | } 244 | 245 | private void OutputHandler(object sender, DataReceivedEventArgs e) 246 | { 247 | // Prepend line numbers to each line of the output. 248 | if (e.Data != null) 249 | { 250 | ConsoleEvent.Invoke(this, new CustomEventArgs { output = e.Data }); 251 | _outStr.Append("\r\n" + e.Data); 252 | } 253 | } 254 | 255 | private void ErrorHandler(object sender, DataReceivedEventArgs e) 256 | { 257 | // Prepend line numbers to each line of the output. 258 | if (e.Data != null) 259 | { 260 | ConsoleEvent.Invoke(this, new CustomEventArgs { error = e.Data }); 261 | _outStr.Append("\r\n" + e.Data); 262 | } 263 | } 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /src/ToolEfuse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace esp_tools_gui 8 | { 9 | class ToolEfuse : Tool 10 | { 11 | public Dictionary> Fuses = new Dictionary>(); 12 | 13 | public ToolEfuse() : base("espefuse.exe", true) 14 | { 15 | 16 | } 17 | 18 | public async void Parse(string args) 19 | { 20 | var str = await Execute(args); 21 | if(args.Contains("summary")) 22 | { 23 | //ChipType = RegexSimple("Detecting chip type...", str); 24 | var substr = str.Split(new string[] { ":\r" }, StringSplitOptions.RemoveEmptyEntries); 25 | var first = true; 26 | List eFuseList; 27 | Fuses.Clear(); 28 | var nextTitle = ""; 29 | foreach(var block in substr) 30 | { 31 | var lines = block.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries); 32 | if(first) 33 | { 34 | nextTitle = lines[lines.Length - 1]; 35 | first = false; 36 | } 37 | else 38 | { 39 | eFuseList = new List(); 40 | Fuses.Add(nextTitle, eFuseList); 41 | nextTitle = lines.Last(); 42 | var memLine = ""; 43 | foreach (var line in lines) 44 | { 45 | var values = RegexFuse(memLine + line); 46 | if(values.Count >= 3) 47 | { 48 | eFuseList.Add(new EFuse { Title = values[0], Description = values[1], Value = values[2], ReadWrite = values[3] }); 49 | memLine = ""; 50 | } 51 | else 52 | { 53 | memLine = line.Trim(); 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | 62 | class EFuse 63 | { 64 | public string Title { get; set; } = ""; 65 | public string Description { get; set; } = ""; 66 | public string Value { get; set; } = ""; 67 | public string ReadWrite { get; set; } = ""; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/ToolPart.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace esp_tools_gui 8 | { 9 | class ToolPart : Tool 10 | { 11 | public ToolPart() : base("parttool.exe", true) 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ToolPartition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace esp_tools_gui 9 | { 10 | public class ToolPartition : Tool 11 | { 12 | public ToolPartition() : base("gen_esp32part.exe", false) 13 | { 14 | 15 | } 16 | 17 | public async Task CreatePartition(int nvs, int ota0, int ota1, int eeprom, int spiffs, int ffat) 18 | { 19 | int addr = 0x9000; 20 | String text = "# Name, Type, SubType, Offset, Size, Flags\n"; 21 | if(nvs > 0) 22 | { 23 | text += "nvs, data, nvs, 0x" + addr.ToString("x") + ", 0x" + nvs.ToString("x") + ",\n"; 24 | addr += nvs; 25 | } 26 | text += "otadata, data, ota, 0x" + addr.ToString("x") + ", 0x" + (PartTool.Otad).ToString("x") + ",\n"; 27 | addr += PartTool.Otad; 28 | text += "app0, app, ota_0, 0x" + addr.ToString("x") + ", 0x" + ota0.ToString("x") + ",\n"; 29 | addr += ota0; 30 | if (ota1 > 0) 31 | { 32 | text += "app1, app, ota_1, 0x" + addr.ToString("x") + ", 0x" + ota1.ToString("x") + ",\n"; 33 | addr += ota1; 34 | } 35 | if (eeprom > 0) 36 | { 37 | text += "eeprom, data, 0x99, 0x" + addr.ToString("x") + ", 0x" + eeprom.ToString("x") + ",\n"; 38 | addr += eeprom; 39 | } 40 | if (spiffs > 0) 41 | { 42 | text += "spiffs, data, spiffs, 0x" + addr.ToString("x") + ", 0x" + spiffs.ToString("x") + ",\n"; 43 | addr += spiffs; 44 | } 45 | if (ffat > 0) 46 | { 47 | text += "ffat, data, fat, 0x" + addr.ToString("x") + ", 0x" + ffat.ToString("x") + ",\n"; 48 | addr += ffat; 49 | } 50 | 51 | String csvFile = GetPartitionPath(false); 52 | String binFile = GetPartitionPath(true); 53 | 54 | if (File.Exists(csvFile)) File.Delete(csvFile); 55 | if (File.Exists(binFile)) File.Delete(binFile); 56 | File.WriteAllText(csvFile, text); 57 | 58 | return await Execute("part.csv part.bin"); 59 | 60 | /* 61 | nvs, data, nvs, 0x9000, 0x5000, 62 | otadata, data, ota, 0xe000, 0x2000, 63 | app0, app, ota_0, 0x10000, 0x140000, 64 | app1, app, ota_1, 0x150000,0x140000, 65 | spiffs, data, spiffs, 0x290000,0x170000, 66 | */ 67 | } 68 | 69 | public string GetPartitionPath(bool bin) 70 | { 71 | if(bin) 72 | { 73 | return ExePath + "\\part.bin"; 74 | } 75 | else 76 | { 77 | return ExePath + "\\part.csv"; 78 | } 79 | } 80 | 81 | public async Task ImportTable(string filename) 82 | { 83 | String csvFile = GetPartitionPath(false); 84 | String binFile = GetPartitionPath(true); 85 | 86 | if (File.Exists(csvFile)) File.Delete(csvFile); 87 | if (File.Exists(binFile)) File.Delete(binFile); 88 | 89 | if(filename.EndsWith(".bin")) 90 | { 91 | File.Copy(filename, binFile); 92 | await Execute("part.bin part.csv"); 93 | } 94 | else if(filename.EndsWith(".csv")) 95 | { 96 | File.Copy(filename, csvFile); 97 | await Execute("part.csv part.bin"); 98 | } 99 | else 100 | { 101 | return false; 102 | } 103 | return true; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/ToolSecure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace esp_tools_gui 8 | { 9 | class ToolSecure : Tool 10 | { 11 | public ToolSecure() : base("espsecure.exe", true) 12 | { 13 | 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ToolTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace esp_tools_gui 9 | { 10 | class ToolTool : Tool 11 | { 12 | public String ChipType { get; set; } = ""; 13 | public String Chip { get; set; } = ""; 14 | public String Features { get; set; } = ""; 15 | public String Crystal { get; set; } = ""; 16 | public String MAC { get; set; } = ""; 17 | public String Flash { get; set; } = ""; 18 | 19 | public List Partitions { get; set; } = new List(); 20 | 21 | public ToolTool() : base("esptool.exe", true) 22 | { 23 | 24 | } 25 | 26 | public async void Parse(string args) 27 | { 28 | var str = await Execute(args); 29 | if (args.Contains("chip_id")) 30 | { 31 | ChipType = RegexSimple("Detecting chip type...", str); 32 | Chip = RegexSimple("Chip is", str); 33 | Features = RegexSimple("Features:", str); 34 | Crystal = RegexSimple("Crystal is", str); 35 | MAC = RegexSimple("MAC:", str); 36 | } 37 | 38 | if (args.Contains("flash_id")) 39 | { 40 | ChipType = RegexSimple("Detecting chip type...", str); 41 | Chip = RegexSimple("Chip is", str); 42 | Features = RegexSimple("Features:", str); 43 | Crystal = RegexSimple("Crystal is", str); 44 | MAC = RegexSimple("MAC:", str); 45 | Flash = RegexSimple("Detected flash size:", str); 46 | } 47 | } 48 | 49 | public Byte[] ReadMemory(int startAddress, int size) 50 | { 51 | String start = startAddress.ToString("x"); 52 | String total = size.ToString("x"); 53 | Parse("read_flash 0x" + start + " 0x" + total + " temp.bin"); 54 | 55 | if(startAddress == 0x8000 && size == 0x400) // read partition info 56 | { 57 | try 58 | { 59 | string binFile = Path.Combine(ExePath, "temp.bin"); 60 | using (FileStream fs2 = new FileStream(binFile, FileMode.Open)) 61 | { 62 | using (BinaryReader r = new BinaryReader(fs2)) 63 | { 64 | Int16 startPart; 65 | Partitions.Clear(); 66 | 67 | do 68 | { 69 | var p = new Partition(); 70 | 71 | startPart = r.ReadByte(); 72 | if (startPart != 0xaa) break; 73 | p.Flags = r.ReadByte(); 74 | p.Type = r.ReadByte(); 75 | p.Subtype = r.ReadByte(); 76 | p.Offset = r.ReadUInt32(); 77 | p.Size = r.ReadUInt32(); 78 | p.Name = Encoding.UTF8.GetString(r.ReadBytes(20), 0, 20); 79 | Partitions.Add(p); 80 | } while (startPart == 0xaa); 81 | } 82 | } 83 | } 84 | catch (Exception) 85 | { 86 | // todo: failed to open image... command was not successfully 87 | } 88 | } 89 | 90 | return File.ReadAllBytes(ExePath + "\\temp.bin"); 91 | } 92 | 93 | public void ReadPartitionTable() 94 | { 95 | ReadMemory(0x8000, 0x400); 96 | } 97 | } 98 | 99 | 100 | class Partition 101 | { 102 | public int Type { get; set; } 103 | public int Subtype { get; set; } 104 | public uint Offset { get; set; } 105 | public uint Size {get; set;} 106 | public int Flags { get; set; } 107 | public string Name { get; set; } 108 | 109 | public string GetTypeName() 110 | { 111 | if (Type == 0) return "APP"; 112 | else if (Type == 1) return "DATA"; 113 | else return "CUSTOM " + Type; 114 | } 115 | 116 | public string GetSubTypeName() 117 | { 118 | if (Type == 0) 119 | { 120 | if (Subtype == 0) return "FACTORY"; 121 | else if(Subtype < 0x20) return "OTA_" + (Subtype - 0x10).ToString("X"); 122 | else if (Subtype == 0x20) return "OTA_TEST"; 123 | else return "OTA_? " + Subtype.ToString("X"); 124 | } 125 | else if (Type == 1) 126 | { 127 | switch(Subtype) 128 | { 129 | case 0: return "OTA"; 130 | case 1: return "PHY"; 131 | case 2: return "NVS"; 132 | case 4: return "NVS_KEYS"; 133 | default: return "UNKNOWN " + Subtype.ToString("X"); 134 | } 135 | } 136 | else return Type.ToString(); 137 | } 138 | 139 | public string GetSize() 140 | { 141 | double size = Size; 142 | if (size < 1000) return size.ToString("0") + " bytes"; 143 | size = size / 1024; 144 | /*if (size < 1000)*/ return size.ToString("0.000") + " kb"; 145 | //size = size / 1024; 146 | //return size.ToString("0.000") + " Mb"; 147 | } 148 | } 149 | } 150 | --------------------------------------------------------------------------------