├── .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": "ARG3BwBgTsaDqYcASsg3Sco/JspSxAbOIsy3BABgfVoTCQkAwEwTdPQ/DeDyQGJEI6g0AUJJ0kSySSJKBWGCgIhAgycJABN19Q+Cl30U4xlE/8m/EwcADJRBqodjGOUAhUeFxiOgBQB5VYKABUdjh+YACUZjjcYAfVWCgEIFEwewDUGFY5XnAolHnMH1t5MGwA1jFtUAmMETBQAMgoCTBtANfVVjldcAmMETBbANgoC3dcs/QRGThQW6BsZhP2NFBQa3d8s/k4eHsQOnBwgD1kcIE3X1D5MGFgDCBsGCI5LXCDKXIwCnAAPXRwiRZ5OHBwRjHvcCN/fKPxMHh7GhZ7qXA6YHCLc2yz+3d8s/k4eHsZOGhrVjH+YAI6bHCCOg1wgjkgcIIaD5V+MG9fyyQEEBgoAjptcII6DnCN23NycAYHxLnYv1/zc3AGB8S52L9f+CgEERBsbdN7cnAGAjpgcCNwcACJjDmEN9/8hXskATRfX/BYlBAYKAQREGxtk/fd03BwBAtycAYJjDNycAYBxD/f+yQEEBgoBBESLEN8TKP5MHxABKwAOpBwEGxibCYwoJBEU3OcW9RxMExACBRGPWJwEERL2Ik7QUAH03hT8cRDcGgAATl8cAmeA3BgABt/b/AHWPtyYAYNjCkMKYQn3/QUeR4AVHMwnpQLqXIygkARzEskAiRJJEAklBAYKAQREGxhMHAAxjEOUCEwWwDZcAyP/ngIDjEwXADbJAQQEXA8j/ZwCD4hMHsA3jGOX+lwDI/+eAgOETBdANxbdBESLEJsIGxiqEswS1AGMXlACyQCJEkkRBAYKAA0UEAAUERTfttxMFAAwXA8j/ZwAD3nVxJsPO3v10hWn9cpOEhPqThwkHIsVKwdLc1tqmlwbHFpGzhCcAKokmhS6ElzDI/+eAgJOThwkHBWqKl7OKR0Ep5AVnfXUTBIX5kwcHB6KXM4QnABMFhfqTBwcHqpeihTOFJwCXMMj/54CAkCKFwUW5PwFFhWIWkbpAKkSaRApJ9llmWtZaSWGCgKKJY3OKAIVpTobWhUqFlwDI/+eAQOITdfUPAe1OhtaFJoWXMMj/54DAi06ZMwQ0QVm3EwUwBlW/cXH9ck7PUs1Wy17HBtci1SbTStFayWLFZsNqwe7eqokWkRMFAAIuirKKtosCwpcAyP/ngEBIhWdj7FcRhWR9dBMEhPqThwQHopczhCcAIoWXMMj/54AghX17Eww7+ZMMi/kThwQHk4cEB2KX5pcBSTMMJwCzjCcAEk1je00JY3GpA3mgfTWmhYgYSTVdNSaGjBgihZcwyP/ngCCBppkmmWN1SQOzB6lBY/F3A7MEKkFj85oA1oQmhowYToWXAMj/54Dg0xN19Q9V3QLEgUR5XY1NowEBAGKFlwDI/+eAYMR9+QNFMQDmhS0xY04FAOPinf6FZ5OHBweml4qX2pcjiqf4hQT5t+MWpf2RR+OG9PYFZ311kwcHBxMEhfmilzOEJwATBYX6kwcHB6qXM4UnAKKFlyDI/+eAgHflOyKFwUXxM8U7EwUAApcAyP/ngOA2hWIWkbpQKlSaVApZ+klqStpKSku6SypMmkwKTfZdTWGCgAERBs4izFExNwTOP2wAEwVE/5cAyP/ngKDKqocFRZXnskeT9wcgPsZ5OTcnAGAcR7cGQAATBUT/1Y8cx7JFlwDI/+eAIMgzNaAA8kBiRAVhgoBBEbfHyj8GxpOHxwAFRyOA5wAT18UAmMcFZ30XzMPIx/mNOpWqlbGBjMsjqgcAQTcZwRMFUAyyQEEBgoABESLMN8TKP5MHxAAmysRHTsYGzkrIqokTBMQAY/OVAK6EqcADKUQAJpkTWckAHEhjVfAAHERjXvkC4T593UhAJobOhZcAyP/ngCC7E3X1DwHFkwdADFzIXECml1zAXESFj1zE8kBiRNJEQkmySQVhgoDdNm2/t1dBSRlxk4f3hAFFPs6G3qLcptrK2M7W0tTW0trQ3s7izObK6sjuxpcAyP/ngICtt0fKPzd3yz+ThwcAEweHumPg5xSlOZFFaAixMYU5t/fKP5OHh7EhZz6XIyD3CLcFOEC3BzhAAUaThwcLk4UFADdJyj8VRSMg+QCXAMj/54DgGzcHAGBcRxMFAAK3xMo/k+cXEFzHlwDI/+eAoBq3RwBgiF+BRbd5yz9xiWEVEzUVAJcAyP/ngOCwwWf9FxMHABCFZkFmtwUAAQFFk4TEALdKyj8NapcAyP/ngOCrk4mJsRMJCQATi8oAJpqDp8kI9d+Dq8kIhUcjpgkIIwLxAoPHGwAJRyMT4QKjAvECAtRNR2OL5wZRR2OJ5wYpR2Of5wCDxzsAA8crAKIH2Y8RR2OW5wCDp4sAnEM+1EE2oUVIEJE+g8c7AAPHKwCiB9mPEWdBB2N+9wITBbANlwDI/+eAQJQTBcANlwDI/+eAgJMTBeAOlwDI/+eAwJKBNr23I6AHAJEHbb3JRyMT8QJ9twPHGwDRRmPn5gKFRmPm5gABTBME8A+dqHkXE3f3D8lG4+jm/rd2yz8KB5OGxro2lxhDAoeTBgcDk/b2DxFG42nW/BMH9wITd/cPjUZj7uYIt3bLPwoHk4aGvzaXGEMChxMHQAJjmucQAtQdRAFFlwDI/+eAIIoBRYE8TTxFPKFFSBB9FEk0ffABTAFEE3X0DyU8E3X8Dw08UTzjEQTsg8cbAElHY2X3MAlH43n36vUXk/f3Dz1H42P36jd3yz+KBxMHh8C6l5xDgocFRJ3rcBCBRQFFlwDI/+eAQIkd4dFFaBAVNAFEMagFRIHvlwDI/+eAwI0zNKAAKaAhR2OF5wAFRAFMYbcDrIsAA6TLALNnjADSB/X3mTll9cFsIpz9HH19MwWMQF3cs3eVAZXjwWwzBYxAY+aMAv18MwWMQF3QMYGXAMj/54Bgil35ZpT1tzGBlwDI/+eAYIld8WqU0bdBgZcAyP/ngKCIWfkzBJRBwbchR+OK5/ABTBMEAAw5t0FHzb9BRwVE453n9oOlywADpYsAVTK5v0FHBUTjk+f2A6cLAZFnY+jnHoOlSwEDpYsAMTGBt0FHBUTjlOf0g6cLARFnY2n3HAOnywCDpUsBA6WLADOE5wLdNiOsBAAjJIqwCb8DxwQAYwMHFAOniwDBFxMEAAxjE/cAwEgBR5MG8A5jRvcCg8dbAAPHSwABTKIH2Y8Dx2sAQgddj4PHewDiB9mP44T25hMEEAyFtTOG6wADRoYBBQexjuG3g8cEAP3H3ERjnQcUwEgjgAQAVb1hR2OW5wKDp8sBA6eLAYOmSwEDpgsBg6XLAAOliwCX8Mf/54BgeSqMMzSgAAG9AUwFRCm1EUcFROOd5+a3lwBgtENld30XBWb5jtGOA6WLALTDtEeBRfmO0Y60x/RD+Y7RjvTD1F91j1GP2N+X8Mf/54BAdwW1E/f3AOMXB+qT3EcAE4SLAAFMfV3jd5zbSESX8Mf/54DAYRhEVEAQQPmOYwenARxCE0f3/32P2Y4UwgUMQQTZvxFHtbVBRwVE45rn3oOniwADp0sBIyT5ACMi6QDJs4MlSQDBF5Hlic8BTBMEYAyhuwMniQBjZvcGE/c3AOMbB+IDKIkAAUYBRzMF6ECzhuUAY2n3AOMHBtIjJKkAIyLZAA2zM4brABBOEQeQwgVG6b8hRwVE45Tn2AMkiQAZwBMEgAwjJAkAIyIJADM0gAC9swFMEwQgDMW5AUwTBIAM5bEBTBMEkAzFsRMHIA1jg+cMEwdADeOR57oDxDsAg8crACIEXYyX8Mf/54BgXwOsxABBFGNzhAEijOMPDLbAQGKUMYCcSGNV8ACcRGNa9Arv8I/hdd3IQGKGk4WLAZfwx//ngGBbAcWTB0AM3MjcQOKX3MDcRLOHh0HcxJfwx//ngEBaFb4JZRMFBXEDrMsAA6SLAJfwx//ngEBMtwcAYNhLtwYAAcEWk1dHARIHdY+9i9mPs4eHAwFFs9WHApfwx//ngOBMEwWAPpfwx//ngOBI3bSDpksBA6YLAYOlywADpYsA7/Av98G8g8U7AIPHKwAThYsBogXdjcEVqTptvO/w79qBtwPEOwCDxysAE4yLASIEXYzcREEUxeORR4VLY/6HCJMHkAzcyHm0A6cNACLQBUizh+xAPtaDJ4qwY3P0AA1IQsY6xO/wb9YiRzJIN8XKP+KFfBCThsoAEBATBUUCl/DH/+eA4Ek398o/kwjHAIJXA6eIsIOlDQAdjB2PPpyyVyOk6LCqi76VI6C9AJOHygCdjQHFoWdjlvUAWoVdOCOgbQEJxNxEmcPjQHD5Y98LAJMHcAyFv4VLt33LP7fMyj+TjY26k4zMAOm/45ULntxE44IHnpMHgAyxt4OniwDjmwecAUWX8Mf/54DAOQllEwUFcZfwx//ngCA2l/DH/+eA4DlNugOkywDjBgSaAUWX8Mf/54AgNxMFgD6X8Mf/54CgMwKUQbr2UGZU1lRGWbZZJlqWWgZb9ktmTNZMRk22TQlhgoA=",
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": "FIADYACAA2BIAMo/BIADYDZBAIH7/wxJwCAAmQjGBAAAgfj/wCAAqAiB9/+goHSICOAIACH2/8AgAIgCJ+jhHfAAAAAIAABgHAAAYBAAAGA2QQAh/P/AIAA4AkH7/8AgACgEICCUnOJB6P9GBAAMODCIAcAgAKgIiASgoHTgCAALImYC6Ib0/yHx/8AgADkCHfAAAPAryz9oq8o/hIAAAEBAAACo68o/9CvLPzZBALH5/yCgdBARICU2AZYaBoH2/5KhAZCZEZqYwCAAuAmR8/+goHSaiMAgAJIYAJCQ9BvJwMD0wCAAwlgAmpvAIACiSQDAIACSGACB6v+QkPSAgPSHmUeB5f+SoQGQmRGamMAgAMgJoeX/seP/h5wXxgEAfOiHGt7GCADAIACJCsAgALkJRgIAwCAAuQrAIACJCZHX/5qIDAnAIACSWAAd8AAAVCAAYFQwAGA2QQCR/f/AIACICYCAJFZI/5H6/8AgAIgJgIAkVkj/HfAAAAAsIABgACAAYAAAAAg2QQAQESCl/P8h+v8MCMAgAIJiAJH6/4H4/8AgAJJoAMAgAJgIVnn/wCAAiAJ88oAiMCAgBB3wAAAAAEA2QQAQESDl+/8Wav+B7P+R+//AIACSaADAIACYCFZ5/x3wAADoCABAuAgAQDaBAIH9/+AIABwGBgwAAABgVEMMCAwa0JURDI05Me0CiWGpUZlBiSGJEdkBLA8MzAxLgfL/4AgAUETAWjNaIuYUzQwCHfAAABQoAEA2QQAgoiCB/f/gCAAd8AAAcOL6PwggAGC8CgBAyAoAQDZhABARIGXv/zH5/70BrQOB+v/gCABNCgwS7OqIAZKiAJCIEIkBEBEg5fP/kfL/oKIBwCAAiAmgiCDAIACJCbgBrQOB7v/gCACgJIMd8AAAWIDKP/8PAABkq8o/NkEAgfz/DBmSSAAwnEGZKJH6/zkYKTgwMLSaIiozMDxBOUgx9v8ioAAyAwAiaAUnEwmBv//gCABGAwAAEBEgZfb/LQqMGiKgxR3wAP///wAEIABg9AgAQAwJAEAACQBANoEAMeT/KEMWghEQESAl5v8W+hAM+AwEJ6gMiCMMEoCANIAkkyBAdBARICXo/xARIOXg/yHa/yICABYyCqgjgev/QCoRFvQEJyg8gaH/4AgAgej/4AgA6CMMAgwaqWGpURyPQO4RDI3CoNgMWylBKTEpISkRKQGBl//gCACBlP/gCACGAgAAAKCkIYHb/+AIABwKBiAAAAAnKDmBjf/gCACB1P/gCADoIwwSHI9A7hEMjSwMDFutAilhKVFJQUkxSSFJEUkBgYP/4AgAgYH/4AgARgEAgcn/4AgADBqGDQAAKCMMGUAiEZCJAcwUgIkBkb//kCIQkb7/wCAAImkAIVr/wCAAgmIAwCAAiAJWeP8cCgwSQKKDKEOgIsApQygjqiIpIx3wAAA2gQCBaf/gCAAsBoYPAAAAga//4AgAYFRDDAgMGtCVEe0CqWGpUYlBiTGZITkRiQEsDwyNwqASsqAEgVz/4AgAgVr/4AgAWjNaIlBEwOYUvx3wAAAUCgBANmEAQYT/WDRQM2MWYwtYFFpTUFxBRgEAEBEgZeb/aESmFgRoJGel7xARIGXM/xZq/1F6/2gUUgUAFkUGgUX/4AgAYFB0gqEAUHjAd7MIzQO9Aq0Ghg4AzQe9Aq0GUtX/EBEgZfT/OlVQWEEMCUYFAADCoQCZARARIOXy/5gBctcBG5mQkHRgp4BwsoBXOeFww8AQESAl8f+BLv/gCACGBQDNA70CrQaB1f/gCACgoHSMSiKgxCJkBSgUOiIpFCg0MCLAKTQd8ABcBwBANkEAgf7/4AgAggoYDAmCyPwMEoApkx3wNkEAgfj/4AgAggoYDAmCyP0MEoApkx3wvP/OP0QAyj9MAMo/QCYAQDQmAEDQJgBANmEAfMitAoeTLTH3/8YFAACoAwwcvQGB9//gCACBj/6iAQCICOAIAKgDgfP/4AgA5hrdxgoAAABmAyYMA80BDCsyYQCB7v/gCACYAYHo/zeZDagIZhoIMeb/wCAAokMAmQgd8EAAyj8AAMo/KCYAQDZBACH8/4Hc/8gCqAix+v+B+//gCAAMCIkCHfCQBgBANkEAEBEgpfP/jLqB8v+ICIxIEBEgpfz/EBEg5fD/FioAoqAEgfb/4AgAHfBIBgBANkEAEBEgpfD/vBqR5v+ICRuoqQmR5f8MCoqZIkkAgsjBDBmAqYOggHTMiqKvQKoiIJiTnNkQESBl9/9GBQCtAoHv/+AIABARIOXq/4xKEBEg5ff/HfAAADZBAKKgwBARIOX5/x3wAAA2QQCCoMCtAoeSEaKg2xARIGX4/6Kg3EYEAAAAAIKg24eSCBARICX3/6Kg3RARIKX2/x3wNkEAOjLGAgAAogIAGyIQESCl+/83kvEd8AAAAFwcAEAgCgBAaBwAQHQcAEA2ISGi0RCB+v/gCACGDwAAUdz+DBRARBGCBQBAQ2PNBL0BrQKMmBARICWp/8YBAAAAgfD/4AgAoKB0/DrNBL0BotEQge3/4AgASiJAM8BW4/siogsQIrCtArLREIHo/+AIAK0CHAsQESCl9v8tA4YAACKgYx3wAACIJgBAhBsAQJQmAECQGwBANkEAEBEgpdv/rIoME0Fy//AzAYyyqASB9v/gCACtA8YJAK0DgfT/4AgAqASB8//gCAAGCQAQESDl1v8MGPCIASwDoIODrQgWkgCB7P/gCACGAQAAgej/4AgAHfBgBgBANkEhYqQd4GYRGmZZBgwXUqAAYtEQUKUgQHcRUmYaEBEg5ff/R7cCxkIArQaBt//gCADGLwCRmP5Qc8CCCQBAd2PNB70BrQIWqAAQESBlmP/GAQAAAIGt/+AIAKCgdIyqDAiCZhZ9CEYSAAAAEBEgpeP/vQetARARICXn/xARIKXi/80HELEgYKYggaH/4AgAeiJ6VTe1yIKhB8CIEZKkHRqI4JkRiAgamZgJgHXAlzeDxur/DAiCRmyipBsQqqCBz//gCABWCv+yoguiBmwQu7AQESClsgD36hL2Rw+Sog0QmbB6maJJABt3hvH/fOmXmsFmRxKSoQeCJhrAmREamYkJN7gCh7WLIqILECKwvQatAoGA/+AIABARIOXY/60CHAsQESBl3P8QESDl1/8MGhARIOXm/x3wAADKP09IQUmwgABgoTrYUJiAAGC4gABgKjEdj7SAAGD4K8s/rIA3QJggDGA8gjdArIU3QAgACGCAIQxgEIA3QBCAA2BQgDdADAAAYDhAAGCYLMs///8AACyBAGAQQAAA/CvLPwwsyz98kABg/4///4CQAGCEkABgeJAAYFAAyj9UAMo/WCzLPxQAAGDw//8A+CvLP1gAyj9wgMo/gAcAQHgbAEC4JgBAZCYAQHQfAEDsCgBABCAAQFQJAEBQCgBAAAYAQBwpAEAkJwBACCgAQOQGAEB0gQRAnAkAQPwJAEAICgBAqAYAQIQJAEBsCQBAkAkAQCgIAEDYBgBANgEBIcH/DAoiYRCB5f/gCAAQESDlr/8WigQxvP8hvP9Bvf/AIAApAwwCwCAAKQTAIAApA1G5/zG5/2G5/8AgADkFwCAAOAZ89BBEAUAzIMAgADkGwCAAKQWGAQBJAksiBgIAIaj/Ma//QqAANzLsEBEgJcD/DEuiwUAQESClw/8ioQEQESDlvv8xb/2QIhEqI8AgADkCQaT/IUf9SQIQESClqP8tChb6BSGm/sGn/qgCDCuBqf7gCABBnP+xnf8cGgwMwCAAqQSBt//gCAAMGvCqAYEl/+AIALGW/6gCDBWBsv/gCACoAoEd/+AIAKgCga//4AgAQZD/wCAAKARQIiDAIAApBIYWABARIGWg/6yaQYr/HBqxiv/AIACiZAAgwiCBoP/gCAAhh/8MRAwawCAASQLwqgHGCAAAALGD/80KDFqBmP/gCABBgP9SoQHAIAAoBCwKUCIgwCAAKQSBAv/gCACBk//gCAAhef/AIAAoAsy6HMRAIhAiwvgMFCCkgwwLgYz/4AgAgYv/4AgAXQqMmkG0/QwSIkQARhQAHIYMEmlBYsEgqWFpMakhqRGpAf0K7QopUQyNwqCfsqAEIKIggXb94AgAcgEiHGhix+dgYHRnuAEtBTyGDBV3NgEMBUGg/VAiICAgdCJEABbiAKFZ/4Fy/+AIAIFn/eAIAPFW/wwdDBwMG+KhAEDdEQDMEWC7AQwKgWr/4AgAMZD9YtMrhhYAwCAAUgcAUFB0FhUFDBrwqgHAIAAiRwCByf7gCACionHAqhGBX//gCACBXv/gCABxQv986MAgAFgHfPqAVRAQqgHAIABZB4FY/+AIAIFX/+AIACCiIIFW/+AIAHEz/kH1/MAgACgEFmL5DAfAIABYBAwSwCAAeQQiQTQiBQEMKHnhIkE1glEbHDd3EiQcR3cSIWaSISIFA3IFAoAiEXAiIGZCEiglwCAAKAIp4YYBAAAAHCIiURsQESBlmf+yoAiiwTQQESDlnP+yBQMiBQKAuxEgSyAhGf8gIPRHshqioMAQESCll/+ioO4QESAll/8QESDllf+G2P8iBQEcRyc3N/YiGwYJAQAiwi8gIHS2QgIGJQBxC/9wIqAoAqACAAAiwv4gIHQcJye3Akb/AHEF/3AioCgCoAIAcsIwcHB0tlfFhvkALEkMByKgwJcUAob3AHnhDHKtBxARIGWQ/60HEBEg5Y//EBEgZY7/EBEgJY7/DIuiwTQiwv8QESBlkf9WIv1GQAAMElakOcLBIL0ErQSBCP/gCABWqjgcS6LBIBARICWP/4bAAAwSVnQ3gQL/4AgAoCSDxtoAJoQEDBLG2AAoJXg1cIIggIC0Vtj+EBEgZUH/eiKsmgb4/0EZ/aCsQYIEAIz4gS794AgARgMActfwRgMAAACB8f7gCAAW6v4G7v9wosDMF8anAKCA9FaY/EYKAEEK/aCg9YIEAJwYgR/94AgAxgMAfPgAiBGKd8YCAIHj/uAIABbK/kbf/wwYAIgRcKLAdzjKhgkAQfz8oKxBggQAjOiBEv3gCAAGAwBy1/AGAwAAgdX+4AgAFvr+BtL/cKLAVif9hosADAcioMAmhAIGqgAMBy0HRqgAJrT1Bn4ADBImtAIGogC4NaglDAcQESClgf+gJ4OGnQAMGWa0X4hFIKkRDAcioMKHugIGmwC4VaglkmEWEBEgZTf/kiEWoJeDRg4ADBlmtDSIRSCpEQwHIqDCh7oCRpAAKDW4VaglIHiCkmEWEBEgZTT/Ic38DAiSIRaJYiLSK3JiAqCYgy0JBoMAkcf8DAeiCQAioMZ3mgKGgQB4JbLE8CKgwLeXAiIpBQwHkqDvRgIAeoWCCBgbd4CZMLcn8oIFBXIFBICIEXCIIHIFBgB3EYB3IIIFB4CIAXCIIICZwIKgwQwHkCiTxm0Aga/8IqDGkggAfQkWmRqYOAwHIqDIdxkCBmcAKFiSSABGYgAciQwHDBKXFAIGYgD4dehl2FXIRbg1qCWBev7gCAAMCH0KoCiDBlsADBImRAJGVgCRX/6BX/7AIAB4CUAiEYB3ECB3IKglwCAAeQmRWv4MC8AgAHgJgHcQIHcgwCAAeQmRVv7AIAB4CYB3ECB3IMAgAHkJkVL+wCAAeAmAdxAgJyDAIAApCYFb/uAIAAYgAABAkDQMByKgwHcZAoY9AEBEQYvFfPhGDwCoPIJhFZJhFsJhFIFU/uAIAMIhFIIhFSgseByoDJIhFnByECYCDcAgANgKICgw0CIQIHcgwCAAeQobmcLMEEc5vsZ//2ZEAkZ+/wwHIqDAhiYADBImtALGIQAhL/6IVXgliQIhLv55AgwCBh0A8Sr+DAfIDwwZssTwjQctB7Apk8CJgyCIECKgxneYYKEk/n0I2AoioMm3PVOw4BQioMBWrgQtCIYCAAAqhYhoSyKJB40JIO3AKny3Mu0WaNjpCnkPxl//DBJmhBghFP6CIgCMGIKgyAwHeQIhEP55AgwSgCeDDAdGAQAADAcioP8goHQQESClUv9woHQQESDlUf8QESClUP9W8rAiBQEcJyc3H/YyAkbA/iLC/SAgdAz3J7cCxrz+cf/9cCKgKAKgAgAAcqDSdxJfcqDUd5ICBiEARrX+KDVYJRARIKU3/40KVmqsoqJxwKoRgmEVgQD+4AgAcfH9kfH9wCAAeAeCIRVwtDXAdxGQdxBwuyAgu4KtCFC7woH//eAIAKKj6IH0/eAIAMag/gAA2FXIRbg1qCUQESAlXP8GnP4AsgUDIgUCgLsRILsgssvwosUYEBEgJSL/BpX+ACIFA3IFAoAiEXAiIIHt/eAIAHEH/CLC8Ig3gCJjFjKjiBeKgoCMQUYDAAAAgmEVEBEgpQb/giEVkicEphkFkicCl6jnEBEgZez+Fmr/qBfNArLFGIHc/eAIAIw6UqDEWVdYFypVWRdYNyAlwCk3gdb94AgABnf+AAAiBQOCBQJyxRiAIhFYM4AiICLC8FZFCvZSAoYnACKgyUYsAFGz/YHk+6gFKfGgiMCJgYgmrQmHsgEMOpJhFqJhFBARIOX9/qIhFIGq/akB6AWhqf3dCL0HwsE88sEggmEVgbz94AgAuCbNCqjxkiEWoLvAuSagIsC4Bap3qIGCIRWquwwKuQXAqYOAu8Cg0HTMiuLbgK0N4KmDrCqtCIJhFZJhFsJhFBARIKUP/4IhFZIhFsIhFIkFBgEAAAwcnQyMslgzjHXAXzHAVcCWNfXWfAAioMcpUwZA/lbcjygzFoKPIqDIBvv/KCVW0o4QESBlJf+ionHAqhGBif3gCACBlv3gCACGNP4oNRbSjBARIGUj/6Kj6IGC/eAIAOACAAYu/h3wAAAANkEAnQKCoMAoA4eZD8wyDBKGBwAMAikDfOKGDwAmEgcmIhiGAwAAAIKg24ApI4eZKgwiKQN88kYIAAAAIqDcJ5kKDBIpAy0IBgQAAACCoN188oeZBgwSKQMioNsd8AAA",
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 | [](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 |
--------------------------------------------------------------------------------