├── .github └── workflows │ └── nuget-publish.yaml ├── .gitignore ├── ESPTool.sln ├── ESPTool ├── ChipTypes.cs ├── Commands │ ├── RequestCommand.cs │ ├── RequestCommandBuilder.cs │ ├── ResponseCommand.cs │ └── ResponseCommandStatus.cs ├── Communication │ ├── Communicator.cs │ ├── Frame.cs │ └── SlipFraming.cs ├── Config │ ├── ConfigProvider.cs │ ├── DeviceConfig.cs │ ├── EFuseMapping.cs │ ├── ESPToolConfig.cs │ └── PinSequenceStep.cs ├── EFlagKey.cs ├── ESPToolbox.cs ├── EspDotNet.csproj ├── Example.cs ├── Loaders │ ├── ESP32BootLoader │ │ ├── BootLoaderCommandExecutor.cs │ │ ├── BootLoaderResponseStatus.cs │ │ └── ESP32Loader.cs │ ├── ILoader.cs │ └── SoftLoader │ │ ├── SoftLoader.cs │ │ ├── SoftLoaderCommandExecutor.cs │ │ └── SoftLoaderResponseStatus.cs ├── Resources │ ├── Config │ │ ├── Devices │ │ │ ├── ESP32.json │ │ │ ├── ESP32C3.json │ │ │ ├── ESP32H2.json │ │ │ ├── ESP32S2.json │ │ │ ├── ESP32S3.json │ │ │ └── ESP8266.json │ │ └── ESPToolConfig.json │ └── stub │ │ ├── stub_flasher_32.json │ │ ├── stub_flasher_32c2.json │ │ ├── stub_flasher_32c3.json │ │ ├── stub_flasher_32c6.json │ │ ├── stub_flasher_32c6beta.json │ │ ├── stub_flasher_32h2.json │ │ ├── stub_flasher_32h2beta1.json │ │ ├── stub_flasher_32h2beta2.json │ │ ├── stub_flasher_32p4.json │ │ ├── stub_flasher_32s2.json │ │ ├── stub_flasher_32s3.json │ │ ├── stub_flasher_32s3beta2.json │ │ └── stub_flasher_8266.json ├── Tools │ ├── BootloaderTool.cs │ ├── ChangeBaudrateTool.cs │ ├── ChipTypeDetectTool.cs │ ├── EFuseTool.cs │ ├── Firmware │ │ ├── DefaultFirmwareProviders.cs │ │ ├── FirmwareProvider.cs │ │ ├── FirmwareSegment.cs │ │ ├── FirmwareSegmentProvider.cs │ │ ├── IFirmwareProvider.cs │ │ └── IFirmwareSegmentProvider.cs │ ├── FirmwareUploadTool.cs │ ├── FlashEraseTool.cs │ ├── GetAddressesTool.cs │ ├── IUploadTool.cs │ ├── ResetDeviceTool.cs │ ├── SoftloaderTool.cs │ ├── UploadFlashDeflatedTool.cs │ ├── UploadFlashTool.cs │ └── UploadRamTool.cs └── Utils │ └── ZlibCompressionHelper.cs ├── LICENSE └── README.md /.github/workflows/nuget-publish.yaml: -------------------------------------------------------------------------------- 1 | name: Publish to NuGet & GitHub Releases 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" # Triggers when a tag like v2.0.2 is pushed 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Setup .NET 16 | uses: actions/setup-dotnet@v3 17 | with: 18 | dotnet-version: "8.0.x" 19 | 20 | - name: Restore dependencies 21 | run: dotnet restore 22 | 23 | - name: Get version from Git tag 24 | id: version 25 | run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV 26 | 27 | - name: Build the project 28 | run: dotnet build --configuration Release --no-restore /p:Version=${{ env.VERSION }} 29 | 30 | - name: Pack NuGet package 31 | run: dotnet pack --configuration Release --no-build --output nupkg /p:PackageVersion=${{ env.VERSION }} 32 | 33 | - name: Push to NuGet 34 | run: dotnet nuget push nupkg/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate 35 | 36 | - name: Create GitHub Release 37 | uses: softprops/action-gh-release@v2 38 | with: 39 | tag_name: v${{ env.VERSION }} 40 | name: Release v${{ env.VERSION }} 41 | body: | 42 | **What's new in v${{ env.VERSION }}** 43 | - Automatic release via GitHub Actions. 44 | - View commit history for more details. 45 | files: nupkg/*.nupkg 46 | draft: false 47 | prerelease: false 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /ESPTool.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.12.35707.178 d17.12 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EspDotNet", "ESPTool\EspDotNet.csproj", "{573E6BC7-AF1A-45EB-B682-685473F62437}" 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 | {573E6BC7-AF1A-45EB-B682-685473F62437}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {573E6BC7-AF1A-45EB-B682-685473F62437}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {573E6BC7-AF1A-45EB-B682-685473F62437}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {573E6BC7-AF1A-45EB-B682-685473F62437}.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 = {41E90229-CE52-4D2B-87B0-8EBF1D0A6368} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /ESPTool/ChipTypes.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet 2 | { 3 | public enum ChipTypes : uint 4 | { 5 | Unknown = 0, 6 | ESP32c6, 7 | ESP32c3, 8 | ESP32c2, 9 | ESP32, 10 | ESP8266, 11 | ESP32s3beta2, 12 | ESP32s3, 13 | ESP32s2, 14 | ESP32p4, 15 | ESP32h2beta2, 16 | ESP32h2beta1, 17 | ESP32h2, 18 | ESP32c6beta, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ESPTool/Commands/RequestCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace EspDotNet.Commands 6 | { 7 | public class RequestCommand 8 | { 9 | public byte Direction { get; set; } = 0; 10 | public ushort Size { get; set; } 11 | public uint Checksum { get; set; } 12 | public byte Command { get; set; } 13 | public bool ChecksumRequired { get; set; } 14 | public byte[] Payload { get; set; } = new byte[0]; 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /ESPTool/Commands/RequestCommandBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Commands 2 | { 3 | public class RequestCommandBuilder 4 | { 5 | private readonly RequestCommand _request; 6 | 7 | public RequestCommandBuilder() 8 | { 9 | _request = new RequestCommand(); 10 | } 11 | 12 | /// 13 | /// Sets the command. 14 | /// 15 | /// The command byte. 16 | public RequestCommandBuilder WithCommand(byte cmd) 17 | { 18 | _request.Command = cmd; 19 | return this; 20 | } 21 | 22 | /// 23 | /// Appends a byte array to the payload. 24 | /// 25 | public RequestCommandBuilder AppendPayload(byte[] payloadPart) 26 | { 27 | _request.Payload = _request.Payload.Concat(payloadPart).ToArray(); 28 | _request.Size = (ushort)_request.Payload.Length; 29 | return this; 30 | } 31 | 32 | /// 33 | /// Sets whether a checksum is required. 34 | /// 35 | /// True if a checksum is required, false otherwise. 36 | public RequestCommandBuilder RequiresChecksum(bool checksumRequired = true) 37 | { 38 | _request.ChecksumRequired = checksumRequired; 39 | return this; 40 | } 41 | 42 | /// 43 | /// Sets the direction byte. 44 | /// 45 | /// The direction byte. 46 | public RequestCommandBuilder WithDirection(byte direction) 47 | { 48 | _request.Direction = direction; 49 | return this; 50 | } 51 | 52 | /// 53 | /// Builds and returns the final RequestCMD object. 54 | /// 55 | public RequestCommand Build() 56 | { 57 | if (_request.ChecksumRequired) 58 | { 59 | CalculateChecksum(); 60 | } 61 | return _request; 62 | } 63 | 64 | /// 65 | /// Calculates the checksum for the payload if required. 66 | /// 67 | private void CalculateChecksum() 68 | { 69 | _request.Checksum = 0xEF; 70 | 71 | for (int i = 16; i < _request.Payload.Length; i++) 72 | { 73 | _request.Checksum ^= _request.Payload[i]; 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ESPTool/Commands/ResponseCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace EspDotNet.Commands 6 | { 7 | public partial class ResponseCommand 8 | { 9 | public byte Direction { get; set; } 10 | public byte Command { get; set; } 11 | public virtual ushort Size { get; set; } 12 | public uint Value { get; set; } 13 | public virtual byte[] Payload { get; set; } = new byte[0]; 14 | public bool Success { get; set; } 15 | public ResponseCommandStatus Error { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ESPTool/Commands/ResponseCommandStatus.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Commands 2 | { 3 | public enum ResponseCommandStatus : byte 4 | { 5 | NoError, 6 | Unknown, 7 | Invalid, //"Received message is invalid" (parameters or length field is invalid) 8 | Failed, //"Failed to act on received message" 9 | InvalidCRC, //"Invalid CRC in message" 10 | WriteError, //"flash write error" - after writing a block of data to flash, the ROM loader reads the value back and the 8-bit CRC is compared to the data read from flash. If they don't match, this error is returned. 11 | ReadError, //"flash read error" - SPI read failed 12 | ReadLenthError, //"flash read length error" - SPI read request length is too long 13 | DeflateError, //"Deflate error" (ESP32 compressed uploads only) 14 | BadBlockSize, 15 | FailedSPIOP, 16 | FailedSPIUnlock, 17 | NotInFlashMode, 18 | InflateError, 19 | NotEnoughData, 20 | TooMuchData, 21 | TaskCancelled, 22 | UnsupportedByLoader, 23 | UnsupportedByDevice, 24 | MD5Mismatch, 25 | WrongChip, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ESPTool/Communication/Communicator.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Config; 2 | using Microsoft.Extensions.Logging; 3 | using System; 4 | using System.Diagnostics; 5 | using System.IO.Ports; 6 | using System.Text.RegularExpressions; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace EspDotNet.Communication 12 | { 13 | public class Communicator : IDisposable 14 | { 15 | private readonly SerialPort _serialPort; 16 | private readonly SlipFraming _slipFraming; 17 | 18 | public Communicator() 19 | { 20 | _serialPort = new SerialPort(); 21 | _slipFraming = new SlipFraming(_serialPort); 22 | } 23 | 24 | /// 25 | /// Opens the serial port with the specified port name and baud rate. 26 | /// 27 | /// The name of the serial port to open. 28 | /// The baud rate for the communication. 29 | public void OpenSerial(string portName, int baudRate) 30 | { 31 | if (_serialPort.IsOpen && (_serialPort.PortName != portName || _serialPort.BaudRate != baudRate)) 32 | { 33 | _serialPort.Close(); 34 | } 35 | 36 | if (!_serialPort.IsOpen) 37 | { 38 | _serialPort.PortName = portName; 39 | _serialPort.BaudRate = baudRate; 40 | _serialPort.Open(); 41 | } 42 | } 43 | 44 | /// 45 | /// Closes the serial port. 46 | /// 47 | public void CloseSerial() 48 | { 49 | if (_serialPort.IsOpen) 50 | { 51 | _serialPort.Close(); 52 | } 53 | } 54 | 55 | /// 56 | /// Gets the current baud rate of the serial port. 57 | /// 58 | /// The baud rate of the serial port. 59 | public int GetBaudRate() => _serialPort.BaudRate; 60 | 61 | /// 62 | /// Changes the baud rate of the serial port. 63 | /// 64 | /// The new baud rate for the communication. 65 | public void ChangeBaudRate(int baudRate) 66 | { 67 | if (_serialPort.IsOpen) 68 | _serialPort.Close(); 69 | 70 | _serialPort.BaudRate = baudRate; 71 | _serialPort.Open(); 72 | 73 | } 74 | 75 | /// 76 | /// Clears the input buffer of the serial port. 77 | /// 78 | public void ClearBuffer() 79 | { 80 | if (_serialPort.IsOpen) 81 | { 82 | _serialPort.DiscardInBuffer(); 83 | } 84 | } 85 | 86 | /// 87 | /// Writes a SLIP-encoded frame asynchronously to the stream. 88 | /// 89 | /// The frame to send. 90 | /// Cancellation token to cancel the operation. 91 | /// A task representing the asynchronous operation. 92 | /// Thrown if the operation is canceled via the cancellation token. 93 | public async Task WriteFrameAsync(Frame frame, CancellationToken token) 94 | { 95 | await _slipFraming.WriteFrameAsync(frame, token); 96 | } 97 | 98 | /// 99 | /// Reads and decodes a SLIP-encoded frame asynchronously from the stream. 100 | /// Reads until the end of the frame is received. 101 | /// 102 | /// Cancellation token to cancel the operation. 103 | /// The frame received, or null if no frame is available. 104 | /// Thrown if the operation is canceled via the cancellation token. 105 | public async Task ReadFrameAsync(CancellationToken token) 106 | { 107 | return await _slipFraming.ReadFrameAsync(token); 108 | } 109 | 110 | public async Task ExecutePinSequence(List sequence, CancellationToken token) 111 | { 112 | foreach (var step in sequence) 113 | { 114 | if (step.Dtr != null) 115 | _serialPort.DtrEnable = step.Dtr.Value; 116 | 117 | if (step.Rts != null) 118 | { 119 | _serialPort.RtsEnable = step.Rts.Value; 120 | if (OperatingSystem.IsWindows()) 121 | _serialPort.DtrEnable = _serialPort.DtrEnable; 122 | } 123 | 124 | await Task.Delay(step.Delay, token); 125 | } 126 | } 127 | 128 | public async Task ReadRawAsync(byte[] buffer, CancellationToken token) 129 | { 130 | return await _serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length, token); 131 | } 132 | 133 | 134 | /// 135 | /// Disposes the serial port and associated resources. 136 | /// 137 | public void Dispose() 138 | { 139 | if (_serialPort.IsOpen) 140 | { 141 | _serialPort.Close(); 142 | } 143 | _serialPort.Dispose(); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /ESPTool/Communication/Frame.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Communication 2 | { 3 | public class Frame 4 | { 5 | public byte[] Data { get; set; } 6 | 7 | public Frame() 8 | { 9 | 10 | } 11 | public Frame(byte[] data) 12 | { 13 | Data = data; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ESPTool/Communication/SlipFraming.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.IO.Ports; 6 | using System.Linq; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace EspDotNet.Communication 11 | { 12 | /* In slipframing, the following rules apply: 13 | * 0xC0 => 0xDB 0xDC 14 | * 0xDC => 0xDB 0xDD 15 | */ 16 | 17 | public class SlipFraming 18 | { 19 | private const byte FrameDelimiter = 0xC0; 20 | private const byte EscapeByte = 0xDB; 21 | private const byte EscapeFrameDelimiter = 0xDC; 22 | private const byte EscapeEscapeByte = 0xDD; 23 | private readonly SerialPort _serialPort; 24 | 25 | public SlipFraming(SerialPort serialPort) 26 | { 27 | _serialPort = serialPort; 28 | } 29 | 30 | public async Task WriteFrameAsync(Frame frame, CancellationToken token) 31 | { 32 | byte[] escapedFrame = EscapeFrame(frame); 33 | _serialPort.BaseStream.WriteByte(FrameDelimiter); // Start of frame 34 | await _serialPort.BaseStream.WriteAsync(escapedFrame, 0, escapedFrame.Length, token); 35 | _serialPort.BaseStream.WriteByte(FrameDelimiter); // end of frame 36 | await _serialPort.BaseStream.FlushAsync(token); // Ensure all data is sent 37 | } 38 | 39 | public async Task ReadFrameAsync(CancellationToken token) 40 | { 41 | List escapedFrameBuffer = new List(); 42 | 43 | // In slipframing, all delimiters are replaced, so we can record everything between delimeters and decode it later 44 | while (true) 45 | { 46 | byte currentByte = await ReadByte(token); 47 | 48 | if (currentByte == FrameDelimiter) 49 | { 50 | // If we havent recieved any data yet, this is the SOF 51 | if (escapedFrameBuffer.Count > 0) 52 | return Unescape(escapedFrameBuffer.ToArray()); 53 | } 54 | else 55 | { 56 | escapedFrameBuffer.Add(currentByte); 57 | } 58 | } 59 | } 60 | 61 | private async Task ReadByte(CancellationToken token) 62 | { 63 | // Wait for data 64 | while (_serialPort.BytesToRead == 0) 65 | { 66 | // Prevent busy waiting 67 | await Task.Delay(10, token); 68 | } 69 | 70 | return (byte)_serialPort.ReadByte(); 71 | } 72 | 73 | private byte[] EscapeFrame(Frame frame) 74 | { 75 | List buffer = new(); 76 | 77 | foreach (byte b in frame.Data) 78 | { 79 | if (b == FrameDelimiter) 80 | { 81 | buffer.Add(EscapeByte); 82 | buffer.Add(EscapeFrameDelimiter); 83 | } 84 | else if (b == EscapeByte) 85 | { 86 | buffer.Add(EscapeByte); 87 | buffer.Add(EscapeEscapeByte); 88 | } 89 | else 90 | { 91 | buffer.Add(b); 92 | } 93 | } 94 | return buffer.ToArray(); 95 | } 96 | 97 | private Frame? Unescape(byte[] data) 98 | { 99 | List buffer = new List(); 100 | 101 | for (int i = 0; i < data.Length; i++) 102 | { 103 | if (data[i] == EscapeByte) 104 | { 105 | i++; 106 | if (i >= data.Length) break; 107 | 108 | if (data[i] == EscapeFrameDelimiter) 109 | { 110 | buffer.Add(FrameDelimiter); 111 | } 112 | else if (data[i] == EscapeEscapeByte) 113 | { 114 | buffer.Add(EscapeByte); 115 | } 116 | } 117 | else 118 | { 119 | buffer.Add(data[i]); 120 | } 121 | } 122 | 123 | return new Frame(buffer.ToArray()); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /ESPTool/Config/ConfigProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | 5 | namespace EspDotNet.Config 6 | { 7 | public static class ConfigProvider 8 | { 9 | private static readonly string EmbeddedResourcePrefix = $"{Assembly.GetExecutingAssembly().GetName().Name}.Resources.Config."; 10 | private static readonly string DevicesFolder = "Devices."; 11 | 12 | /// 13 | /// Loads the default ESPToolConfig from embedded resources. 14 | /// 15 | public static ESPToolConfig LoadDefaultConfig() 16 | { 17 | string resourceName = $"{EmbeddedResourcePrefix}ESPToolConfig.json"; 18 | 19 | try 20 | { 21 | string json = ReadEmbeddedJson(resourceName); 22 | var config = JsonSerializer.Deserialize(json) ?? new ESPToolConfig(); 23 | config.Devices = LoadDefaultDevices(); 24 | 25 | return config; 26 | } 27 | catch (Exception ex) 28 | { 29 | Console.WriteLine($"Failed to load tool config: {ex.Message}"); 30 | return new ESPToolConfig(); 31 | } 32 | } 33 | 34 | /// 35 | /// Loads all embedded device configurations. 36 | /// 37 | private static List LoadDefaultDevices() 38 | { 39 | var devices = new List(); 40 | 41 | foreach (var resourceName in GetEmbeddedDeviceConfigNames()) 42 | { 43 | try 44 | { 45 | devices.Add(LoadDeviceConfig(resourceName)); 46 | } 47 | catch (Exception ex) 48 | { 49 | Console.WriteLine($"Failed to load {resourceName}: {ex.Message}"); 50 | } 51 | } 52 | 53 | return devices; 54 | } 55 | 56 | /// 57 | /// Loads a single device configuration from an embedded JSON file. 58 | /// 59 | private static DeviceConfig LoadDeviceConfig(string resourceName) 60 | { 61 | var options = new JsonSerializerOptions 62 | { 63 | Converters = 64 | { 65 | new JsonStringEnumConverter() 66 | } 67 | }; 68 | string json = ReadEmbeddedJson(resourceName); 69 | return JsonSerializer.Deserialize(json, options) 70 | ?? throw new Exception($"Failed to deserialize JSON from resource: {resourceName}"); 71 | } 72 | 73 | /// 74 | /// Reads JSON data from an embedded resource. 75 | /// 76 | private static string ReadEmbeddedJson(string resourceName) 77 | { 78 | var assembly = Assembly.GetExecutingAssembly(); 79 | 80 | using Stream stream = assembly.GetManifestResourceStream(resourceName) 81 | ?? throw new Exception($"Embedded resource '{resourceName}' not found in assembly."); 82 | 83 | using StreamReader reader = new StreamReader(stream); 84 | return reader.ReadToEnd(); 85 | } 86 | 87 | /// 88 | /// Finds all embedded JSON files for devices. 89 | /// 90 | private static IEnumerable GetEmbeddedDeviceConfigNames() 91 | { 92 | var assembly = Assembly.GetExecutingAssembly(); 93 | return assembly.GetManifestResourceNames() 94 | .Where(name => name.StartsWith(EmbeddedResourcePrefix + DevicesFolder) && name.EndsWith(".json")); 95 | } 96 | } 97 | } 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ESPTool/Config/DeviceConfig.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Config 2 | { 3 | public class DeviceConfig 4 | { 5 | public ChipTypes ChipType { get; set; } 6 | public int RamBlockSize { get; set; } 7 | public int FlashBlockSize { get; set; } 8 | public int MagicRegisterValue { get; set; } 9 | public Dictionary EFlags { get; set; } = new Dictionary(); 10 | 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ESPTool/Config/EFuseMapping.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Config 2 | { 3 | public class EFuseMapping 4 | { 5 | public uint Address { get; set; } 6 | public int Size { get; set; } 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /ESPTool/Config/ESPToolConfig.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Tools.Firmware; 2 | 3 | namespace EspDotNet.Config 4 | { 5 | public class ESPToolConfig 6 | { 7 | public List Devices { get; set; } = []; 8 | public List BootloaderSequence { get; set; } = []; 9 | public List ResetSequence { get; set; } = []; 10 | } 11 | } 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ESPTool/Config/PinSequenceStep.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Config 2 | { 3 | public class PinSequenceStep 4 | { 5 | public bool? Dtr { get; set; } 6 | 7 | public bool? Rts { get; set; } 8 | 9 | public TimeSpan Delay { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ESPTool/EFlagKey.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Config 2 | { 3 | public enum EFlagKey 4 | { 5 | BaseMacAddress, 6 | } 7 | 8 | } 9 | -------------------------------------------------------------------------------- /ESPTool/ESPToolbox.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Communication; 2 | using EspDotNet.Config; 3 | using EspDotNet.Loaders.SoftLoader; 4 | using EspDotNet.Loaders; 5 | using EspDotNet.Tools.Firmware; 6 | using EspDotNet.Tools; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace EspDotNet 10 | { 11 | public class ESPToolbox 12 | { 13 | private readonly ESPToolConfig _config; 14 | 15 | public ESPToolbox() 16 | { 17 | _config = ConfigProvider.LoadDefaultConfig(); 18 | } 19 | 20 | public ESPToolbox(ESPToolConfig config) 21 | { 22 | _config = config; 23 | } 24 | 25 | public Communicator CreateCommunicator() 26 | { 27 | return new Communicator(); 28 | } 29 | 30 | public void OpenSerial(Communicator communicator, string portName, int baudRate) 31 | { 32 | communicator.OpenSerial(portName, baudRate); 33 | } 34 | 35 | public void CloseSerial(Communicator communicator) 36 | { 37 | communicator.CloseSerial(); 38 | } 39 | 40 | public async Task StartBootloaderAsync(Communicator communicator, CancellationToken token = default) 41 | { 42 | var bootloader = new BootloaderTool(communicator, _config.BootloaderSequence); 43 | return await bootloader.StartAsync(token); 44 | } 45 | 46 | public async Task DetectChipTypeAsync(ILoader loader, CancellationToken token = default) 47 | { 48 | var detectTool = new ChipTypeDetectTool(loader, _config); 49 | return await detectTool.DetectChipTypeAsync(token); 50 | } 51 | 52 | public async Task StartSoftloaderAsync( 53 | Communicator communicator, 54 | ILoader bootloader, 55 | ChipTypes chipType, 56 | CancellationToken token = default) 57 | { 58 | var deviceConfig = GetDeviceConfig(chipType); 59 | var firmwareProvider = DefaultFirmwareProviders.GetSoftloaderForDevice(chipType); 60 | var uploadTool = new UploadRamTool(bootloader) 61 | { 62 | BlockSize = (uint)deviceConfig.FlashBlockSize 63 | }; 64 | var softloaderTool = new SoftloaderTool(communicator, uploadTool, firmwareProvider); 65 | return await softloaderTool.StartAsync(token); 66 | } 67 | 68 | public async Task ChangeBaudAsync(Communicator communicator, ILoader loader, int baudRate, CancellationToken token = default) 69 | { 70 | var baudTool = new ChangeBaudrateTool(communicator, loader); 71 | await baudTool.ChangeBaudAsync(baudRate, token); 72 | } 73 | 74 | public async Task EraseFlashAsync(SoftLoader loader, CancellationToken token = default) 75 | { 76 | var eraseTool = new FlashEraseTool(loader); 77 | await eraseTool.EraseFlashAsync(token); 78 | } 79 | 80 | public async Task ResetDeviceAsync(Communicator communicator, CancellationToken token = default) 81 | { 82 | var sequence = _config.ResetSequence ?? throw new InvalidOperationException("No reset sequence in config"); 83 | var resetTool = new ResetDeviceTool(communicator, sequence); 84 | await resetTool.ResetAsync(token); 85 | } 86 | 87 | public async Task ReadEfuseAsync(ILoader loader, ChipTypes chipType, EFlagKey key, CancellationToken token = default) 88 | { 89 | var tool = new EFuseTool(loader, GetDeviceConfig(chipType)); 90 | return await tool.ReadAsync(key, token); 91 | } 92 | 93 | public IUploadTool CreateUploadRamTool(ILoader loader, ChipTypes chipType) 94 | { 95 | return new UploadRamTool(loader) 96 | { 97 | BlockSize = (uint)GetDeviceConfig(chipType).FlashBlockSize 98 | }; 99 | } 100 | 101 | public IUploadTool CreateUploadFlashTool(ILoader loader, ChipTypes chipType) 102 | { 103 | return new UploadFlashTool(loader) 104 | { 105 | BlockSize = (uint)GetDeviceConfig(chipType).FlashBlockSize 106 | }; 107 | } 108 | 109 | public IUploadTool CreateUploadFlashDeflatedTool(SoftLoader loader, ChipTypes chipType) 110 | { 111 | return new UploadFlashDeflatedTool(loader) 112 | { 113 | BlockSize = (uint)GetDeviceConfig(chipType).FlashBlockSize 114 | }; 115 | } 116 | 117 | public async Task UploadFirmwareAsync( 118 | IUploadTool uploadTool, 119 | IFirmwareProvider firmware, 120 | CancellationToken token = default, 121 | IProgress? progress = null) 122 | { 123 | var firmwareTool = new FirmwareUploadTool(uploadTool) 124 | { 125 | Progress = progress ?? new Progress() 126 | }; 127 | 128 | await firmwareTool.UploadFirmwareAsync(firmware, token); 129 | } 130 | 131 | public async Task UploadFirmwareAndExecuteAsync( 132 | IUploadTool uploadTool, 133 | IFirmwareProvider firmware, 134 | Communicator communicator, 135 | CancellationToken token = default, 136 | IProgress? progress = null) 137 | { 138 | await UploadFirmwareAsync(uploadTool, firmware, token, progress); 139 | await ResetDeviceAsync(communicator, token); 140 | } 141 | 142 | private DeviceConfig GetDeviceConfig(ChipTypes chipType) 143 | { 144 | return _config.Devices.FirstOrDefault(d => d.ChipType == chipType) 145 | ?? throw new InvalidOperationException($"No device config found for {chipType}"); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /ESPTool/EspDotNet.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | ESPTool 5 | net8.0 6 | enable 7 | enable 8 | Bas Visscher 9 | Koole controls 10 | https://github.com/KooleControls/ESPTool 11 | Git 12 | ESP32 13 | latest 14 | README.md 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /ESPTool/Example.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Tools.Firmware; 2 | using EspDotNet; 3 | using System.Diagnostics; 4 | using System.Threading; 5 | using System; 6 | 7 | public class Example 8 | { 9 | 10 | public async Task UploadFirmwareAsync(CancellationToken token = default) 11 | { 12 | var toolbox = new ESPToolbox(); 13 | var communicator = toolbox.CreateCommunicator(); 14 | toolbox.OpenSerial(communicator, "COM30", 115200); 15 | 16 | var loader = await toolbox.StartBootloaderAsync(communicator); 17 | var chipType = await toolbox.DetectChipTypeAsync(loader); 18 | 19 | var softloader = await toolbox.StartSoftloaderAsync(communicator, loader, chipType); 20 | await toolbox.ChangeBaudAsync(communicator, softloader, 921600); 21 | 22 | var uploadTool = toolbox.CreateUploadFlashDeflatedTool(softloader, chipType); 23 | var myFirmware = GetFirmware(); 24 | var progress = new Progress(p => Debug.WriteLine($"Upload progress: {p:P0}")); 25 | 26 | await toolbox.UploadFirmwareAsync(uploadTool, myFirmware, token, progress); 27 | await toolbox.ResetDeviceAsync(communicator); 28 | } 29 | 30 | 31 | private IFirmwareProvider GetFirmware() 32 | { 33 | return new FirmwareProvider( 34 | entryPoint: 0x00000000, 35 | segments: 36 | [ 37 | new FirmwareSegmentProvider(0x00001000, File.ReadAllBytes("bootloader.bin")), 38 | new FirmwareSegmentProvider(0x00008000, File.ReadAllBytes("partition-table.bin")), 39 | new FirmwareSegmentProvider(0x0000F000, File.ReadAllBytes("ota_data_initial.bin")), 40 | new FirmwareSegmentProvider(0x00800000, File.ReadAllBytes("application.bin")), 41 | ] 42 | ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /ESPTool/Loaders/ESP32BootLoader/BootLoaderCommandExecutor.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Commands; 2 | using EspDotNet.Communication; 3 | 4 | namespace EspDotNet.Loaders.ESP32BootLoader 5 | { 6 | public class BootLoaderCommandExecutor 7 | { 8 | protected readonly Communicator _communicator; 9 | 10 | public BootLoaderCommandExecutor(Communicator communicator) 11 | { 12 | _communicator = communicator; 13 | } 14 | 15 | /// 16 | /// Sends a request frame and waits for a response frame. 17 | /// 18 | /// Thrown if the operation is canceled via the token. 19 | public async Task ExecuteCommandAsync(RequestCommand requestCommand, CancellationToken token) 20 | { 21 | _communicator.ClearBuffer(); 22 | 23 | // Convert the RequestCommand to a Frame 24 | Frame requestFrame = RequestToFrame(requestCommand); 25 | 26 | // Write the frame to the communicator 27 | await _communicator.WriteFrameAsync(requestFrame, token); 28 | 29 | // Read the response frame 30 | Frame responseFrame = await _communicator.ReadFrameAsync(token) ?? throw new Exception("No frame received"); 31 | 32 | // Convert the response frame back to a ResponseCommand 33 | var response = FrameToResponse(responseFrame); 34 | 35 | // Check 36 | if (response.Command != requestCommand.Command) 37 | { 38 | throw new Exception("Response didnt match"); 39 | } 40 | return response; 41 | } 42 | 43 | private static Frame RequestToFrame(RequestCommand command) 44 | { 45 | List raw = new List 46 | { 47 | command.Direction, 48 | command.Command 49 | }; 50 | raw.AddRange(BitConverter.GetBytes(command.Size)); 51 | raw.AddRange(BitConverter.GetBytes(command.Checksum)); 52 | raw.AddRange(command.Payload); 53 | return new Frame(raw.ToArray()); 54 | } 55 | 56 | private static ResponseCommand FrameToResponse(Frame frame) 57 | { 58 | ResponseCommand response = new ResponseCommand(); 59 | try 60 | { 61 | response.Direction = frame.Data[0]; 62 | response.Command = frame.Data[1]; 63 | response.Size = BitConverter.ToUInt16(frame.Data, 2); 64 | response.Value = BitConverter.ToUInt32(frame.Data, 4); 65 | response.Payload = frame.Data.Skip(8).ToArray(); 66 | response.Success = response.Payload[response.Size - 4] == 0; 67 | BootLoaderResponseStatus status = (BootLoaderResponseStatus)response.Payload[response.Size - 3]; 68 | response.Error = GeneralizeResponseStatus(status); 69 | } 70 | catch 71 | { 72 | response.Success = false; 73 | } 74 | return response; 75 | } 76 | 77 | 78 | private static ResponseCommandStatus GeneralizeResponseStatus(BootLoaderResponseStatus err) 79 | { 80 | return err switch 81 | { 82 | BootLoaderResponseStatus.Invalid => ResponseCommandStatus.Invalid, 83 | BootLoaderResponseStatus.Failed => ResponseCommandStatus.Failed, 84 | BootLoaderResponseStatus.InvalidCRC => ResponseCommandStatus.InvalidCRC, 85 | BootLoaderResponseStatus.WriteError => ResponseCommandStatus.WriteError, 86 | BootLoaderResponseStatus.ReadError => ResponseCommandStatus.ReadError, 87 | BootLoaderResponseStatus.ReadLenthError => ResponseCommandStatus.ReadLenthError, 88 | BootLoaderResponseStatus.DeflateError => ResponseCommandStatus.DeflateError, 89 | _ => ResponseCommandStatus.Unknown, 90 | }; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ESPTool/Loaders/ESP32BootLoader/BootLoaderResponseStatus.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Loaders.ESP32BootLoader 2 | { 3 | public enum BootLoaderResponseStatus 4 | { 5 | Invalid = 0x05, 6 | Failed = 0x06, 7 | InvalidCRC = 0x07, 8 | WriteError = 0x08, 9 | ReadError = 0x09, 10 | ReadLenthError = 0x0a, 11 | DeflateError = 0x0b, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ESPTool/Loaders/ESP32BootLoader/ESP32Loader.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Commands; 2 | using EspDotNet.Communication; 3 | using EspDotNet.Loaders; 4 | using System; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace EspDotNet.Loaders.ESP32BootLoader 9 | { 10 | public class ESP32BootLoader : ILoader 11 | { 12 | private readonly Communicator _communicator; 13 | private readonly BootLoaderCommandExecutor _commandExecutor; 14 | 15 | public ESP32BootLoader(Communicator communicator) 16 | { 17 | _communicator = communicator; 18 | _commandExecutor = new BootLoaderCommandExecutor(communicator); 19 | } 20 | 21 | 22 | /// 23 | /// Begins the flash process. 24 | /// 25 | public async Task FlashBeginAsync(uint size, uint blocks, uint blockSize, uint offset, CancellationToken token) 26 | { 27 | var request = new RequestCommandBuilder() 28 | .WithCommand(0x02) 29 | .AppendPayload(BitConverter.GetBytes(size)) 30 | .AppendPayload(BitConverter.GetBytes(blocks)) 31 | .AppendPayload(BitConverter.GetBytes(blockSize)) 32 | .AppendPayload(BitConverter.GetBytes(offset)) 33 | .Build(); 34 | 35 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 36 | if (response.Success != true) 37 | throw new Exception($"FlashBegin failed {response.Error}"); 38 | } 39 | 40 | /// 41 | /// Sends flash data. 42 | /// 43 | public async Task FlashDataAsync(byte[] blockData, uint seq, CancellationToken token) 44 | { 45 | var request = new RequestCommandBuilder() 46 | .WithCommand(0x03) 47 | .RequiresChecksum() 48 | .AppendPayload(BitConverter.GetBytes(blockData.Length)) 49 | .AppendPayload(BitConverter.GetBytes(seq)) 50 | .AppendPayload(BitConverter.GetBytes(0)) 51 | .AppendPayload(BitConverter.GetBytes(0)) 52 | .AppendPayload(blockData) 53 | .Build(); 54 | 55 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 56 | if (response.Success != true) 57 | throw new Exception($"FlashData failed {response.Error}"); 58 | } 59 | 60 | /// 61 | /// Ends the flash process. 62 | /// 63 | public async Task FlashEndAsync(uint execute, uint entryPoint, CancellationToken token) 64 | { 65 | var request = new RequestCommandBuilder() 66 | .WithCommand(0x04) 67 | .AppendPayload(BitConverter.GetBytes(execute)) 68 | .AppendPayload(BitConverter.GetBytes(entryPoint)) 69 | .Build(); 70 | 71 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 72 | if (response.Success != true) 73 | throw new Exception($"FlashEnd failed {response.Error}"); 74 | } 75 | 76 | 77 | /// 78 | /// Begins memory upload. 79 | /// 80 | public async Task MemBeginAsync(uint size, uint blocks, uint blockSize, uint offset, CancellationToken token) 81 | { 82 | var request = new RequestCommandBuilder() 83 | .WithCommand(0x05) 84 | .AppendPayload(BitConverter.GetBytes(size)) 85 | .AppendPayload(BitConverter.GetBytes(blocks)) 86 | .AppendPayload(BitConverter.GetBytes(blockSize)) 87 | .AppendPayload(BitConverter.GetBytes(offset)) 88 | .Build(); 89 | 90 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 91 | if (response.Success != true) 92 | throw new Exception($"MemBegin failed {response.Error}"); 93 | } 94 | 95 | /// 96 | /// Ends memory upload. 97 | /// 98 | public async Task MemEndAsync(uint execute, uint entryPoint, CancellationToken token) 99 | { 100 | var request = new RequestCommandBuilder() 101 | .WithCommand(0x06) 102 | .AppendPayload(BitConverter.GetBytes(execute)) 103 | .AppendPayload(BitConverter.GetBytes(entryPoint)) 104 | .Build(); 105 | 106 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 107 | if (response.Success != true) 108 | throw new Exception($"MemEnd failed {response.Error}"); 109 | } 110 | 111 | /// 112 | /// Sends memory data. 113 | /// 114 | public async Task MemDataAsync(byte[] blockData, uint seq, CancellationToken token) 115 | { 116 | var request = new RequestCommandBuilder() 117 | .WithCommand(0x07) 118 | .RequiresChecksum() 119 | .AppendPayload(BitConverter.GetBytes(blockData.Length)) 120 | .AppendPayload(BitConverter.GetBytes(seq)) 121 | .AppendPayload(BitConverter.GetBytes(0)) 122 | .AppendPayload(BitConverter.GetBytes(0)) 123 | .AppendPayload(blockData) 124 | .Build(); 125 | 126 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 127 | if (response.Success != true) 128 | throw new Exception($"MemData failed {response.Error}"); 129 | } 130 | 131 | /// 132 | /// Synchronizes with the loader. 133 | /// 134 | public async Task SynchronizeAsync(CancellationToken token) 135 | { 136 | var request = new RequestCommandBuilder() 137 | .WithCommand(0x08) 138 | .AppendPayload(new byte[] { 0x07, 0x07, 0x12, 0x20, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }) 139 | .Build(); 140 | 141 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 142 | return response.Success; 143 | } 144 | 145 | public async Task ReadRegisterAsync(uint address, CancellationToken token) 146 | { 147 | var request = new RequestCommandBuilder() 148 | .WithCommand(0x0a) 149 | .AppendPayload(BitConverter.GetBytes(address)) 150 | .Build(); 151 | 152 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 153 | if (response.Success != true) 154 | throw new Exception($"Reading register failed {response.Error}"); 155 | 156 | return response.Value; 157 | } 158 | 159 | /// 160 | /// Changes the baud rate for communication in ESP32. 161 | /// 162 | /// The new baud rate to set. 163 | /// Cancellation token for the operation. 164 | /// Thrown if the operation is canceled via the token. 165 | public async Task ChangeBaudAsync(int baud, int oldBaud, CancellationToken token) 166 | { 167 | var request = new RequestCommandBuilder() 168 | .WithCommand(0x0F) 169 | .AppendPayload(BitConverter.GetBytes(baud)) 170 | .AppendPayload(BitConverter.GetBytes(0)) // Adding second parameter with value 0 171 | .Build(); 172 | 173 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 174 | if (response?.Success != true) 175 | throw new InvalidOperationException("Failed to change baud rate."); 176 | } 177 | } 178 | } 179 | 180 | -------------------------------------------------------------------------------- /ESPTool/Loaders/ILoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace EspDotNet.Loaders 6 | { 7 | /// 8 | /// Base interface for all loaders. 9 | /// 10 | public interface ILoader 11 | { 12 | Task ReadRegisterAsync(uint address, CancellationToken token); 13 | Task ChangeBaudAsync(int baud, int oldBaud, CancellationToken token); 14 | 15 | Task FlashBeginAsync(uint size, uint blocks, uint blockSize, uint offset, CancellationToken token); 16 | Task FlashDataAsync(byte[] blockData, uint seq, CancellationToken token); 17 | Task FlashEndAsync(uint execute, uint entryPoint, CancellationToken token); 18 | 19 | Task MemBeginAsync(uint size, uint blocks, uint blockSize, uint offset, CancellationToken token); 20 | Task MemDataAsync(byte[] blockData, uint seq, CancellationToken token); 21 | Task MemEndAsync(uint execute, uint entryPoint, CancellationToken token); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ESPTool/Loaders/SoftLoader/SoftLoader.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Commands; 2 | using EspDotNet.Communication; 3 | using EspDotNet.Loaders; 4 | using System; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace EspDotNet.Loaders.SoftLoader 9 | { 10 | public class SoftLoader : ILoader 11 | { 12 | private readonly byte[] OHAI = { 0x4F, 0x48, 0x41, 0x49 }; 13 | protected readonly Communicator _communicator; 14 | protected readonly SoftLoaderCommandExecutor _commandExecutor; 15 | 16 | public SoftLoader(Communicator communicator) 17 | { 18 | _communicator = communicator; 19 | _commandExecutor = new SoftLoaderCommandExecutor(communicator); 20 | } 21 | 22 | /// 23 | /// Changes the baud rate for communication in the SoftLoader. 24 | /// 25 | /// The new baud rate to set. 26 | /// The current baud rate. 27 | /// Cancellation token for the operation. 28 | /// Thrown if the operation is canceled via the token. 29 | public async Task ChangeBaudAsync(int baud, int oldBaud, CancellationToken token) 30 | { 31 | var request = new RequestCommandBuilder() 32 | .WithCommand(0x0F) 33 | .AppendPayload(BitConverter.GetBytes(baud)) 34 | .AppendPayload(BitConverter.GetBytes(oldBaud)) 35 | .Build(); 36 | 37 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 38 | if (!response.Success) 39 | throw new InvalidOperationException("Failed to change baud rate."); 40 | } 41 | 42 | /// 43 | /// Calculates and verifies the MD5 checksum of a given flash region. 44 | /// 45 | /// Thrown if the operation is canceled via the token. 46 | public async Task SPI_FLASH_MD5(uint address, uint size, CancellationToken token) 47 | { 48 | var request = new RequestCommandBuilder() 49 | .WithCommand(0x13) 50 | .AppendPayload(BitConverter.GetBytes(address)) 51 | .AppendPayload(BitConverter.GetBytes(size)) 52 | .AppendPayload(BitConverter.GetBytes(0)) 53 | .AppendPayload(BitConverter.GetBytes(0)) 54 | .Build(); 55 | 56 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 57 | if (!response.Success) 58 | throw new InvalidOperationException("Failed to compute MD5 checksum."); 59 | 60 | return response.Payload.Take(16).ToArray(); // Return the MD5 checksum (first 16 bytes) 61 | } 62 | 63 | /// 64 | /// Begins the flash process using compressed data. 65 | /// 66 | public async Task FlashDeflBeginAsync(uint size, uint blocks, uint blockSize, uint offset, CancellationToken token) 67 | { 68 | var request = new RequestCommandBuilder() 69 | .WithCommand(0x10) 70 | .AppendPayload(BitConverter.GetBytes(size)) 71 | .AppendPayload(BitConverter.GetBytes(blocks)) 72 | .AppendPayload(BitConverter.GetBytes(blockSize)) 73 | .AppendPayload(BitConverter.GetBytes(offset)) 74 | .Build(); 75 | 76 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 77 | if (!response.Success) 78 | throw new InvalidOperationException("Failed to begin flash with compressed data."); 79 | } 80 | 81 | /// 82 | /// Sends compressed flash data. 83 | /// 84 | public async Task FlashDeflDataAsync(byte[] blockData, uint seq, CancellationToken token) 85 | { 86 | var request = new RequestCommandBuilder() 87 | .WithCommand(0x11) 88 | .RequiresChecksum() 89 | .AppendPayload(BitConverter.GetBytes(blockData.Length)) 90 | .AppendPayload(BitConverter.GetBytes(seq)) 91 | .AppendPayload(BitConverter.GetBytes(0)) 92 | .AppendPayload(BitConverter.GetBytes(0)) 93 | .AppendPayload(blockData) 94 | .Build(); 95 | 96 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 97 | if (!response.Success) 98 | throw new InvalidOperationException("Failed to send compressed flash data."); 99 | } 100 | 101 | /// 102 | /// Ends the flash process using compressed data. 103 | /// 104 | public async Task FlashDeflEndAsync(uint executeFlags, uint entryPoint, CancellationToken token) 105 | { 106 | var request = new RequestCommandBuilder() 107 | .WithCommand(0x12) 108 | .AppendPayload(BitConverter.GetBytes(executeFlags)) 109 | .AppendPayload(BitConverter.GetBytes(entryPoint)) 110 | .Build(); 111 | 112 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 113 | if (!response.Success) 114 | throw new InvalidOperationException("Failed to end flash with compressed data."); 115 | } 116 | 117 | /// 118 | /// Erases the entire flash memory. 119 | /// 120 | public async Task EraseFlashAsync(CancellationToken token) 121 | { 122 | var request = new RequestCommandBuilder() 123 | .WithCommand(0xD0) 124 | .Build(); 125 | 126 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 127 | if (!response.Success) 128 | throw new InvalidOperationException("Failed to erase flash memory."); 129 | } 130 | 131 | 132 | 133 | 134 | #region Supported by software loader and ROM loaders 135 | 136 | /// 137 | /// Begins the flash process. 138 | /// 139 | public virtual async Task FlashBeginAsync(uint size, uint blocks, uint blockSize, uint offset, CancellationToken token) 140 | { 141 | var request = new RequestCommandBuilder() 142 | .WithCommand(0x02) 143 | .AppendPayload(BitConverter.GetBytes(size)) 144 | .AppendPayload(BitConverter.GetBytes(blocks)) 145 | .AppendPayload(BitConverter.GetBytes(blockSize)) 146 | .AppendPayload(BitConverter.GetBytes(offset)) 147 | .Build(); 148 | 149 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 150 | if (response.Success != true) 151 | throw new Exception($"FlashBegin failed {response.Error}"); 152 | } 153 | 154 | /// 155 | /// Sends flash data. 156 | /// 157 | public virtual async Task FlashDataAsync(byte[] blockData, uint seq, CancellationToken token) 158 | { 159 | var request = new RequestCommandBuilder() 160 | .WithCommand(0x03) 161 | .RequiresChecksum() 162 | .AppendPayload(BitConverter.GetBytes(blockData.Length)) 163 | .AppendPayload(BitConverter.GetBytes(seq)) 164 | .AppendPayload(BitConverter.GetBytes(0)) 165 | .AppendPayload(BitConverter.GetBytes(0)) 166 | .AppendPayload(blockData) 167 | .Build(); 168 | 169 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 170 | if (response.Success != true) 171 | throw new Exception($"FlashData failed {response.Error}"); 172 | } 173 | 174 | /// 175 | /// Ends the flash process. 176 | /// 177 | public virtual async Task FlashEndAsync(uint execute, uint entryPoint, CancellationToken token) 178 | { 179 | var request = new RequestCommandBuilder() 180 | .WithCommand(0x04) 181 | .AppendPayload(BitConverter.GetBytes(execute)) 182 | .AppendPayload(BitConverter.GetBytes(entryPoint)) 183 | .Build(); 184 | 185 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 186 | if (response.Success != true) 187 | throw new Exception($"FlashEnd failed {response.Error}"); 188 | } 189 | 190 | 191 | /// 192 | /// Begins memory upload. 193 | /// 194 | public virtual async Task MemBeginAsync(uint size, uint blocks, uint blockSize, uint offset, CancellationToken token) 195 | { 196 | var request = new RequestCommandBuilder() 197 | .WithCommand(0x05) 198 | .AppendPayload(BitConverter.GetBytes(size)) 199 | .AppendPayload(BitConverter.GetBytes(blocks)) 200 | .AppendPayload(BitConverter.GetBytes(blockSize)) 201 | .AppendPayload(BitConverter.GetBytes(offset)) 202 | .Build(); 203 | 204 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 205 | if (response.Success != true) 206 | throw new Exception($"MemBegin failed {response.Error}"); 207 | } 208 | 209 | /// 210 | /// Ends memory upload. 211 | /// 212 | public virtual async Task MemEndAsync(uint execute, uint entryPoint, CancellationToken token) 213 | { 214 | var request = new RequestCommandBuilder() 215 | .WithCommand(0x06) 216 | .AppendPayload(BitConverter.GetBytes(execute)) 217 | .AppendPayload(BitConverter.GetBytes(entryPoint)) 218 | .Build(); 219 | 220 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 221 | if (response.Success != true) 222 | throw new Exception($"MemEnd failed {response.Error}"); 223 | } 224 | 225 | /// 226 | /// Sends memory data. 227 | /// 228 | public virtual async Task MemDataAsync(byte[] blockData, uint seq, CancellationToken token) 229 | { 230 | var request = new RequestCommandBuilder() 231 | .WithCommand(0x07) 232 | .RequiresChecksum() 233 | .AppendPayload(BitConverter.GetBytes(blockData.Length)) 234 | .AppendPayload(BitConverter.GetBytes(seq)) 235 | .AppendPayload(BitConverter.GetBytes(0)) 236 | .AppendPayload(BitConverter.GetBytes(0)) 237 | .AppendPayload(blockData) 238 | .Build(); 239 | 240 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 241 | if (response.Success != true) 242 | throw new Exception($"MemData failed {response.Error}"); 243 | } 244 | 245 | public virtual async Task ReadRegisterAsync(uint address, CancellationToken token) 246 | { 247 | var request = new RequestCommandBuilder() 248 | .WithCommand(0x0a) 249 | .AppendPayload(BitConverter.GetBytes(address)) 250 | .Build(); 251 | 252 | var response = await _commandExecutor.ExecuteCommandAsync(request, token); 253 | if (response.Success != true) 254 | throw new Exception($"Reading register failed {response.Error}"); 255 | 256 | return response.Value; 257 | } 258 | #endregion 259 | 260 | #region Misc 261 | 262 | /// 263 | /// Waits for the OHAI message. 264 | /// 265 | public async Task WaitForOHAIAsync(CancellationToken token) 266 | { 267 | Frame? frame = await _communicator.ReadFrameAsync(token); 268 | 269 | while (frame?.Data.SequenceEqual(OHAI) != true) 270 | { 271 | frame = await _communicator.ReadFrameAsync(token); 272 | } 273 | } 274 | 275 | #endregion 276 | 277 | 278 | } 279 | } -------------------------------------------------------------------------------- /ESPTool/Loaders/SoftLoader/SoftLoaderCommandExecutor.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Commands; 2 | using EspDotNet.Communication; 3 | 4 | namespace EspDotNet.Loaders.SoftLoader 5 | { 6 | 7 | public class SoftLoaderCommandExecutor 8 | { 9 | protected readonly Communicator _communicator; 10 | 11 | public SoftLoaderCommandExecutor(Communicator communicator) 12 | { 13 | _communicator = communicator; 14 | } 15 | 16 | /// 17 | /// Sends a request frame and waits for a response frame. 18 | /// 19 | /// Thrown if the operation is canceled via the token. 20 | public async Task ExecuteCommandAsync(RequestCommand requestCommand, CancellationToken token) 21 | { 22 | _communicator.ClearBuffer(); 23 | 24 | // Convert the RequestCommand to a Frame 25 | Frame requestFrame = RequestToFrame(requestCommand); 26 | 27 | // Write the frame to the communicator 28 | await _communicator.WriteFrameAsync(requestFrame, token); 29 | 30 | // Read the response frame 31 | Frame responseFrame = await _communicator.ReadFrameAsync(token) ?? throw new Exception("No frame received"); 32 | 33 | // Convert the response frame back to a ResponseCommand 34 | var response = FrameToResponse(responseFrame); 35 | 36 | // Check 37 | if (response.Command != requestCommand.Command) 38 | { 39 | throw new Exception("Response didnt match"); 40 | } 41 | return response; 42 | } 43 | 44 | private static Frame RequestToFrame(RequestCommand command) 45 | { 46 | List raw = new List 47 | { 48 | command.Direction, 49 | command.Command 50 | }; 51 | raw.AddRange(BitConverter.GetBytes(command.Size)); 52 | raw.AddRange(BitConverter.GetBytes(command.Checksum)); 53 | raw.AddRange(command.Payload); 54 | return new Frame(raw.ToArray()); 55 | } 56 | 57 | 58 | 59 | private static ResponseCommand FrameToResponse(Frame frame) 60 | { 61 | ResponseCommand response = new ResponseCommand(); 62 | try 63 | { 64 | response.Direction = frame.Data[0]; 65 | response.Command = frame.Data[1]; 66 | response.Size = BitConverter.ToUInt16(frame.Data, 2); 67 | response.Value = BitConverter.ToUInt32(frame.Data, 4); 68 | response.Payload = frame.Data.Skip(8).ToArray(); 69 | 70 | //These 2 fields are switched around when compared to the documentation. 71 | response.Success = response.Payload[response.Size - 1] == 0; 72 | SoftLoaderResponseStatus status = (SoftLoaderResponseStatus)response.Payload[response.Size - 2]; 73 | response.Error = GeneralizeResponseStatus(status); 74 | 75 | if (response.Error != ResponseCommandStatus.NoError) 76 | { 77 | response.Success = false; 78 | } 79 | } 80 | catch 81 | { 82 | response.Success = false; 83 | } 84 | return response; 85 | } 86 | 87 | private static ResponseCommandStatus GeneralizeResponseStatus(SoftLoaderResponseStatus err) 88 | { 89 | return err switch 90 | { 91 | SoftLoaderResponseStatus.ESP_OK => ResponseCommandStatus.NoError, 92 | SoftLoaderResponseStatus.ESP_BAD_DATA_LEN => ResponseCommandStatus.Invalid, 93 | SoftLoaderResponseStatus.ESP_BAD_DATA_CHECKSUM => ResponseCommandStatus.InvalidCRC, 94 | SoftLoaderResponseStatus.ESP_BAD_BLOCKSIZE => ResponseCommandStatus.BadBlockSize, 95 | SoftLoaderResponseStatus.ESP_INVALID_COMMAND => ResponseCommandStatus.Failed, 96 | SoftLoaderResponseStatus.ESP_FAILED_SPI_OP => ResponseCommandStatus.FailedSPIOP, 97 | SoftLoaderResponseStatus.ESP_FAILED_SPI_UNLOCK => ResponseCommandStatus.FailedSPIUnlock, 98 | SoftLoaderResponseStatus.ESP_NOT_IN_FLASH_MODE => ResponseCommandStatus.NotInFlashMode, 99 | SoftLoaderResponseStatus.ESP_INFLATE_ERROR => ResponseCommandStatus.InflateError, 100 | SoftLoaderResponseStatus.ESP_NOT_ENOUGH_DATA => ResponseCommandStatus.NotEnoughData, 101 | SoftLoaderResponseStatus.ESP_TOO_MUCH_DATA => ResponseCommandStatus.TooMuchData, 102 | SoftLoaderResponseStatus.ESP_CMD_NOT_IMPLEMENTED => ResponseCommandStatus.Failed, 103 | _ => ResponseCommandStatus.Unknown, 104 | }; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /ESPTool/Loaders/SoftLoader/SoftLoaderResponseStatus.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Loaders.SoftLoader 2 | { 3 | //https://github.com/espressif/esptool/blob/master/flasher_stub/include/stub_flasher.h#L95 4 | public enum SoftLoaderResponseStatus 5 | { 6 | ESP_OK = 0, 7 | ESP_BAD_DATA_LEN = 0xC0, 8 | ESP_BAD_DATA_CHECKSUM = 0xC1, 9 | ESP_BAD_BLOCKSIZE = 0xC2, 10 | ESP_INVALID_COMMAND = 0xC3, 11 | ESP_FAILED_SPI_OP = 0xC4, 12 | ESP_FAILED_SPI_UNLOCK = 0xC5, 13 | ESP_NOT_IN_FLASH_MODE = 0xC6, 14 | ESP_INFLATE_ERROR = 0xC7, 15 | ESP_NOT_ENOUGH_DATA = 0xC8, 16 | ESP_TOO_MUCH_DATA = 0xC9, 17 | ESP_CMD_NOT_IMPLEMENTED = 0xFF, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ESPTool/Resources/Config/Devices/ESP32.json: -------------------------------------------------------------------------------- 1 | { 2 | "ChipType": "ESP32", 3 | "FlashBlockSize": 1024, 4 | "RamBlockSize": 6144, 5 | "MagicRegisterValue": 15736195, 6 | "EFlags": { 7 | "BaseMacAddress": { 8 | "Address": 1073061892, 9 | "Size": 6 10 | } 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /ESPTool/Resources/Config/Devices/ESP32C3.json: -------------------------------------------------------------------------------- 1 | { 2 | "ChipType": "ESP32c3", 3 | "FlashBlockSize": 1024, 4 | "RamBlockSize": 6144, 5 | "MagicRegisterValue": 456216687 6 | } 7 | 8 | -------------------------------------------------------------------------------- /ESPTool/Resources/Config/Devices/ESP32H2.json: -------------------------------------------------------------------------------- 1 | { 2 | "ChipType": "ESP32h2", 3 | "FlashBlockSize": 1024, 4 | "RamBlockSize": 6144, 5 | "MagicRegisterValue": 3391540258 6 | } 7 | 8 | -------------------------------------------------------------------------------- /ESPTool/Resources/Config/Devices/ESP32S2.json: -------------------------------------------------------------------------------- 1 | { 2 | "ChipType": "ESP32s2", 3 | "FlashBlockSize": 1024, 4 | "RamBlockSize": 6144, 5 | "MagicRegisterValue": 1990 6 | } 7 | 8 | -------------------------------------------------------------------------------- /ESPTool/Resources/Config/Devices/ESP32S3.json: -------------------------------------------------------------------------------- 1 | { 2 | "ChipType": "ESP32s3", 3 | "FlashBlockSize": 1024, 4 | "RamBlockSize": 6144, 5 | "MagicRegisterValue": 9, 6 | "EFlags": { 7 | "BaseMacAddress": { 8 | "Address": 1610641476, 9 | "Size": 6 10 | } 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /ESPTool/Resources/Config/Devices/ESP8266.json: -------------------------------------------------------------------------------- 1 | { 2 | "ChipType": "ESP8266", 3 | "FlashBlockSize": 1024, 4 | "RamBlockSize": 6144, 5 | "MagicRegisterValue": 4293968129 6 | } 7 | 8 | -------------------------------------------------------------------------------- /ESPTool/Resources/Config/ESPToolConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "BootloaderSequence": [ 3 | { 4 | "Dtr": false, 5 | "Rts": true, 6 | "Delay": "00:00:00.500" 7 | }, 8 | { 9 | "Dtr": true, 10 | "Rts": false, 11 | "Delay": "00:00:00.500" 12 | }, 13 | { 14 | "Dtr": false, 15 | "Rts": false, 16 | "Delay": "00:00:00.000" 17 | } 18 | ], 19 | "ResetSequence": [ 20 | { 21 | "Dtr": false, 22 | "Rts": true, 23 | "Delay": "00:00:00.500" 24 | }, 25 | { 26 | "Dtr": false, 27 | "Rts": false, 28 | "Delay": "00:00:00.000" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1074521580, 3 | "text": "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", 4 | "text_start": 1074520064, 5 | "data": "DMD8P+znC0B/6AtAZ+0LQAbpC0Cf6AtABukLQGXpC0CC6gtA9OoLQJ3qC0CV5wtAGuoLQHTqC0CI6QtAGOsLQLDpC0AY6wtAbegLQMroC0AG6QtAZekLQIXoC0DI6wtAKe0LQLjmC0BL7QtAuOYLQLjmC0C45gtAuOYLQLjmC0C45gtAuOYLQLjmC0Bv6wtAuOYLQEnsC0Ap7QtA", 6 | "data_start": 1073605544, 7 | "bss_start": 1073528832 8 | } 9 | -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32c2.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1077413304, 3 | "text": "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", 4 | "text_start": 1077411840, 5 | "data": "DEDKP+AIOEAsCThAhAk4QFIKOEC+CjhAbAo4QKgHOEAOCjhATgo4QJgJOEBYBzhAzAk4QFgHOEC6CDhA/gg4QCwJOECECThAzAg4QBIIOEBCCDhAyAg4QBYNOEAsCThA1gs4QMoMOECkBjhA9Aw4QKQGOECkBjhApAY4QKQGOECkBjhApAY4QKQGOECkBjhAcgs4QKQGOEDyCzhAygw4QA==", 6 | "data_start": 1070295976, 7 | "bss_start": 1070219264 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32c3.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1077413532, 3 | "text": "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", 4 | "text_start": 1077411840, 5 | "data": "FEDIP4wKOEDcCjhANAs4QAIMOEBuDDhAHAw4QD4JOEC+CzhA/gs4QEgLOEDuCDhAfAs4QO4IOEBmCjhArAo4QNwKOEA0CzhAeAo4QKIJOEDsCThAdAo4QMYOOEDcCjhAhg04QH4OOEAuCDhApg44QC4IOEAuCDhALgg4QC4IOEAuCDhALgg4QC4IOEAuCDhAIg04QC4IOECkDThAfg44QA==", 6 | "data_start": 1070164912, 7 | "bss_start": 1070088192 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32c6.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1082132112, 3 | "text": "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", 4 | "text_start": 1082130432, 5 | "data": "EACEQD4KgECOCoBA5gqAQLQLgEAgDIBAzguAQAoJgEBwC4BAsAuAQPoKgEC6CIBALguAQLoIgEAYCoBAXgqAQI4KgEDmCoBAKgqAQG4JgECeCYBAJgqAQHgOgECOCoBAOA2AQDAOgED6B4BAWA6AQPoHgED6B4BA+geAQPoHgED6B4BA+geAQPoHgED6B4BA1AyAQPoHgEBWDYBAMA6AQA==", 6 | "data_start": 1082469292, 7 | "bss_start": 1082392576 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32c6beta.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1077413318, 3 | "text": "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", 4 | "text_start": 1077411840, 5 | "data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==", 6 | "data_start": 1070164904, 7 | "bss_start": 1070088192 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32h2.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1082132112, 3 | "text": "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", 4 | "text_start": 1082130432, 5 | "data": "EACDQD4KgECOCoBA5gqAQLQLgEAgDIBAzguAQAoJgEBwC4BAsAuAQPoKgEC6CIBALguAQLoIgEAYCoBAXgqAQI4KgEDmCoBAKgqAQG4JgECeCYBAJgqAQHgOgECOCoBAOA2AQDAOgED6B4BAWA6AQPoHgED6B4BA+geAQPoHgED6B4BA+geAQPoHgED6B4BA1AyAQPoHgEBWDYBAMA6AQA==", 6 | "data_start": 1082403756, 7 | "bss_start": 1082327040 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32h2beta1.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1077413318, 3 | "text": "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", 4 | "text_start": 1077411840, 5 | "data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==", 6 | "data_start": 1070164904, 7 | "bss_start": 1070088192 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32h2beta2.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1077413318, 3 | "text": "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", 4 | "text_start": 1077411840, 5 | "data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==", 6 | "data_start": 1070164904, 7 | "bss_start": 1070088192 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32p4.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1341195718, 3 | "text": "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", 4 | "text_start": 1341194240, 5 | "data": "DAD1T+4I8U86CfFPkgnxT2gK8U/UCvFPggrxT7YH8U8kCvFPZArxT6YJ8U9mB/FP2gnxT2YH8U/ICPFPDAnxTzoJ8U+SCfFP2gjxTyAI8U9QCPFP1gjxTywN8U86CfFP7AvxT+AM8U+yBvFPCg3xT7IG8U+yBvFPsgbxT7IG8U+yBvFPsgbxT7IG8U+yBvFPiAvxT7IG8U8IDPFP4AzxTw==", 6 | "data_start": 1341533096, 7 | "bss_start": 1341456384 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32s2.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1073907716, 3 | "text": "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", 4 | "text_start": 1073905664, 5 | "data": "WAD9P0uLAkDdiwJA8pACQGaMAkD+iwJAZowCQMWMAkDejQJAUY4CQPmNAkDVigJAd40CQNCNAkDojAJAdI4CQBCNAkB0jgJAy4sCQCqMAkBmjAJAxYwCQOOLAkAXiwJAN48CQKqQAkDqiQJA0ZACQOqJAkDqiQJA6okCQOqJAkDqiQJA6okCQOqJAkDqiQJA1I4CQOqJAkDJjwJAqpACQA==", 6 | "data_start": 1073622012, 7 | "bss_start": 1073545216 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32s3.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1077381712, 3 | "text": "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", 4 | "text_start": 1077379072, 5 | "data": "WADKPy6ON0ADjzdAF5Q3QI2PN0AjjzdAjY83QO2PN0AKkTdAfJE3QCWRN0C5jTdAoJA3QPyQN0AQkDdAoJE3QDiQN0CgkTdA8Y43QE6PN0CNjzdA7Y83QAmPN0D6jTdAYJI3QN2TN0DQjDdA/ZM3QNCMN0DQjDdA0Iw3QNCMN0DQjDdA0Iw3QNCMN0DQjDdA+pE3QNCMN0D1kjdA3ZM3QAQInwAAAAAAAAAYAQQIBQAAAAAAAAAIAQQIBgAAAAAAAAAAAQQIIQAAAAAAIAAAEQQI3AAAAAAAIAAAEQQIDAAAAAAAIAAAAQQIEgAAAAAAIAAAESAoDAAQAQAA", 6 | "data_start": 1070279672, 7 | "bss_start": 1070202880 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_32s3beta2.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1077380596, 3 | "text": "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", 4 | "text_start": 1077379072, 5 | "data": "DADKPxeIN0CriDdAw403QDeJN0DLiDdAN4k3QJaJN0C2ijdAKIs3QNGKN0ChhzdASIo3QKiKN0C5iTdATIs3QOGJN0BMizdAmYg3QPiIN0A3iTdAlok3QLGIN0DjhzdABIw3QIWNN0DAhjdAp403QMCGN0DAhjdAwIY3QMCGN0DAhjdAwIY3QMCGN0DAhjdAqYs3QMCGN0CZjDdAhY03QA==", 6 | "data_start": 1070279592, 7 | "bss_start": 1070202880 8 | } -------------------------------------------------------------------------------- /ESPTool/Resources/stub/stub_flasher_8266.json: -------------------------------------------------------------------------------- 1 | { 2 | "entry": 1074843652, 3 | "text": "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", 4 | "text_start": 1074843648, 5 | "data": "CIH+PwUFBAACAwcAAwMLANTXEEAL2BBAOdgQQNbYEECF5xBAOtkQQJDZEEDc2RBAhecQQKLaEEAf2xBA4NsQQIXnEECF5xBAeNwQQIXnEEBV3xBAHOAQQFfgEECF5xBAhecQQPPgEECF5xBA2+EQQIHiEEDA4xBAf+QQQFDlEECF5xBAhecQQIXnEECF5xBAfuYQQIXnEEB05xBAsN0QQKnYEEDC5RBAydoQQBvaEECF5xBACOcQQE/nEECF5xBAhecQQIXnEECF5xBAhecQQIXnEECF5xBAhecQQELaEEB/2hBA2uUQQAEAAAACAAAAAwAAAAQAAAAFAAAABwAAAAkAAAANAAAAEQAAABkAAAAhAAAAMQAAAEEAAABhAAAAgQAAAMEAAAABAQAAgQEAAAECAAABAwAAAQQAAAEGAAABCAAAAQwAAAEQAAABGAAAASAAAAEwAAABQAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABgAAAAcAAAAHAAAACAAAAAgAAAAJAAAACQAAAAoAAAAKAAAACwAAAAsAAAAMAAAADAAAAA0AAAANAAAAAAAAAAAAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAANAAAADwAAABEAAAATAAAAFwAAABsAAAAfAAAAIwAAACsAAAAzAAAAOwAAAEMAAABTAAAAYwAAAHMAAACDAAAAowAAAMMAAADjAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAgAAAAMAAAADAAAAAwAAAAMAAAAEAAAABAAAAAQAAAAEAAAABQAAAAUAAAAFAAAABQAAAAAAAAAAAAAAAAAAABAREgAIBwkGCgULBAwDDQIOAQ8AAQEAAAEAAAAEAAAA", 6 | "data_start": 1073720488, 7 | "bss_start": 1073643776 8 | } -------------------------------------------------------------------------------- /ESPTool/Tools/BootloaderTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Communication; 2 | using EspDotNet.Config; 3 | using EspDotNet.Loaders.ESP32BootLoader; 4 | using System.Text.RegularExpressions; 5 | using System.Text; 6 | 7 | namespace EspDotNet.Tools 8 | { 9 | public class BootloaderTool 10 | { 11 | private readonly Communicator _communicator; 12 | private readonly List _bootloaderSequence; 13 | 14 | public BootloaderTool(Communicator communicator, List bootloaderSequence) 15 | { 16 | _communicator = communicator; 17 | _bootloaderSequence = bootloaderSequence; 18 | } 19 | 20 | public async Task StartAsync(CancellationToken token = default) 21 | { 22 | // Start bootloader 23 | await _communicator.ExecutePinSequence(_bootloaderSequence, token); 24 | 25 | // Check bootloader message 26 | if (!await TryReadBootStartup(token)) 27 | throw new Exception("Booloader message not verified"); 28 | 29 | // Instantiate loader and synchronize 30 | var bootloader = new ESP32BootLoader(_communicator); 31 | 32 | if (!await Synchronize(bootloader, token)) 33 | throw new Exception("Failed to synchronize with bootloader"); 34 | 35 | return bootloader; 36 | } 37 | 38 | private async Task TryReadBootStartup(CancellationToken token) 39 | { 40 | var buffer = new byte[4096]; 41 | var read = await _communicator.ReadRawAsync(buffer, token); 42 | if (read > 0) 43 | { 44 | var data = new byte[read]; 45 | Array.Copy(buffer, data, read); 46 | Regex regex = new Regex("boot:(0x[0-9a-fA-F]+)(.*waiting for download)?"); 47 | var result = regex.Match(Encoding.ASCII.GetString(data)); 48 | return result.Success; 49 | } 50 | return false; 51 | } 52 | 53 | private async Task Synchronize(ESP32BootLoader loader, CancellationToken token) 54 | { 55 | for (int tryNo = 0; tryNo < 100; tryNo++) 56 | { 57 | token.ThrowIfCancellationRequested(); 58 | 59 | // Try to sync for 100ms. 60 | using CancellationTokenSource cts = new CancellationTokenSource(); 61 | 62 | // Register the token and store the registration to dispose of it later 63 | using CancellationTokenRegistration ctr = token.Register(() => cts.Cancel()); 64 | 65 | cts.CancelAfter(100); // Cancel after 100ms 66 | 67 | try 68 | { 69 | if(await loader.SynchronizeAsync(cts.Token)) 70 | return true; 71 | } 72 | catch (OperationCanceledException) 73 | { 74 | } 75 | finally 76 | { 77 | ctr.Unregister(); 78 | } 79 | } 80 | 81 | return false; 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /ESPTool/Tools/ChangeBaudrateTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Communication; 2 | using EspDotNet.Loaders; 3 | 4 | namespace EspDotNet.Tools 5 | { 6 | public class ChangeBaudrateTool 7 | { 8 | private readonly ILoader _loader; 9 | private readonly Communicator _communicator; 10 | public ChangeBaudrateTool(Communicator communicator, ILoader loader) 11 | { 12 | _loader = loader; 13 | _communicator = communicator; 14 | } 15 | public async Task ChangeBaudAsync(int baud, CancellationToken token) 16 | { 17 | int oldBaud = _communicator.GetBaudRate(); 18 | if (baud == oldBaud) 19 | return; 20 | await _loader.ChangeBaudAsync(baud, oldBaud, token); 21 | _communicator.ChangeBaudRate(baud); 22 | 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ESPTool/Tools/ChipTypeDetectTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Config; 2 | using EspDotNet.Loaders; 3 | 4 | namespace EspDotNet.Tools 5 | { 6 | public class ChipTypeDetectTool 7 | { 8 | private readonly ILoader _loader; 9 | private readonly ESPToolConfig _config; 10 | 11 | public ChipTypeDetectTool(ILoader loader, ESPToolConfig config) 12 | { 13 | _loader = loader; 14 | _config = config; 15 | } 16 | public async Task DetectChipTypeAsync(CancellationToken token) 17 | { 18 | // https://esp32.com/viewtopic.php?t=26626 19 | uint CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000; 20 | uint id = await _loader.ReadRegisterAsync(CHIP_DETECT_MAGIC_REG_ADDR, token); 21 | var deviceConfig = _config.Devices.FirstOrDefault(device => device.MagicRegisterValue == id); 22 | return deviceConfig == null ? ChipTypes.Unknown : deviceConfig.ChipType; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ESPTool/Tools/EFuseTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Config; 2 | using EspDotNet.Loaders; 3 | using EspDotNet.Loaders.SoftLoader; 4 | 5 | namespace EspDotNet.Tools 6 | { 7 | public class EFuseTool 8 | { 9 | private readonly ILoader _loader; 10 | private readonly DeviceConfig _deviceConfig; 11 | public EFuseTool(ILoader loader, DeviceConfig deviceConfig) 12 | { 13 | _loader = loader; 14 | _deviceConfig = deviceConfig; 15 | } 16 | 17 | public async Task ReadAsync(EFlagKey key, CancellationToken token) 18 | { 19 | if (!_deviceConfig.EFlags.TryGetValue(key, out EFuseMapping? mapping)) 20 | { 21 | throw new Exception($"EFuse mapping not found for key {key}"); 22 | } 23 | 24 | // Calculate how many 4-byte registers we need to read. 25 | int registersNeeded = (mapping.Size + 3) / 4; 26 | List resultBytes = new List(); 27 | 28 | for (int i = 0; i < registersNeeded; i++) 29 | { 30 | uint address = mapping.Address + (uint)(i * 4); 31 | uint regValue = await _loader.ReadRegisterAsync(address, token); 32 | // Convert the register value to bytes (assuming little-endian format). 33 | byte[] regBytes = BitConverter.GetBytes(regValue); 34 | resultBytes.AddRange(regBytes); 35 | } 36 | 37 | // Trim the result to the requested size. 38 | byte[] data = resultBytes.Take(mapping.Size).ToArray(); 39 | return data; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ESPTool/Tools/Firmware/DefaultFirmwareProviders.cs: -------------------------------------------------------------------------------- 1 | using System.Buffers.Text; 2 | using System.Reflection; 3 | using System.Text; 4 | using System.Text.Json; 5 | using System.Text.Json.Serialization; 6 | 7 | namespace EspDotNet.Tools.Firmware 8 | { 9 | public class DefaultFirmwareProviders 10 | { 11 | public static IFirmwareProvider GetSoftloaderForDevice(ChipTypes chipType) 12 | { 13 | return chipType switch 14 | { 15 | ChipTypes.ESP32c6beta => GetFirmware("stub_flasher_32c6beta.json"), 16 | ChipTypes.ESP32h2 => GetFirmware("stub_flasher_32h2.json"), 17 | ChipTypes.ESP32h2beta1 => GetFirmware("stub_flasher_32h2beta1.json"), 18 | ChipTypes.ESP32h2beta2 => GetFirmware("stub_flasher_32h2beta2.json"), 19 | ChipTypes.ESP32p4 => GetFirmware("stub_flasher_32p4.json"), 20 | ChipTypes.ESP32s2 => GetFirmware("stub_flasher_32s2.json"), 21 | ChipTypes.ESP32s3 => GetFirmware("stub_flasher_32s3.json"), 22 | ChipTypes.ESP32s3beta2 => GetFirmware("stub_flasher_32s3beta2.json"), 23 | ChipTypes.ESP8266 => GetFirmware("stub_flasher_8266.json"), 24 | ChipTypes.ESP32 => GetFirmware("stub_flasher_32.json"), 25 | ChipTypes.ESP32c2 => GetFirmware("stub_flasher_32c2.json"), 26 | ChipTypes.ESP32c3 => GetFirmware("stub_flasher_32c3.json"), 27 | ChipTypes.ESP32c6 => GetFirmware("stub_flasher_32c6.json"), 28 | _ => throw new Exception($"Chip type {chipType} is not supported"), 29 | }; 30 | } 31 | 32 | private static FirmwareProvider GetFirmware(string resourceName) 33 | { 34 | var stub = GetStub(resourceName); 35 | 36 | return new FirmwareProvider( 37 | entryPoint: stub.Entry, 38 | segments: new List 39 | { 40 | new FirmwareSegmentProvider(stub.TextStart, Convert.FromBase64String(stub.Text)), 41 | new FirmwareSegmentProvider(stub.DataStart, Convert.FromBase64String(stub.Data)), 42 | } 43 | ); 44 | } 45 | 46 | private static Stub GetStub(string resourceName) 47 | { 48 | string json = ReadEmbeddedJson(resourceName); 49 | return JsonSerializer.Deserialize(json) 50 | ?? throw new Exception($"Failed to deserialize JSON from resource: {resourceName}"); 51 | } 52 | 53 | private static string ReadEmbeddedJson(string resourceName) 54 | { 55 | var assembly = Assembly.GetExecutingAssembly(); 56 | string resourcePath = $"{assembly.GetName().Name}.Resources.stub.{resourceName}"; 57 | 58 | using Stream stream = assembly.GetManifestResourceStream(resourcePath) 59 | ?? throw new Exception($"Embedded resource '{resourceName}' not found in assembly."); 60 | 61 | using StreamReader reader = new StreamReader(stream); 62 | return reader.ReadToEnd(); 63 | } 64 | 65 | class Stub 66 | { 67 | [JsonPropertyName("entry")] 68 | public uint Entry { get; set; } 69 | 70 | [JsonPropertyName("text")] 71 | public string Text { get; set; } = string.Empty; 72 | 73 | [JsonPropertyName("text_start")] 74 | public uint TextStart { get; set; } 75 | 76 | [JsonPropertyName("data")] 77 | public string Data { get; set; } = string.Empty; 78 | 79 | [JsonPropertyName("data_start")] 80 | public uint DataStart { get; set; } 81 | 82 | [JsonPropertyName("bss_start")] 83 | public uint BssStart { get; set; } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ESPTool/Tools/Firmware/FirmwareProvider.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Tools.Firmware 2 | { 3 | public class FirmwareProvider : IFirmwareProvider 4 | { 5 | public uint EntryPoint { get; } 6 | public IReadOnlyList Segments { get; } 7 | 8 | public FirmwareProvider(uint entryPoint, IEnumerable segments) 9 | { 10 | EntryPoint = entryPoint; 11 | Segments = segments.ToList().AsReadOnly(); 12 | } 13 | } 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ESPTool/Tools/Firmware/FirmwareSegment.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 EspDotNet.Tools.Firmware 8 | { 9 | 10 | public class FirmwareSegment 11 | { 12 | public uint Offset { get; set; } = 0; 13 | public byte[] Data { get; set; } = []; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ESPTool/Tools/Firmware/FirmwareSegmentProvider.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Tools.Firmware 2 | { 3 | public class FirmwareSegmentProvider : IFirmwareSegmentProvider 4 | { 5 | public uint Offset { get; } 6 | public uint Size => (uint)_data.Length; 7 | private readonly byte[] _data; 8 | 9 | public FirmwareSegmentProvider(uint offset, byte[] data) 10 | { 11 | Offset = offset; 12 | _data = data; 13 | } 14 | 15 | public Task GetStreamAsync(CancellationToken token = default) 16 | { 17 | return Task.FromResult(new MemoryStream(_data, writable: false)); 18 | } 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ESPTool/Tools/Firmware/IFirmwareProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace EspDotNet.Tools.Firmware 4 | { 5 | public interface IFirmwareProvider 6 | { 7 | uint EntryPoint { get; } 8 | IReadOnlyList Segments { get; } 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /ESPTool/Tools/Firmware/IFirmwareSegmentProvider.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Tools.Firmware 2 | { 3 | public interface IFirmwareSegmentProvider 4 | { 5 | uint Offset { get; } 6 | uint Size { get; } 7 | Task GetStreamAsync(CancellationToken token = default); 8 | } 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /ESPTool/Tools/FirmwareUploadTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Loaders; 2 | using EspDotNet.Tools.Firmware; 3 | using EspDotNet.Utils; 4 | using System; 5 | 6 | namespace EspDotNet.Tools 7 | { 8 | public class FirmwareUploadTool 9 | { 10 | public IProgress Progress { get; set; } = new Progress(); 11 | 12 | private readonly IUploadTool _uploadTool; 13 | 14 | public FirmwareUploadTool(IUploadTool uploadTool) 15 | { 16 | _uploadTool = uploadTool; 17 | } 18 | 19 | public Task UploadFirmwareAsync(IFirmwareProvider firmwareProvider, CancellationToken token) 20 | { 21 | return ProcessSegmentsAsync(firmwareProvider, executeOnLast: false, token); 22 | } 23 | 24 | public Task UploadFirmwareAndExecuteAsync(IFirmwareProvider firmwareProvider, CancellationToken token) 25 | { 26 | return ProcessSegmentsAsync(firmwareProvider, executeOnLast: true, token); 27 | } 28 | 29 | private async Task ProcessSegmentsAsync(IFirmwareProvider firmwareProvider, bool executeOnLast, CancellationToken token) 30 | { 31 | Progress.Report(0); 32 | var segments = firmwareProvider.Segments.ToList(); 33 | var totalSize = segments.Sum(s => s.Size); 34 | float progressAccumulated = 0; 35 | 36 | for (int i = 0; i < segments.Count; i++) 37 | { 38 | var segment = segments[i]; 39 | var dataStream = await segment.GetStreamAsync(token); 40 | var offset = segment.Offset; 41 | var size = segment.Size; 42 | float segmentWeight = (float)size / totalSize; // Fractional contribution of this segment 43 | 44 | // Update the upload tool's progress handler for the current segment. 45 | _uploadTool.Progress = new Progress(p => 46 | { 47 | float segmentProgress = p * segmentWeight; 48 | Progress.Report(segmentProgress + progressAccumulated); 49 | }); 50 | 51 | bool isLastSegment = (i == segments.Count - 1); 52 | if (executeOnLast && isLastSegment) 53 | { 54 | await _uploadTool.UploadAndExecute(dataStream, offset, size, firmwareProvider.EntryPoint, token); 55 | } 56 | else 57 | { 58 | await _uploadTool.Upload(dataStream, offset, size, token); 59 | } 60 | 61 | progressAccumulated += segmentWeight; 62 | } 63 | Progress.Report(1); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /ESPTool/Tools/FlashEraseTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Loaders; 2 | using EspDotNet.Loaders.SoftLoader; 3 | 4 | namespace EspDotNet.Tools 5 | { 6 | public class FlashEraseTool 7 | { 8 | private readonly SoftLoader _loader; 9 | public FlashEraseTool(SoftLoader loader) 10 | { 11 | _loader = loader; 12 | } 13 | public async Task EraseFlashAsync(CancellationToken token) 14 | { 15 | await _loader.EraseFlashAsync(token); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ESPTool/Tools/GetAddressesTool.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Tools 2 | { 3 | 4 | public class GetAddressesTool 5 | { 6 | 7 | private readonly ILoader _loader; 8 | 9 | public GetAddressesTool(ILoader loader) 10 | { 11 | _loader = loader; 12 | } 13 | 14 | // Useful notes for how I derived these addresses 15 | //EFUSE_BASE = 0x60007000 # BLOCK0 read base address 16 | //https://github.com/espressif/esptool/blob/955943a8ab02fde8113d67f9ebab75ba4cbaa9f0/esptool/targets/esp32s3.py 17 | //MAC_EFUSE_REG = EFUSE_BASE + 0x044 ( 0x60007000 + 0x044 = 60007044) 18 | //MAC_EFUSE_BASE_ADDR = (MAC_EFUSE_REG + 4 (0x60007044 + 4 = 60007048) 19 | 20 | // Getting the first 4 octets 21 | public async Task GetBaseMacAsync(CancellationToken token) 22 | { 23 | uint EMAC_BASE_ADDR = 0x60007048; 24 | uint BaseAddr = await _loader.ReadRegisterAsync(EMAC_BASE_ADDR, token); 25 | return BaseAddr; 26 | } 27 | 28 | // Getting the last 6 octets 29 | public async Task GetLastSixOctetsAsync(CancellationToken token) 30 | { 31 | uint MAC_EFUSE_REG = 0x60007044; 32 | uint maccy = await _loader.ReadRegisterAsync(MAC_EFUSE_REG, token); 33 | return maccy; 34 | } 35 | 36 | // Gets the base Mac Address 37 | public async Task GetBaseMacAddressAsync(CancellationToken token) 38 | { 39 | string BaseMacAddress = string.Empty; 40 | 41 | // Getting Base part of Mac address 42 | uint BaseAddr = await GetBaseMacAsync(token); 43 | string BaseMac = BaseAddr.ToString("X"); 44 | 45 | //WiFi Base MacAddress 46 | uint maccy = await GetLastSixOctetsAsync(token); 47 | string LowerMac = maccy.ToString("X"); 48 | 49 | BaseMacAddress = SplitAndFormat(BaseMac + LowerMac); 50 | 51 | return BaseMacAddress; 52 | } 53 | 54 | // Gets the wifi AP address 55 | public async Task GetWiFiAPMacAddressAsync(CancellationToken token) 56 | { 57 | string WifiAPAddr = string.Empty; 58 | 59 | // Getting Base part of Mac address 60 | uint BaseAddr = await GetBaseMacAsync(token); 61 | string BaseMac = BaseAddr.ToString("X"); 62 | 63 | // WiFiAP = Base Mac Address + 1 64 | uint maccy = (await GetLastSixOctetsAsync(token) + 1); 65 | string LowerMac = maccy.ToString("X"); 66 | 67 | WifiAPAddr = SplitAndFormat(BaseMac + LowerMac); 68 | 69 | return WifiAPAddr; 70 | } 71 | 72 | public async Task GetBlueToothMacAddressAsync(CancellationToken token) 73 | { 74 | string BTAddr = string.Empty; 75 | // Getting Base part of Mac address 76 | uint BaseAddr = await GetBaseMacAsync(token); 77 | string BaseMac = BaseAddr.ToString("X"); 78 | 79 | // BlueTooth = Base Mac Address + 2 80 | uint maccy = (await GetLastSixOctetsAsync(token) + 2); 81 | string LowerMac = maccy.ToString("X"); 82 | 83 | BTAddr = SplitAndFormat(BaseMac + LowerMac); 84 | 85 | return BTAddr; 86 | } 87 | 88 | // Gets the Ethernet Address of the device 89 | public async Task GetEthernetAddressAsync(CancellationToken token) 90 | { 91 | string EthernetAddr = string.Empty; 92 | // Getting Base part of Mac address 93 | uint BaseAddr = await GetBaseMacAsync(token); 94 | string BaseMac = BaseAddr.ToString("X"); 95 | 96 | // Ethernet = Base Mac Address + 3 97 | uint maccy = (await GetLastSixOctetsAsync(token) + 3); 98 | string LowerMac = maccy.ToString("X"); 99 | 100 | EthernetAddr = SplitAndFormat(BaseMac + LowerMac); 101 | 102 | return EthernetAddr; 103 | } 104 | 105 | // String formatter to format the address to be more like a mac address 106 | public static string SplitAndFormat(string input) 107 | { 108 | if (string.IsNullOrEmpty(input)) 109 | { 110 | return string.Empty; 111 | } 112 | 113 | StringBuilder result = new StringBuilder(); 114 | 115 | for (int i = 0; i < input.Length; i += 2) 116 | { 117 | if (i + 1 < input.Length) 118 | { 119 | result.Append(input.Substring(i, 2)); 120 | if (i + 2 < input.Length) 121 | { 122 | result.Append(":"); 123 | } 124 | } 125 | else 126 | { 127 | result.Append(input.Substring(i)); // Handle odd length 128 | } 129 | } 130 | return result.ToString(); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /ESPTool/Tools/IUploadTool.cs: -------------------------------------------------------------------------------- 1 | namespace EspDotNet.Tools 2 | { 3 | public interface IUploadTool 4 | { 5 | public IProgress Progress { get; set; } 6 | public uint BlockSize { get; set; } 7 | Task Upload(Stream data, uint offset, uint size, CancellationToken token); 8 | Task UploadAndExecute(Stream uncompressedData, uint offset, uint unCompressedSize, uint entryPoint, CancellationToken token); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ESPTool/Tools/ResetDeviceTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Communication; 2 | using EspDotNet.Config; 3 | 4 | namespace EspDotNet.Tools 5 | { 6 | public class ResetDeviceTool 7 | { 8 | private readonly Communicator _communicator; 9 | private readonly List _resetDeviceSequence; 10 | 11 | public ResetDeviceTool(Communicator communicator, List resetDeviceSequence) 12 | { 13 | _communicator = communicator; 14 | _resetDeviceSequence = resetDeviceSequence; 15 | } 16 | 17 | public async Task ResetAsync(CancellationToken token = default) 18 | { 19 | await _communicator.ExecutePinSequence(_resetDeviceSequence, token); 20 | } 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /ESPTool/Tools/SoftloaderTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Communication; 2 | using EspDotNet.Loaders.SoftLoader; 3 | using EspDotNet.Tools.Firmware; 4 | 5 | namespace EspDotNet.Tools 6 | { 7 | public class SoftloaderTool 8 | { 9 | private readonly Communicator _communicator; 10 | private readonly UploadRamTool _uploadTool; 11 | private readonly IFirmwareProvider _firmwareProvider; 12 | 13 | public SoftloaderTool(Communicator communicator, UploadRamTool uploadTool, IFirmwareProvider firmwareProvider) 14 | { 15 | _communicator = communicator; 16 | _uploadTool = uploadTool; 17 | _firmwareProvider = firmwareProvider; 18 | } 19 | 20 | public async Task StartAsync(CancellationToken token = default) 21 | { 22 | // Upload the stubloader 23 | var firmwareTool = new FirmwareUploadTool(_uploadTool); 24 | await firmwareTool.UploadFirmwareAndExecuteAsync(_firmwareProvider, token); 25 | 26 | // Instantiate loader and synchronize 27 | SoftLoader softLoader = new SoftLoader(_communicator); 28 | await softLoader.WaitForOHAIAsync(token); 29 | return softLoader; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ESPTool/Tools/UploadFlashDeflatedTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Loaders; 2 | using EspDotNet.Loaders.SoftLoader; 3 | using EspDotNet.Tools.Firmware; 4 | using EspDotNet.Utils; 5 | using System; 6 | 7 | namespace EspDotNet.Tools 8 | { 9 | public class UploadFlashDeflatedTool : IUploadTool 10 | { 11 | public IProgress Progress { get; set; } = new Progress(); 12 | public uint BlockSize { get; set; } = 1024; 13 | private readonly SoftLoader _loader; 14 | 15 | public UploadFlashDeflatedTool(SoftLoader loader) 16 | { 17 | _loader = loader; 18 | } 19 | 20 | public async Task Upload(Stream uncompressedStream, uint offset, uint unCompressedSize, CancellationToken token) 21 | { 22 | MemoryStream compressedStream = new MemoryStream(); 23 | ZlibCompressionHelper.CompressToZlibStream(uncompressedStream, compressedStream); 24 | compressedStream.Position = 0; 25 | 26 | UInt32 compressedSize = (UInt32)compressedStream.Length; 27 | UInt32 blockSize = (UInt32)BlockSize; 28 | UInt32 blocks = compressedSize / blockSize; 29 | if (compressedSize % blockSize != 0) 30 | blocks++; 31 | 32 | 33 | await _loader.FlashDeflBeginAsync(unCompressedSize, blocks, BlockSize, offset, token); 34 | 35 | // Send data 36 | for (uint i = 0; i < blocks; i++) 37 | { 38 | uint srcIndex = i * BlockSize; 39 | uint len = Math.Min(BlockSize, compressedSize - srcIndex); 40 | 41 | byte[] buffer = new byte[len]; 42 | int bytesRead = await compressedStream.ReadAsync(buffer, 0, (int)len, token); 43 | if (bytesRead != len) 44 | break; 45 | 46 | await _loader.FlashDeflDataAsync(buffer, i, token); 47 | Progress.Report((float)(i + 1) / blocks); 48 | } 49 | 50 | // Sending end is not required here 51 | // https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/serial-protocol.html#writing-data 52 | } 53 | 54 | public async Task UploadAndExecute(Stream uncompressedData, uint offset, uint unCompressedSize, uint entryPoint, CancellationToken token) 55 | { 56 | await Upload(uncompressedData, offset, unCompressedSize, token); 57 | 58 | // End memory transfer, 0 means execute, confusing 59 | await _loader.FlashDeflEndAsync(0, entryPoint, token); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ESPTool/Tools/UploadFlashTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Loaders; 2 | using EspDotNet.Tools.Firmware; 3 | using EspDotNet.Utils; 4 | 5 | namespace EspDotNet.Tools 6 | { 7 | public class UploadFlashTool : IUploadTool 8 | { 9 | public IProgress Progress { get; set; } = new Progress(); 10 | public uint BlockSize { get; set; } = 1024; 11 | private readonly ILoader _loader; 12 | 13 | public UploadFlashTool(ILoader loader) 14 | { 15 | _loader = loader; 16 | } 17 | 18 | public async Task Upload(Stream data, uint offset, uint size, CancellationToken token) 19 | { 20 | // Calculate blocks 21 | uint blocks = (size + BlockSize - 1) / BlockSize; 22 | await _loader.FlashBeginAsync(size, blocks, BlockSize, offset, token); 23 | 24 | // Send data 25 | for (uint i = 0; i < blocks; i++) 26 | { 27 | uint srcIndex = i * BlockSize; 28 | uint len = Math.Min(BlockSize, size - srcIndex); 29 | 30 | byte[] buffer = new byte[len]; 31 | int bytesRead = await data.ReadAsync(buffer, 0, (int)len, token); 32 | if (bytesRead != len) 33 | break; 34 | 35 | await _loader.FlashDataAsync(buffer, i, token); 36 | Progress.Report((float)(i + 1) / blocks); 37 | } 38 | 39 | // Sending end is not required here 40 | // https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/serial-protocol.html#writing-data 41 | } 42 | 43 | public async Task UploadAndExecute(Stream uncompressedData, uint offset, uint unCompressedSize, uint entryPoint, CancellationToken token) 44 | { 45 | await Upload(uncompressedData, offset, unCompressedSize, token); 46 | 47 | // End memory transfer, 0 means execute, confusing 48 | await _loader.FlashEndAsync(0, entryPoint, token); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ESPTool/Tools/UploadRamTool.cs: -------------------------------------------------------------------------------- 1 | using EspDotNet.Loaders; 2 | using EspDotNet.Loaders.SoftLoader; 3 | using EspDotNet.Tools.Firmware; 4 | 5 | namespace EspDotNet.Tools 6 | { 7 | public class UploadRamTool : IUploadTool 8 | { 9 | public IProgress Progress { get; set; } = new Progress(); 10 | public uint BlockSize { get; set; } = 1024; 11 | private readonly ILoader _loader; 12 | 13 | public UploadRamTool(ILoader loader) 14 | { 15 | _loader = loader; 16 | } 17 | 18 | public async Task Upload(Stream data, uint offset, uint size, CancellationToken token) 19 | { 20 | // Calculate blocks 21 | uint blocks = (size + BlockSize - 1) / BlockSize; 22 | await _loader.MemBeginAsync(size, blocks, BlockSize, offset, token); 23 | 24 | // Send data 25 | for (uint i = 0; i < blocks; i++) 26 | { 27 | uint srcIndex = i * BlockSize; 28 | uint len = Math.Min(BlockSize, size - srcIndex); 29 | 30 | byte[] buffer = new byte[len]; 31 | int bytesRead = await data.ReadAsync(buffer, 0, (int)len, token); 32 | if (bytesRead != len) 33 | break; 34 | 35 | await _loader.MemDataAsync(buffer, i, token); 36 | Progress.Report((float)(i + 1) / blocks); 37 | } 38 | 39 | // Sending end is not required here 40 | // https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/serial-protocol.html#writing-data 41 | } 42 | 43 | public async Task UploadAndExecute(Stream uncompressedData, uint offset, uint unCompressedSize, uint entryPoint, CancellationToken token) 44 | { 45 | await Upload(uncompressedData, offset, unCompressedSize, token); 46 | 47 | // End memory transfer, 0 means execute, confusing 48 | await _loader.MemEndAsync(0, entryPoint, token); 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /ESPTool/Utils/ZlibCompressionHelper.cs: -------------------------------------------------------------------------------- 1 | using System.IO.Compression; 2 | 3 | namespace EspDotNet.Utils 4 | { 5 | 6 | 7 | public class ZlibCompressionHelper 8 | { 9 | public static void CompressToZlibStream(Stream inputStream, Stream compressedStream) 10 | { 11 | // Write the zlib header (0x78, 0x9C for default compression) 12 | compressedStream.WriteByte(0x78); 13 | compressedStream.WriteByte(0x9C); 14 | 15 | // Use DeflateStream to compress the data (without zlib header/footer) 16 | using (DeflateStream deflateStream = new DeflateStream(compressedStream, CompressionLevel.Optimal, leaveOpen: true)) 17 | { 18 | inputStream.CopyTo(deflateStream); 19 | } 20 | 21 | // Calculate the zlib footer (Adler-32 checksum) for the compressed data 22 | byte[] adler32Checksum = CalculateAdler32Checksum(inputStream); 23 | compressedStream.Write(adler32Checksum, 0, adler32Checksum.Length); 24 | } 25 | 26 | // Method to calculate Adler-32 checksum 27 | private static byte[] CalculateAdler32Checksum(Stream stream) 28 | { 29 | const uint MOD_ADLER = 65521; 30 | long position = stream.Position; 31 | stream.Position = 0; // Reset stream position 32 | 33 | uint a = 1, b = 0; 34 | 35 | int currentByte; 36 | while ((currentByte = stream.ReadByte()) != -1) 37 | { 38 | a = (a + (uint)currentByte) % MOD_ADLER; 39 | b = (b + a) % MOD_ADLER; 40 | } 41 | 42 | stream.Position = position; // Restore stream position 43 | 44 | uint checksum = b << 16 | a; 45 | 46 | byte[] result = new byte[4]; 47 | result[0] = (byte)(checksum >> 24 & 0xFF); 48 | result[1] = (byte)(checksum >> 16 & 0xFF); 49 | result[2] = (byte)(checksum >> 8 & 0xFF); 50 | result[3] = (byte)(checksum & 0xFF); 51 | 52 | return result; 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Koole Controls 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESPTool - ESP32 Flashing and Bootloader Tool 2 | 3 | **ESPTool** is a native C# implementation of Espressif's ESP tool ([esptool](https://github.com/espressif/esptool)). This library was created to enable direct interaction with ESP devices (such as ESP32) without relying on external applications. It provides a rich set of tools for flashing firmware, erasing flash memory, detecting chip types, and managing bootloader and softloader communication—all via serial communication. 4 | 5 | [![NuGet](https://img.shields.io/nuget/v/ESPTool.svg)](https://www.nuget.org/packages/ESPTool) 6 | 7 | > **Looking for a GUI tool?** Check out the [ESPFlasher GUI tool on GitHub](https://github.com/KooleControls/ESPFlasher). 8 | 9 | ## Features 10 | 11 | - **Bootloader and Softloader Communication:** 12 | - Execute pin sequences to start the bootloader. 13 | - Load and run a softloader. 14 | - **Firmware Operations:** 15 | - Upload firmware using dedicated tools (Flash, Flash Deflated, RAM). 16 | - Erase flash memory. 17 | - **Device Management:** 18 | - Detect chip type. 19 | - Reset the device. 20 | 21 | ## Supported Devices 22 | 23 | While the code is designed to support all ESP devices, testing has only been performed on a subset. Devices tested include: 24 | 25 | - [ ] ESP8266 26 | - [x] ESP32 27 | - [ ] ESP32-c2 28 | - [x] ESP32-c3 29 | - [ ] ESP32-c6 30 | - [ ] ESP32-h2 31 | - [ ] ESP32-p4 32 | - [ ] ESP32-s2 33 | - [x] ESP32-s3 34 | - [ ] ESP32-c6beta 35 | - [ ] ESP32-h2beta1 36 | - [ ] ESP32-h2beta2 37 | - [ ] ESP32-s3beta2 38 | 39 | ## Architecture Overview 40 | 41 | The library is organized into several self‑contained tools, each responsible for a specific aspect of ESP device communication and firmware handling: 42 | 43 | ### Loader Tools 44 | 45 | - **`BootloaderTool`** 46 | Initiates communication with the built‑in ROM bootloader on the ESP device. 47 | - **`SoftloaderTool`** 48 | Handles the process of uploading a softloader (stubloader) into RAM, which extends functionality with commands not available in the ROM bootloader. 49 | 50 | ### Firmware Upload Tools 51 | 52 | Each upload tool encapsulates a specific firmware upload mechanism: 53 | - **`UploadRamTool`** – For uploading firmware directly into RAM. 54 | - **`UploadFlashTool`** – For flashing firmware to the device’s flash memory. 55 | - **`UploadFlashDeflatedTool`** – For flashing compressed (deflated) firmware images. 56 | - **`FirmwareUploadTool`** – Wraps around an upload tool and manages firmware segmented transfers with progress reporting. 57 | 58 | ### Additional Tools 59 | 60 | - **`ChipTypeDetectTool`** – Detects the chip type of the connected device. 61 | - **`ChangeBaudrateTool`** – Handles baud rate changes. 62 | - **`FlashEraseTool`** – Erases the device’s flash memory. 63 | - **`ResetDeviceTool`** – Resets the device by executing a reset pin sequence. 64 | 65 | ## Example 66 | 67 | The main `ESPTool` class serves as a toolbox for creating and retrieving the various tools needed to interact with an ESP device. Its design forces the user to explicitly handle the device state by passing the appropriate loader and chip type when needed, reducing the risk of operating on a disconnected or unsupported device. 68 | 69 | For usage examples, see [Example.cs](./ESPTool/Example.cs). 70 | 71 | ## License 72 | 73 | This project is licensed under the MIT License. See [LICENSE](./LICENSE) for details. 74 | 75 | ## Additional Resources 76 | 77 | - **Official ESPTool Protocol Documentation:** [Espressif Docs](https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/serial-protocol.html) 78 | - **Stubloaders Location:** 79 | Typically found in the toolchain under: 80 | `\tools\python_env\idf5.0_py3.11_env\Lib\site-packages\esptool\targets\stub_flasher` 81 | 82 | --------------------------------------------------------------------------------