From cfae564668d2b6f4f9dc718187eb22143c4f24ab Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Tue, 7 Apr 2026 16:02:58 +0200 Subject: [PATCH 1/5] feature: Command Line input buffer --- js/console.js | 47 +++++++++++++++++++++++++++++++++++++++++++ src/console.ts | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/js/console.js b/js/console.js index 1730d33f..7eb3d335 100644 --- a/js/console.js +++ b/js/console.js @@ -17,6 +17,10 @@ export class ESP32ToolConsole { this.allowInput = allowInput; this.console = null; this.cancelConnection = null; + // Command history buffer + this.commandHistory = []; + this.historyIndex = -1; + this.currentInput = ""; } logs() { @@ -181,6 +185,16 @@ export class ESP32ToolConsole { ev.preventDefault(); ev.stopPropagation(); this._sendCommand(); + } else if (ev.key === "ArrowUp") { + ev.preventDefault(); + this._navigateHistory(1, input); + } else if (ev.key === "ArrowDown") { + ev.preventDefault(); + this._navigateHistory(-1, input); + } else { + if (this.historyIndex !== -1) { + this.historyIndex = -1; + } } }); } @@ -260,9 +274,42 @@ export class ESP32ToolConsole { } } + _navigateHistory(direction, input) { + if (this.commandHistory.length === 0) return; + + if (this.historyIndex === -1) { + this.currentInput = input.value; + } + + const nextIndex = this.historyIndex + direction; + + if (nextIndex < 0) { + this.historyIndex = -1; + input.value = this.currentInput; + } else if (nextIndex < this.commandHistory.length) { + this.historyIndex = nextIndex; + input.value = this.commandHistory[this.historyIndex]; + } + + const len = input.value.length; + input.setSelectionRange(len, len); + } + async _sendCommand() { const input = this.containerElement.querySelector(".esp32tool-console-input"); const command = input.value; + + if (command.trim() !== "") { + if (this.commandHistory[0] !== command) { + this.commandHistory.unshift(command); + if (this.commandHistory.length > 100) { + this.commandHistory.pop(); + } + } + } + this.historyIndex = -1; + this.currentInput = ""; + if (!this.port.writable) { this.console.addLine("Terminal disconnected: port not writable"); return; diff --git a/src/console.ts b/src/console.ts index edd4cedd..b8ad9efe 100644 --- a/src/console.ts +++ b/src/console.ts @@ -9,6 +9,11 @@ export class ESP32ToolConsole { private containerElement: HTMLElement; private allowInput: boolean; + // Command history buffer + private commandHistory: string[] = []; + private historyIndex: number = -1; + private currentInput: string = ""; + constructor( port: SerialPort, containerElement: HTMLElement, @@ -164,6 +169,17 @@ export class ESP32ToolConsole { ev.preventDefault(); ev.stopPropagation(); this._sendCommand(); + } else if (ev.key === "ArrowUp") { + ev.preventDefault(); + this._navigateHistory(1, input); + } else if (ev.key === "ArrowDown") { + ev.preventDefault(); + this._navigateHistory(-1, input); + } else { + // User is editing — reset history navigation to live input + if (this.historyIndex !== -1) { + this.historyIndex = -1; + } } }); } @@ -242,11 +258,49 @@ export class ESP32ToolConsole { } } + private _navigateHistory(direction: 1 | -1, input: HTMLInputElement) { + if (this.commandHistory.length === 0) return; + + // Save current unsent input before navigating away + if (this.historyIndex === -1) { + this.currentInput = input.value; + } + + const nextIndex = this.historyIndex + direction; + + if (nextIndex < 0) { + // Back to unsent draft + this.historyIndex = -1; + input.value = this.currentInput; + } else if (nextIndex < this.commandHistory.length) { + this.historyIndex = nextIndex; + input.value = this.commandHistory[this.historyIndex]; + } + + // Move cursor to end + const len = input.value.length; + input.setSelectionRange(len, len); + } + private async _sendCommand() { const input = this.containerElement.querySelector( ".esp32tool-console-input", )!; const command = input.value; + + if (command.trim() !== "") { + // Avoid consecutive duplicates, cap at 100 + if (this.commandHistory[0] !== command) { + this.commandHistory.unshift(command); + if (this.commandHistory.length > 100) { + this.commandHistory.pop(); + } + } + } + // Reset history navigation state + this.historyIndex = -1; + this.currentInput = ""; + if (!this.port.writable) { this.console!.addLine("Terminal disconnected: port not writable"); return; From f25c4075df01eef92b3724974131b00251529d92 Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Tue, 7 Apr 2026 16:14:52 +0200 Subject: [PATCH 2/5] refactor: build js/util from src/util --- js/util/console-color.js | 495 ++++++++++++++++++------------ js/util/line-break-transformer.js | 58 ++-- js/util/timestamp-transformer.js | 59 ++-- package.json | 3 +- tsconfig.util.json | 14 + 5 files changed, 373 insertions(+), 256 deletions(-) create mode 100644 tsconfig.util.json diff --git a/js/util/console-color.js b/js/util/console-color.js index 198b0dd7..b38a3451 100644 --- a/js/util/console-color.js +++ b/js/util/console-color.js @@ -1,177 +1,235 @@ export class ColoredConsole { - constructor(targetElement) { - this.targetElement = targetElement; - this.state = { - bold: false, - italic: false, - underline: false, - strikethrough: false, - foregroundColor: null, - backgroundColor: null, - carriageReturn: false, - lines: [], - secret: false, - blink: false, - rapidBlink: false, - }; - } - - logs() { - if (this.state.lines.length > 0) { - this.processLines(); + constructor(targetElement) { + this.targetElement = targetElement; + this.state = { + bold: false, + italic: false, + underline: false, + strikethrough: false, + foregroundColor: null, + backgroundColor: null, + carriageReturn: false, + lines: [], + secret: false, + blink: false, + rapidBlink: false, + }; } - return this.targetElement.innerText; - } - - processLine(line) { - // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape sequences - const re = /(?:\x1B|\\x1B)(?:\[(.*?)[@-~]|\].*?(?:\x07|\x1B\\))/g; - let i = 0; - - const lineSpan = document.createElement("span"); - lineSpan.classList.add("line"); - - const addSpan = (content) => { - if (content === "") return; - - const span = document.createElement("span"); - if (this.state.bold) span.classList.add("log-bold"); - if (this.state.italic) span.classList.add("log-italic"); - if (this.state.underline) span.classList.add("log-underline"); - if (this.state.strikethrough) span.classList.add("log-strikethrough"); - if (this.state.secret) span.classList.add("log-secret"); - if (this.state.blink) span.classList.add("log-blink"); - if (this.state.rapidBlink) span.classList.add("log-rapid-blink"); - if (this.state.foregroundColor !== null) - span.classList.add(`log-fg-${this.state.foregroundColor}`); - if (this.state.backgroundColor !== null) - span.classList.add(`log-bg-${this.state.backgroundColor}`); - span.appendChild(document.createTextNode(content)); - lineSpan.appendChild(span); - - if (this.state.secret) { - const redacted = document.createElement("span"); - redacted.classList.add("log-secret-redacted"); - redacted.appendChild(document.createTextNode("[redacted]")); - lineSpan.appendChild(redacted); - } - }; - - while (true) { - const match = re.exec(line); - if (match === null) break; - - const j = match.index; - addSpan(line.substring(i, j)); - i = j + match[0].length; - - if (match[1] === undefined) continue; - - for (const colorCode of match[1].split(";")) { - switch (parseInt(colorCode)) { - case 0: - this.state.bold = false; - this.state.italic = false; - this.state.underline = false; - this.state.strikethrough = false; - this.state.foregroundColor = null; - this.state.backgroundColor = null; - this.state.secret = false; - this.state.blink = false; - this.state.rapidBlink = false; - break; - case 1: this.state.bold = true; break; - case 3: this.state.italic = true; break; - case 4: this.state.underline = true; break; - case 5: this.state.blink = true; this.state.rapidBlink = false; break; - case 6: this.state.rapidBlink = true; this.state.blink = false; break; - case 8: this.state.secret = true; break; - case 9: this.state.strikethrough = true; break; - case 22: this.state.bold = false; break; - case 23: this.state.italic = false; break; - case 24: this.state.underline = false; break; - case 25: this.state.blink = false; this.state.rapidBlink = false; break; - case 28: this.state.secret = false; break; - case 29: this.state.strikethrough = false; break; - case 30: this.state.foregroundColor = "black"; break; - case 31: this.state.foregroundColor = "red"; break; - case 32: this.state.foregroundColor = "green"; break; - case 33: this.state.foregroundColor = "yellow"; break; - case 34: this.state.foregroundColor = "blue"; break; - case 35: this.state.foregroundColor = "magenta"; break; - case 36: this.state.foregroundColor = "cyan"; break; - case 37: this.state.foregroundColor = "white"; break; - case 39: this.state.foregroundColor = null; break; - case 40: this.state.backgroundColor = "black"; break; - case 41: this.state.backgroundColor = "red"; break; - case 42: this.state.backgroundColor = "green"; break; - case 43: this.state.backgroundColor = "yellow"; break; - case 44: this.state.backgroundColor = "blue"; break; - case 45: this.state.backgroundColor = "magenta"; break; - case 46: this.state.backgroundColor = "cyan"; break; - case 47: this.state.backgroundColor = "white"; break; - case 49: this.state.backgroundColor = null; break; + logs() { + if (this.state.lines.length > 0) { + this.processLines(); } - } + return this.targetElement.innerText; } - addSpan(line.substring(i)); - return lineSpan; - } - - processLines() { - const atBottom = - this.targetElement.scrollTop > - this.targetElement.scrollHeight - this.targetElement.offsetHeight - 50; - const prevCarriageReturn = this.state.carriageReturn; - const fragment = document.createDocumentFragment(); - - if (this.state.lines.length === 0) { - return; - } - - for (const line of this.state.lines) { - // A lone \r is a pure carriage-return signal — update state but don't - // create a DOM node for it (it has no renderable content). - if (line === "\r") { - this.state.carriageReturn = true; - continue; - } - if (this.state.carriageReturn && line !== "\n") { - if (fragment.childElementCount) { - fragment.removeChild(fragment.lastChild); + processLine(line) { + // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape sequences + // eslint-disable-next-line no-control-regex + const re = /(?:\x1B|\\x1B)(?:\[(.*?)[@-~]|\].*?(?:\x07|\x1B\\))/g; + let i = 0; + const lineSpan = document.createElement("span"); + lineSpan.classList.add("line"); + const addSpan = (content) => { + if (content === "") + return; + const span = document.createElement("span"); + if (this.state.bold) + span.classList.add("log-bold"); + if (this.state.italic) + span.classList.add("log-italic"); + if (this.state.underline) + span.classList.add("log-underline"); + if (this.state.strikethrough) + span.classList.add("log-strikethrough"); + if (this.state.secret) + span.classList.add("log-secret"); + if (this.state.blink) + span.classList.add("log-blink"); + if (this.state.rapidBlink) + span.classList.add("log-rapid-blink"); + if (this.state.foregroundColor !== null) + span.classList.add(`log-fg-${this.state.foregroundColor}`); + if (this.state.backgroundColor !== null) + span.classList.add(`log-bg-${this.state.backgroundColor}`); + span.appendChild(document.createTextNode(content)); + lineSpan.appendChild(span); + if (this.state.secret) { + const redacted = document.createElement("span"); + redacted.classList.add("log-secret-redacted"); + redacted.appendChild(document.createTextNode("[redacted]")); + lineSpan.appendChild(redacted); + } + }; + while (true) { + const match = re.exec(line); + if (match === null) + break; + const j = match.index; + addSpan(line.substring(i, j)); + i = j + match[0].length; + if (match[1] === undefined) + continue; + for (const colorCode of match[1].split(";")) { + switch (parseInt(colorCode)) { + case 0: + // reset + this.state.bold = false; + this.state.italic = false; + this.state.underline = false; + this.state.strikethrough = false; + this.state.foregroundColor = null; + this.state.backgroundColor = null; + this.state.secret = false; + this.state.blink = false; + this.state.rapidBlink = false; + break; + case 1: + this.state.bold = true; + break; + case 3: + this.state.italic = true; + break; + case 4: + this.state.underline = true; + break; + case 5: + this.state.blink = true; + this.state.rapidBlink = false; + break; + case 6: + this.state.rapidBlink = true; + this.state.blink = false; + break; + case 8: + this.state.secret = true; + break; + case 9: + this.state.strikethrough = true; + break; + case 22: + this.state.bold = false; + break; + case 23: + this.state.italic = false; + break; + case 24: + this.state.underline = false; + break; + case 25: + this.state.blink = false; + this.state.rapidBlink = false; + break; + case 28: + this.state.secret = false; + break; + case 29: + this.state.strikethrough = false; + break; + case 30: + this.state.foregroundColor = "black"; + break; + case 31: + this.state.foregroundColor = "red"; + break; + case 32: + this.state.foregroundColor = "green"; + break; + case 33: + this.state.foregroundColor = "yellow"; + break; + case 34: + this.state.foregroundColor = "blue"; + break; + case 35: + this.state.foregroundColor = "magenta"; + break; + case 36: + this.state.foregroundColor = "cyan"; + break; + case 37: + this.state.foregroundColor = "white"; + break; + case 39: + this.state.foregroundColor = null; + break; + case 40: + this.state.backgroundColor = "black"; + break; + case 41: + this.state.backgroundColor = "red"; + break; + case 42: + this.state.backgroundColor = "green"; + break; + case 43: + this.state.backgroundColor = "yellow"; + break; + case 44: + this.state.backgroundColor = "blue"; + break; + case 45: + this.state.backgroundColor = "magenta"; + break; + case 46: + this.state.backgroundColor = "cyan"; + break; + case 47: + this.state.backgroundColor = "white"; + break; + case 49: + this.state.backgroundColor = null; + break; + } + } } - } - const hadCarriageReturn = line.endsWith("\r"); - fragment.appendChild(this.processLine(line.replace(/\r/g, ""))); - this.state.carriageReturn = hadCarriageReturn; - } - - if ( - prevCarriageReturn && - fragment.childElementCount > 0 && - this.targetElement.lastChild - ) { - this.targetElement.replaceChild(fragment, this.targetElement.lastChild); - } else { - this.targetElement.appendChild(fragment); + addSpan(line.substring(i)); + return lineSpan; } - - this.state.lines = []; - - if (atBottom) { - this.targetElement.scrollTop = this.targetElement.scrollHeight; + processLines() { + const atBottom = this.targetElement.scrollTop > + this.targetElement.scrollHeight - this.targetElement.offsetHeight - 50; + const prevCarriageReturn = this.state.carriageReturn; + const fragment = document.createDocumentFragment(); + if (this.state.lines.length === 0) { + return; + } + for (const line of this.state.lines) { + // A lone \r is a pure carriage-return signal — update state but don't + // create a DOM node for it (it has no renderable content). + if (line === "\r") { + this.state.carriageReturn = true; + continue; + } + if (this.state.carriageReturn && line !== "\n") { + if (fragment.childElementCount) { + fragment.removeChild(fragment.lastChild); + } + } + const hadCarriageReturn = line.endsWith("\r"); + fragment.appendChild(this.processLine(line.replace(/\r/g, ""))); + this.state.carriageReturn = hadCarriageReturn; + } + if (prevCarriageReturn && + fragment.childElementCount > 0 && + this.targetElement.lastChild) { + this.targetElement.replaceChild(fragment, this.targetElement.lastChild); + } + else { + this.targetElement.appendChild(fragment); + } + this.state.lines = []; + // Keep scroll at bottom + if (atBottom) { + this.targetElement.scrollTop = this.targetElement.scrollHeight; + } } - } - - addLine(line) { - // Processing of lines is deferred for performance reasons - if (this.state.lines.length === 0) { - setTimeout(() => this.processLines(), 0); + addLine(line) { + // Processing of lines is deferred for performance reasons + if (this.state.lines.length === 0) { + setTimeout(() => this.processLines(), 0); + } + this.state.lines.push(line); } - this.state.lines.push(line); - } } - export const coloredConsoleStyles = ` .log { flex: 1; @@ -182,42 +240,95 @@ export const coloredConsoleStyles = ` padding: 16px; overflow: auto; line-height: 1.45; - border-radius: 0; + border-radius: 3px; white-space: pre-wrap; overflow-wrap: break-word; color: #ddd; - min-height: 0; } - .log-bold { font-weight: bold; } - .log-italic { font-style: italic; } - .log-underline { text-decoration: underline; } - .log-strikethrough { text-decoration: line-through; } - .log-underline.log-strikethrough { text-decoration: underline line-through; } - .log-blink { animation: blink 1s step-end infinite; } - .log-rapid-blink { animation: blink 0.4s step-end infinite; } - @keyframes blink { 50% { opacity: 0; } } + .log-bold { + font-weight: bold; + } + .log-italic { + font-style: italic; + } + .log-underline { + text-decoration: underline; + } + .log-strikethrough { + text-decoration: line-through; + } + .log-underline.log-strikethrough { + text-decoration: underline line-through; + } + .log-blink { + animation: blink 1s step-end infinite; + } + .log-rapid-blink { + animation: blink 0.4s step-end infinite; + } + @keyframes blink { + 50% { + opacity: 0; + } + } .log-secret { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } - .log-secret-redacted { opacity: 0; width: 1px; font-size: 1px; } - .log-fg-black { color: rgb(128, 128, 128); } - .log-fg-red { color: rgb(255, 0, 0); } - .log-fg-green { color: rgb(0, 255, 0); } - .log-fg-yellow { color: rgb(255, 255, 0); } - .log-fg-blue { color: rgb(0, 0, 255); } - .log-fg-magenta { color: rgb(255, 0, 255); } - .log-fg-cyan { color: rgb(0, 255, 255); } - .log-fg-white { color: rgb(187, 187, 187); } - .log-bg-black { background-color: rgb(0, 0, 0); } - .log-bg-red { background-color: rgb(255, 0, 0); } - .log-bg-green { background-color: rgb(0, 255, 0); } - .log-bg-yellow { background-color: rgb(255, 255, 0); } - .log-bg-blue { background-color: rgb(0, 0, 255); } - .log-bg-magenta { background-color: rgb(255, 0, 255); } - .log-bg-cyan { background-color: rgb(0, 255, 255); } - .log-bg-white { background-color: rgb(255, 255, 255); } + .log-secret-redacted { + opacity: 0; + width: 1px; + font-size: 1px; + } + .log-fg-black { + color: rgb(128, 128, 128); + } + .log-fg-red { + color: rgb(255, 0, 0); + } + .log-fg-green { + color: rgb(0, 255, 0); + } + .log-fg-yellow { + color: rgb(255, 255, 0); + } + .log-fg-blue { + color: rgb(0, 0, 255); + } + .log-fg-magenta { + color: rgb(255, 0, 255); + } + .log-fg-cyan { + color: rgb(0, 255, 255); + } + .log-fg-white { + color: rgb(187, 187, 187); + } + .log-bg-black { + background-color: rgb(0, 0, 0); + } + .log-bg-red { + background-color: rgb(255, 0, 0); + } + .log-bg-green { + background-color: rgb(0, 255, 0); + } + .log-bg-yellow { + background-color: rgb(255, 255, 0); + } + .log-bg-blue { + background-color: rgb(0, 0, 255); + } + .log-bg-magenta { + background-color: rgb(255, 0, 255); + } + .log-bg-cyan { + background-color: rgb(0, 255, 255); + } + .log-bg-white { + background-color: rgb(255, 255, 255); + } `; diff --git a/js/util/line-break-transformer.js b/js/util/line-break-transformer.js index a876f1b0..047a887f 100644 --- a/js/util/line-break-transformer.js +++ b/js/util/line-break-transformer.js @@ -1,33 +1,31 @@ export class LineBreakTransformer { - constructor() { - this.chunks = ""; - } - - transform(chunk, controller) { - // Append new chunks to existing chunks. - this.chunks += chunk; - // Split on \r\n, lone \r, or lone \n — capturing the separator so we can - // distinguish a lone \r (overwrite intent) from a normal newline. - const re = /\r\n|\r|\n/g; - let lastIndex = 0; - let match; - while ((match = re.exec(this.chunks)) !== null) { - // If this is a lone \r at the very end of the buffer, leave it so it can - // be combined with a possible following \n in the next chunk. - if (match[0] === "\r" && match.index === this.chunks.length - 1) { - break; - } - const line = this.chunks.substring(lastIndex, match.index); - // Emit with \r suffix only for lone \r (overwrite), \n for everything else. - const suffix = match[0] === "\r" ? "\r" : "\n"; - controller.enqueue(line + suffix); - lastIndex = re.lastIndex; + constructor() { + this.chunks = ""; + } + transform(chunk, controller) { + // Append new chunks to existing chunks. + this.chunks += chunk; + // Split on \r\n, lone \r, or lone \n — capturing the separator so we can + // distinguish a lone \r (overwrite intent) from a normal newline. + const re = /\r\n|\r|\n/g; + let lastIndex = 0; + let match; + while ((match = re.exec(this.chunks)) !== null) { + // If this is a lone \r at the very end of the buffer, leave it so it can + // be combined with a possible following \n in the next chunk. + if (match[0] === "\r" && match.index === this.chunks.length - 1) { + break; + } + const line = this.chunks.substring(lastIndex, match.index); + // Emit with \r suffix only for lone \r (overwrite), \n for everything else. + const suffix = match[0] === "\r" ? "\r" : "\n"; + controller.enqueue(line + suffix); + lastIndex = re.lastIndex; + } + this.chunks = this.chunks.substring(lastIndex); + } + flush(controller) { + // When the stream is closed, flush any remaining chunks out. + controller.enqueue(this.chunks); } - this.chunks = this.chunks.substring(lastIndex); - } - - flush(controller) { - // When the stream is closed, flush any remaining chunks out. - controller.enqueue(this.chunks); - } } diff --git a/js/util/timestamp-transformer.js b/js/util/timestamp-transformer.js index d4691e39..e9e78cbe 100644 --- a/js/util/timestamp-transformer.js +++ b/js/util/timestamp-transformer.js @@ -1,6 +1,6 @@ // Matches lines that already carry a wall-clock or tick timestamp so we don't -// add a redundant one. Does NOT match bare log-level prefixes like ESPHome's -// [I][tag:line]: — those have no time information. +// add a redundant one. Intentionally does NOT match bare log-level prefixes +// like ESPHome's [I][tag:line]: — those have no time information. // // Covered formats: // (123456) FreeRTOS ms-tick e.g. "(12345) " @@ -8,39 +8,32 @@ // [HH:MM:SS.mmm] wall-clock bracket with millis // I (1234) tag: ESP-IDF log level + tick e.g. "I (1234) wifi: ..." // HH:MM:SS.mmm plain wall-clock -const DEVICE_TIMESTAMP_RE = - /^\s*(?:\(\d+\)\s|\[\d{2}:\d{2}:\d{2}(?:\.\d+)?\]|[DIWEACV] \(\d+\) \w|(?:\d{2}:){2}\d{2}\.\d)/; - +const DEVICE_TIMESTAMP_RE = /^\s*(?:\(\d+\)\s|\[\d{2}:\d{2}:\d{2}(?:\.\d+)?\]|[DIWEACV] \(\d+\) \w|(?:\d{2}:){2}\d{2}\.\d)/; export class TimestampTransformer { - constructor() { - this.deviceHasTimestamps = false; - } - - transform(chunk, controller) { - // Pass through pure newline / empty sentinel unchanged so that - // carriage-return overwrite logic in console-color.js still works. - if (chunk === "" || chunk === "\n" || chunk === "\r") { - controller.enqueue(chunk); - return; + constructor() { + this.deviceHasTimestamps = false; } - - if (!this.deviceHasTimestamps && DEVICE_TIMESTAMP_RE.test(chunk)) { - this.deviceHasTimestamps = true; + transform(chunk, controller) { + // Pass through pure newline / empty sentinel unchanged so that + // carriage-return overwrite logic in console-color.ts still works. + if (chunk === "" || chunk === "\n" || chunk === "\r") { + controller.enqueue(chunk); + return; + } + if (!this.deviceHasTimestamps && DEVICE_TIMESTAMP_RE.test(chunk)) { + this.deviceHasTimestamps = true; + } + if (this.deviceHasTimestamps) { + controller.enqueue(chunk); + return; + } + const date = new Date(); + const h = date.getHours().toString().padStart(2, "0"); + const m = date.getMinutes().toString().padStart(2, "0"); + const s = date.getSeconds().toString().padStart(2, "0"); + controller.enqueue(`[${h}:${m}:${s}] ${chunk}`); } - - if (this.deviceHasTimestamps) { - controller.enqueue(chunk); - return; + reset() { + this.deviceHasTimestamps = false; } - - const date = new Date(); - const h = date.getHours().toString().padStart(2, "0"); - const m = date.getMinutes().toString().padStart(2, "0"); - const s = date.getSeconds().toString().padStart(2, "0"); - controller.enqueue(`[${h}:${m}:${s}] ${chunk}`); - } - - reset() { - this.deviceHasTimestamps = false; - } } diff --git a/package.json b/package.json index a95d0cba..b8f0eed8 100644 --- a/package.json +++ b/package.json @@ -21,13 +21,14 @@ }, "scripts": { "prebuild": "node -e \"const fs=require('fs'); fs.rmSync('dist',{recursive:true,force:true}); fs.rmSync('js/modules',{recursive:true,force:true}); fs.mkdirSync('js/modules',{recursive:true});\"", - "build": "npm run prebuild && node update-sw-version.cjs && tsc --skipLibCheck && rollup -c && node -e \"const fs=require('fs'); fs.readdirSync('dist/web').filter(f=>f.endsWith('.js')).forEach(f=>fs.copyFileSync('dist/web/'+f,'js/modules/'+f)); fs.renameSync('js/modules/index.js','js/modules/esptool.js');\" && node fix-cli-imports.cjs", + "build": "npm run prebuild && node update-sw-version.cjs && tsc --skipLibCheck && tsc -p tsconfig.util.json && rollup -c && node -e \"const fs=require('fs'); fs.readdirSync('dist/web').filter(f=>f.endsWith('.js')).forEach(f=>fs.copyFileSync('dist/web/'+f,'js/modules/'+f)); fs.renameSync('js/modules/index.js','js/modules/esptool.js');\" && node fix-cli-imports.cjs", "build:binary": "node build-single-binary.cjs", "build:cli-electron": "node build-electron-cli.cjs", "format": "npm exec -- prettier --write src", "dev:clean": "node -e \"const fs=require('fs'); fs.rmSync('dist',{recursive:true,force:true});\"", "dev:tsc-once": "tsc", "dev:tsc": "tsc --watch", + "dev:tsc-util": "tsc -p tsconfig.util.json --watch", "dev:rollup": "rollup -c --watch", "dev:serve": "serve -p 5004", "develop": "npm run dev:clean && npm run dev:tsc-once && npm-run-all --parallel dev:serve dev:tsc dev:rollup", diff --git a/tsconfig.util.json b/tsconfig.util.json new file mode 100644 index 00000000..31813857 --- /dev/null +++ b/tsconfig.util.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "lib": ["es2019", "dom"], + "target": "es2019", + "module": "es2020", + "moduleResolution": "node", + "outDir": "js/util", + "declaration": false, + "strict": true, + "skipLibCheck": true, + "removeComments": false + }, + "include": ["src/util/*.ts"] +} From 73dc3262e5a50f84161f91353762c33702433e42 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Tue, 7 Apr 2026 16:17:49 +0200 Subject: [PATCH 3/5] merge main --- apple-touch-icon.png | Bin 21079 -> 21079 bytes icons/icon-128.png | Bin 6351 -> 6351 bytes icons/icon-144.png | Bin 7148 -> 7148 bytes icons/icon-152.png | Bin 7332 -> 7332 bytes icons/icon-192.png | Bin 9431 -> 9431 bytes icons/icon-384.png | Bin 19326 -> 19326 bytes icons/icon-512.png | Bin 26502 -> 26502 bytes icons/icon-72.png | Bin 3388 -> 3388 bytes icons/icon-96.png | Bin 4924 -> 4924 bytes js/modules/esp32-BL5RXAvE.js | 16 - js/modules/esp32-BRKoi17y.js | 1 + js/modules/esp32c2-Btgr_lwh.js | 1 + js/modules/esp32c2-JZd7VMTK.js | 16 - js/modules/esp32c3--2RgnV8f.js | 16 - js/modules/esp32c3-CHKfoI8W.js | 1 + js/modules/esp32c5-BDW4KtLo.js | 1 + js/modules/esp32c5-D7Zxncy7.js | 16 - js/modules/esp32c6-B8dieLFx.js | 16 - js/modules/esp32c6-il8tTxAG.js | 1 + js/modules/esp32c61-CVOVhUkw.js | 16 - js/modules/esp32c61-thKzxBGf.js | 1 + js/modules/esp32h2-C7Y4kn-J.js | 16 - js/modules/esp32h2-CxoUHv_P.js | 1 + js/modules/esp32p4-BN3KBRYS.js | 16 - js/modules/esp32p4-D3jLP-jY.js | 1 + js/modules/esp32p4r3-CW9u2O6_.js | 16 - js/modules/esp32p4r3-CqI71ojR.js | 1 + js/modules/esp32s2-iX3WoDbg.js | 1 + js/modules/esp32s2-t0j-Iiag.js | 16 - js/modules/esp32s3-B8l06aKE.js | 16 - js/modules/esp32s3-DGwDVIgz.js | 1 + js/modules/esp8266-CUwxJpGa.js | 1 + js/modules/esp8266-nEkNAo8K.js | 16 - js/modules/esptool.js | 10298 +---------------------------- screenshots/desktop.png | Bin 13171 -> 13171 bytes screenshots/mobile.png | Bin 11823 -> 11823 bytes 36 files changed, 13 insertions(+), 10489 deletions(-) delete mode 100644 js/modules/esp32-BL5RXAvE.js create mode 100644 js/modules/esp32-BRKoi17y.js create mode 100644 js/modules/esp32c2-Btgr_lwh.js delete mode 100644 js/modules/esp32c2-JZd7VMTK.js delete mode 100644 js/modules/esp32c3--2RgnV8f.js create mode 100644 js/modules/esp32c3-CHKfoI8W.js create mode 100644 js/modules/esp32c5-BDW4KtLo.js delete mode 100644 js/modules/esp32c5-D7Zxncy7.js delete mode 100644 js/modules/esp32c6-B8dieLFx.js create mode 100644 js/modules/esp32c6-il8tTxAG.js delete mode 100644 js/modules/esp32c61-CVOVhUkw.js create mode 100644 js/modules/esp32c61-thKzxBGf.js delete mode 100644 js/modules/esp32h2-C7Y4kn-J.js create mode 100644 js/modules/esp32h2-CxoUHv_P.js delete mode 100644 js/modules/esp32p4-BN3KBRYS.js create mode 100644 js/modules/esp32p4-D3jLP-jY.js delete mode 100644 js/modules/esp32p4r3-CW9u2O6_.js create mode 100644 js/modules/esp32p4r3-CqI71ojR.js create mode 100644 js/modules/esp32s2-iX3WoDbg.js delete mode 100644 js/modules/esp32s2-t0j-Iiag.js delete mode 100644 js/modules/esp32s3-B8l06aKE.js create mode 100644 js/modules/esp32s3-DGwDVIgz.js create mode 100644 js/modules/esp8266-CUwxJpGa.js delete mode 100644 js/modules/esp8266-nEkNAo8K.js diff --git a/apple-touch-icon.png b/apple-touch-icon.png index 72eea093d188e0c401f9e3ce567b5a7d71448ec0..311df219d1330bd54e62e6fec925ed6742d89196 100644 GIT binary patch delta 21 dcmcb#Gi*LVS-&piC5CCCt2^RnW diff --git a/icons/icon-128.png b/icons/icon-128.png index 3484789bd60e03f96fc0be89f0cc16d62abf7f36..97c67281903c623d2239de33baefd2b7d9cd365d 100644 GIT binary patch delta 19 acmX?ac;0YA76&^YpWxe%I^G+LVkH1c(g!2} delta 19 bcmX?ac;0YA76%)ToYLakZ`d~$#YzAGODhLn diff --git a/icons/icon-144.png b/icons/icon-144.png index 7737ec0987e93012a0b1632ee12930ec93d04520..ccf91b49521f3fc55515f2e7d17931012ae28401 100644 GIT binary patch delta 19 acmaE3{>FSl76&^YpWxe%I^G+Ls-yuFSl76%)ToYLakZ`d~$RY?N?P)G;F diff --git a/icons/icon-152.png b/icons/icon-152.png index 7f5221d644c794d3f4a21c30bb8f58715659b313..d1bdb69029067f5d0dc97fb372fdc700a5a7a285 100644 GIT binary patch delta 19 acmZ2txx{ip76&^YpWxe%I^G+LjAQ^rga)?& delta 19 bcmZ2txx{ip76%)ToYLakZ`d~$8OZJ_mRJ delta 19 bcmccadEIkD76%)ToYLakZ`d~$rK$h`PnQR> diff --git a/icons/icon-384.png b/icons/icon-384.png index 6d37e95b7e55acf92dea9cb8611a05dc0ddc0738..6e027fdf287968a42ce87bf636b480b75250e53c 100644 GIT binary patch delta 21 dcmex2jq%?!#tB&*?0kHJZ$IjIZ!F^R1^{A82rvKu delta 21 dcmex2jq%?!#tB&*Y&>#Gi*LVS-&n-s4FF@K2x { - let encoded = [0xc0]; - for (const byte of buffer) { - if (byte == 0xdb) { - encoded = encoded.concat([0xdb, 0xdd]); - } - else if (byte == 0xc0) { - encoded = encoded.concat([0xdb, 0xdc]); - } - else { - encoded.push(byte); - } - } - encoded.push(0xc0); - return encoded; -}; -/** - * @name toByteArray - * Convert a string to a byte array - */ -const toByteArray = (str) => { - const byteArray = []; - for (let i = 0; i < str.length; i++) { - const charcode = str.charCodeAt(i); - if (charcode <= 0xff) { - byteArray.push(charcode); - } - } - return byteArray; -}; -const hexFormatter = (bytes) => "[" + bytes.map((value) => toHex(value)).join(", ") + "]"; -const toHex = (value, size = 2) => { - const hex = value.toString(16).toUpperCase(); - if (hex.startsWith("-")) { - return "-0x" + hex.substring(1).padStart(size, "0"); - } - else { - return "0x" + hex.padStart(size, "0"); - } -}; -/** - * Format MAC address array to string (e.g., [0xAA, 0xBB, 0xCC] -> "AA:BB:CC:DD:EE:FF") - */ -const formatMacAddr = (macAddr) => { - return macAddr - .map((value) => value.toString(16).toUpperCase().padStart(2, "0")) - .join(":"); -}; -/** - * @name padTo - * Pad data to the next alignment boundary with the given fill byte (default 0xFF) - */ -function padTo(data, alignment, padCharacter = 0xff) { - const padMod = data.length % alignment; - if (padMod !== 0) { - const padding = new Uint8Array(alignment - padMod).fill(padCharacter); - const paddedData = new Uint8Array(data.length + padding.length); - paddedData.set(data); - paddedData.set(padding, data.length); - return paddedData; - } - return data; -} -const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); - -const DETECTED_FLASH_SIZES = { - 0x12: "256KB", - 0x13: "512KB", - 0x14: "1MB", - 0x15: "2MB", - 0x16: "4MB", - 0x17: "8MB", - 0x18: "16MB", - 0x19: "32MB", - 0x1a: "64MB", - 0x1b: "128MB", - 0x1c: "256MB", - 0x20: "64MB", - 0x21: "128MB", - 0x22: "256MB", - 0x32: "256KB", - 0x33: "512KB", - 0x34: "1MB", - 0x35: "2MB", - 0x36: "4MB", - 0x37: "8MB", - 0x38: "16MB", - 0x39: "32MB", - 0x3a: "64MB", -}; -const FLASH_WRITE_SIZE = 0x400; -const STUB_FLASH_WRITE_SIZE = 0x4000; -const FLASH_SECTOR_SIZE = 0x1000; // Flash sector size, minimum unit of erase. -const ESP_ROM_BAUD = 115200; -const USB_JTAG_SERIAL_PID = 0x1001; -const ESP8266_SPI_REG_BASE = 0x60000200; -const ESP8266_BASEFUSEADDR = 0x3ff00050; -const ESP8266_MACFUSEADDR = 0x3ff00050; -const ESP8266_SPI_USR_OFFS = 0x1c; -const ESP8266_SPI_USR1_OFFS = 0x20; -const ESP8266_SPI_USR2_OFFS = 0x24; -const ESP8266_SPI_MOSI_DLEN_OFFS = -1; -const ESP8266_SPI_MISO_DLEN_OFFS = -1; -const ESP8266_SPI_W0_OFFS = 0x40; -const ESP8266_UART_DATE_REG_ADDR = 0x60000078; -const ESP8266_BOOTLOADER_FLASH_OFFSET = 0x0000; -const ESP32_SPI_REG_BASE = 0x3ff42000; -const ESP32_BASEFUSEADDR = 0x3ff5a000; -const ESP32_MACFUSEADDR = 0x3ff5a000; -const ESP32_SPI_USR_OFFS = 0x1c; -const ESP32_SPI_USR1_OFFS = 0x20; -const ESP32_SPI_USR2_OFFS = 0x24; -const ESP32_SPI_MOSI_DLEN_OFFS = 0x28; -const ESP32_SPI_MISO_DLEN_OFFS = 0x2c; -const ESP32_SPI_W0_OFFS = 0x80; -const ESP32_UART_DATE_REG_ADDR = 0x60000078; -const ESP32_BOOTLOADER_FLASH_OFFSET = 0x1000; -const ESP32_APB_CTL_DATE_ADDR = 0x3ff66000 + 0x7c; -const ESP32S2_SPI_REG_BASE = 0x3f402000; -const ESP32S2_BASEFUSEADDR = 0x3f41a000; -const ESP32S2_EFUSE_BLOCK1_ADDR = ESP32S2_BASEFUSEADDR + 0x044; -const ESP32S2_MACFUSEADDR = 0x3f41a044; -const ESP32S2_SPI_USR_OFFS = 0x18; -const ESP32S2_SPI_USR1_OFFS = 0x1c; -const ESP32S2_SPI_USR2_OFFS = 0x20; -const ESP32S2_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32S2_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32S2_SPI_W0_OFFS = 0x58; -const ESP32S2_UART_DATE_REG_ADDR = 0x60000078; -const ESP32S2_BOOTLOADER_FLASH_OFFSET = 0x1000; -// ESP32-S2 RTC Watchdog Timer registers for USB-OTG reset -const ESP32S2_RTCCNTL_BASE_REG = 0x3f408000; -const ESP32S2_RTC_CNTL_WDTWPROTECT_REG = ESP32S2_RTCCNTL_BASE_REG + 0x00ac; -const ESP32S2_RTC_CNTL_WDTCONFIG0_REG = ESP32S2_RTCCNTL_BASE_REG + 0x0094; -const ESP32S2_RTC_CNTL_WDTCONFIG1_REG = ESP32S2_RTCCNTL_BASE_REG + 0x0098; -const ESP32S2_RTC_CNTL_WDT_WKEY = 0x50d83aa1; -const ESP32S2_RTC_CNTL_OPTION1_REG = 0x3f408128; -const ESP32S2_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1; // Is download mode forced over USB? -const ESP32S2_UARTDEV_BUF_NO = 0x3ffffd14; // Variable in ROM .bss which indicates the port in use -const ESP32S2_UARTDEV_BUF_NO_USB_OTG = 2; // Value of the above indicating that USB-OTG is in use -const ESP32S3_SPI_REG_BASE = 0x60002000; -const ESP32S3_BASEFUSEADDR = 0x60007000; -const ESP32S3_EFUSE_BLOCK1_ADDR = ESP32S3_BASEFUSEADDR + 0x044; -const ESP32S3_MACFUSEADDR = 0x60007000 + 0x044; -const ESP32S3_SPI_USR_OFFS = 0x18; -const ESP32S3_SPI_USR1_OFFS = 0x1c; -const ESP32S3_SPI_USR2_OFFS = 0x20; -const ESP32S3_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32S3_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32S3_SPI_W0_OFFS = 0x58; -const ESP32S3_UART_DATE_REG_ADDR = 0x60000080; -const ESP32S3_BOOTLOADER_FLASH_OFFSET = 0x0000; -// ESP32-S3 RTC Watchdog Timer registers for USB-OTG reset -const ESP32S3_RTCCNTL_BASE_REG = 0x60008000; -const ESP32S3_RTC_CNTL_WDTWPROTECT_REG = ESP32S3_RTCCNTL_BASE_REG + 0x00b0; -const ESP32S3_RTC_CNTL_WDTCONFIG0_REG = ESP32S3_RTCCNTL_BASE_REG + 0x0098; -const ESP32S3_RTC_CNTL_WDTCONFIG1_REG = ESP32S3_RTCCNTL_BASE_REG + 0x009c; -const ESP32S3_RTC_CNTL_WDT_WKEY = 0x50d83aa1; -const ESP32S3_RTC_CNTL_OPTION1_REG = 0x6000812c; -const ESP32S3_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1; // Is download mode forced over USB? -const ESP32S3_UARTDEV_BUF_NO = 0x3fcef14c; // Variable in ROM .bss which indicates the port in use -const ESP32S3_UARTDEV_BUF_NO_USB_OTG = 3; // The above var when USB-OTG is used -const ESP32S3_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 4; // The above var when USB-JTAG/Serial is used -const ESP32C2_SPI_REG_BASE = 0x60002000; -const ESP32C2_BASEFUSEADDR = 0x60008800; -const ESP32C2_EFUSE_BLOCK2_ADDR = ESP32C2_BASEFUSEADDR + 0x040; -const ESP32C2_MACFUSEADDR = ESP32C2_BASEFUSEADDR + 0x040; -const ESP32C2_SPI_USR_OFFS = 0x18; -const ESP32C2_SPI_USR1_OFFS = 0x1c; -const ESP32C2_SPI_USR2_OFFS = 0x20; -const ESP32C2_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32C2_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32C2_SPI_W0_OFFS = 0x58; -const ESP32C2_UART_DATE_REG_ADDR = 0x6000007c; -const ESP32C2_BOOTLOADER_FLASH_OFFSET = 0x0000; -const ESP32C3_SPI_REG_BASE = 0x60002000; -const ESP32C3_BASEFUSEADDR = 0x60008800; -const ESP32C3_MACFUSEADDR = 0x60008800 + 0x044; -const ESP32C3_SPI_USR_OFFS = 0x18; -const ESP32C3_SPI_USR1_OFFS = 0x1c; -const ESP32C3_SPI_USR2_OFFS = 0x20; -const ESP32C3_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32C3_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32C3_SPI_W0_OFFS = 0x58; -const ESP32C3_UART_DATE_REG_ADDR = 0x6000007c; -const ESP32C3_BOOTLOADER_FLASH_OFFSET = 0x0000; -// ESP32-C3 RTC Watchdog Timer registers -const ESP32C3_RTC_CNTL_BASE_REG = 0x60008000; -const ESP32C3_RTC_CNTL_WDTWPROTECT_REG = ESP32C3_RTC_CNTL_BASE_REG + 0x00a8; -const ESP32C3_RTC_CNTL_WDTCONFIG0_REG = ESP32C3_RTC_CNTL_BASE_REG + 0x0090; -const ESP32C3_RTC_CNTL_WDTCONFIG1_REG = ESP32C3_RTC_CNTL_BASE_REG + 0x0094; -const ESP32C3_RTC_CNTL_WDT_WKEY = 0x50d83aa1; -const ESP32C3_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used -const ESP32C3_BUF_UART_NO_OFFSET = 24; -// Note: ESP32C3_BSS_UART_DEV_ADDR is calculated dynamically based on chip revision in esp_loader.ts -// Revision < 101: 0x3FCDF064, Revision >= 101: 0x3FCDF060 -// ESP32-C3 EFUSE registers for chip revision detection -const ESP32C3_EFUSE_RD_MAC_SPI_SYS_3_REG = 0x60008850; -const ESP32C3_EFUSE_RD_MAC_SPI_SYS_5_REG = 0x60008858; -const ESP32C5_SPI_REG_BASE = 0x60003000; -const ESP32C5_BASEFUSEADDR = 0x600b4800; -const ESP32C5_EFUSE_BLOCK1_ADDR = ESP32C5_BASEFUSEADDR + 0x044; -const ESP32C5_MACFUSEADDR = 0x600b4800 + 0x044; -const ESP32C5_SPI_USR_OFFS = 0x18; -const ESP32C5_SPI_USR1_OFFS = 0x1c; -const ESP32C5_SPI_USR2_OFFS = 0x20; -const ESP32C5_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32C5_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32C5_SPI_W0_OFFS = 0x58; -const ESP32C5_UART_DATE_REG_ADDR = 0x6000007c; -const ESP32C5_UART_CLKDIV_REG = 0x60000014; -const ESP32C5_BOOTLOADER_FLASH_OFFSET = 0x2000; -// ESP32-C5 Crystal frequency detection registers -const ESP32C5_PCR_SYSCLK_CONF_REG = 0x60096110; -const ESP32C5_PCR_SYSCLK_XTAL_FREQ_V = 0x7f << 24; -const ESP32C5_PCR_SYSCLK_XTAL_FREQ_S = 24; -// ESP32-C5 USB-JTAG/Serial detection -const ESP32C5_UARTDEV_BUF_NO = 0x4085f514; // Variable in ROM .bss which indicates the port in use -const ESP32C5_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used -const ESP32C6_SPI_REG_BASE = 0x60003000; -const ESP32C6_BASEFUSEADDR = 0x600b0800; -const ESP32C6_EFUSE_BLOCK1_ADDR = ESP32C6_BASEFUSEADDR + 0x044; -const ESP32C6_MACFUSEADDR = 0x600b0800 + 0x044; -const ESP32C6_SPI_USR_OFFS = 0x18; -const ESP32C6_SPI_USR1_OFFS = 0x1c; -const ESP32C6_SPI_USR2_OFFS = 0x20; -const ESP32C6_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32C6_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32C6_SPI_W0_OFFS = 0x58; -const ESP32C6_UART_DATE_REG_ADDR = 0x6000007c; -const ESP32C6_BOOTLOADER_FLASH_OFFSET = 0x0000; -// ESP32-C6 USB-JTAG/Serial detection -const ESP32C6_UARTDEV_BUF_NO = 0x4087f580; // Variable in ROM .bss which indicates the port in use -const ESP32C6_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used -// ESP32-C5/C6 LP Watchdog Timer registers (Low Power WDT) -const ESP32C5_C6_DR_REG_LP_WDT_BASE = 0x600b1c00; -const ESP32C5_C6_RTC_CNTL_WDTCONFIG0_REG = ESP32C5_C6_DR_REG_LP_WDT_BASE + 0x0000; // LP_WDT_RWDT_CONFIG0_REG -const ESP32C5_C6_RTC_CNTL_WDTCONFIG1_REG = ESP32C5_C6_DR_REG_LP_WDT_BASE + 0x0004; // LP_WDT_RWDT_CONFIG1_REG -const ESP32C5_C6_RTC_CNTL_WDTWPROTECT_REG = ESP32C5_C6_DR_REG_LP_WDT_BASE + 0x0018; // LP_WDT_RWDT_WPROTECT_REG -const ESP32C5_C6_RTC_CNTL_WDT_WKEY = 0x50d83aa1; // LP_WDT_SWD_WKEY -const ESP32C61_SPI_REG_BASE = 0x60003000; -const ESP32C61_BASEFUSEADDR = 0x600b4800; -const ESP32C61_EFUSE_BLOCK1_ADDR = ESP32C61_BASEFUSEADDR + 0x044; -const ESP32C61_MACFUSEADDR = 0x600b4800 + 0x044; -const ESP32C61_SPI_USR_OFFS = 0x18; -const ESP32C61_SPI_USR1_OFFS = 0x1c; -const ESP32C61_SPI_USR2_OFFS = 0x20; -const ESP32C61_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32C61_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32C61_SPI_W0_OFFS = 0x58; -const ESP32C61_UART_DATE_REG_ADDR = 0x6000007c; -const ESP32C61_BOOTLOADER_FLASH_OFFSET = 0x0000; -// ESP32-C61 USB-JTAG/Serial detection (dynamic based on chip revision) -const ESP32C61_UARTDEV_BUF_NO_REV_LE2 = 0x4084f5ec; // revision <= 2 -const ESP32C61_UARTDEV_BUF_NO_REV_GT2 = 0x4084f5e4; // revision > 2 -const ESP32C61_UARTDEV_BUF_NO_USB_JTAG_SERIAL_REV_LE2 = 3; // revision <= 2 -const ESP32C61_UARTDEV_BUF_NO_USB_JTAG_SERIAL_REV_GT2 = 4; // revision > 2 -const ESP32H2_SPI_REG_BASE = 0x60003000; -const ESP32H2_BASEFUSEADDR = 0x600b0800; -const ESP32H2_EFUSE_BLOCK1_ADDR = ESP32H2_BASEFUSEADDR + 0x044; -const ESP32H2_MACFUSEADDR = 0x600b0800 + 0x044; -const ESP32H2_SPI_USR_OFFS = 0x18; -const ESP32H2_SPI_USR1_OFFS = 0x1c; -const ESP32H2_SPI_USR2_OFFS = 0x20; -const ESP32H2_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32H2_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32H2_SPI_W0_OFFS = 0x58; -const ESP32H2_UART_DATE_REG_ADDR = 0x6000007c; -const ESP32H2_BOOTLOADER_FLASH_OFFSET = 0x0000; -// ESP32-H2 USB-JTAG/Serial detection -const ESP32H2_UARTDEV_BUF_NO = 0x4084fefc; // Variable in ROM .bss which indicates the port in use -const ESP32H2_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used -const ESP32H4_SPI_REG_BASE = 0x60099000; -const ESP32H4_BASEFUSEADDR = 0x600b1800; -const ESP32H4_MACFUSEADDR = 0x600b1800 + 0x044; -const ESP32H4_SPI_USR_OFFS = 0x18; -const ESP32H4_SPI_USR1_OFFS = 0x1c; -const ESP32H4_SPI_USR2_OFFS = 0x20; -const ESP32H4_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32H4_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32H4_SPI_W0_OFFS = 0x58; -const ESP32H4_UART_DATE_REG_ADDR = 0x60012000 + 0x7c; -const ESP32H4_BOOTLOADER_FLASH_OFFSET = 0x2000; -// ESP32-H4 USB-JTAG/Serial detection -const ESP32H4_UARTDEV_BUF_NO = 0x4087f580; // Variable in ROM .bss which indicates the port in use -const ESP32H4_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used -const ESP32H21_SPI_REG_BASE = 0x60003000; -const ESP32H21_BASEFUSEADDR = 0x600b4000; -const ESP32H21_MACFUSEADDR = 0x600b4000 + 0x044; -const ESP32H21_SPI_USR_OFFS = 0x18; -const ESP32H21_SPI_USR1_OFFS = 0x1c; -const ESP32H21_SPI_USR2_OFFS = 0x20; -const ESP32H21_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32H21_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32H21_SPI_W0_OFFS = 0x58; -const ESP32H21_UART_DATE_REG_ADDR = 0x6000007c; -const ESP32H21_BOOTLOADER_FLASH_OFFSET = 0x0000; -const ESP32P4_SPI_REG_BASE = 0x5008d000; -const ESP32P4_BASEFUSEADDR = 0x5012d000; -const ESP32P4_EFUSE_BLOCK1_ADDR = ESP32P4_BASEFUSEADDR + 0x044; -const ESP32P4_MACFUSEADDR = 0x5012d000 + 0x044; -const ESP32P4_SPI_USR_OFFS = 0x18; -const ESP32P4_SPI_USR1_OFFS = 0x1c; -const ESP32P4_SPI_USR2_OFFS = 0x20; -const ESP32P4_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32P4_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32P4_SPI_W0_OFFS = 0x58; -const ESP32P4_UART_DATE_REG_ADDR = 0x500ca000 + 0x8c; -const ESP32P4_BOOTLOADER_FLASH_OFFSET = 0x2000; -// ESP32-P4 RTC Watchdog Timer registers -const ESP32P4_DR_REG_LP_WDT_BASE = 0x50116000; -const ESP32P4_RTC_CNTL_WDTWPROTECT_REG = ESP32P4_DR_REG_LP_WDT_BASE + 0x0018; // LP_WDT_WPROTECT_REG -const ESP32P4_RTC_CNTL_WDTCONFIG0_REG = ESP32P4_DR_REG_LP_WDT_BASE + 0x0000; // LP_WDT_CONFIG0_REG -const ESP32P4_RTC_CNTL_WDTCONFIG1_REG = ESP32P4_DR_REG_LP_WDT_BASE + 0x0004; // LP_WDT_CONFIG1_REG -const ESP32P4_RTC_CNTL_WDT_WKEY = 0x50d83aa1; -// ESP32-P4 USB-JTAG/Serial and USB-OTG detection -// Note: UARTDEV_BUF_NO is dynamic based on chip revision -// Revision < 300: 0x4FF3FEB0 + 24 = 0x4FF3FEC8 -// Revision >= 300: 0x4FFBFEB0 + 24 = 0x4FFBFEC8 -const ESP32P4_UARTDEV_BUF_NO_REV0 = 0x4ff3fec8; // Variable in ROM .bss (revision < 300) -const ESP32P4_UARTDEV_BUF_NO_REV300 = 0x4ffbfec8; // Variable in ROM .bss (revision >= 300) -const ESP32P4_UARTDEV_BUF_NO_USB_OTG = 5; // The above var when USB-OTG is used -const ESP32P4_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 6; // The above var when USB-JTAG/Serial is used -const ESP32P4_RTC_CNTL_OPTION1_REG = 0x50110008; -const ESP32P4_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x4; // Is download mode forced over USB? -// Flash power-on related registers and bits needed for ECO6 (Rev 301) -const ESP32P4_DR_REG_LPAON_BASE = 0x50110000; -const ESP32P4_DR_REG_PMU_BASE = ESP32P4_DR_REG_LPAON_BASE + 0x5000; -const ESP32P4_DR_REG_LP_SYS_BASE = ESP32P4_DR_REG_LPAON_BASE + 0x0; -const ESP32P4_LP_SYSTEM_REG_ANA_XPD_PAD_GROUP_REG = ESP32P4_DR_REG_LP_SYS_BASE + 0x10c; -const ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG = ESP32P4_DR_REG_PMU_BASE + 0x1bc; -const ESP32P4_PMU_ANA_0P1A_EN_CUR_LIM_0 = 1 << 27; -const ESP32P4_PMU_EXT_LDO_P0_0P1A_REG = ESP32P4_DR_REG_PMU_BASE + 0x1b8; -const ESP32P4_PMU_0P1A_FORCE_TIEH_SEL_0 = 1 << 7; -const ESP32P4_PMU_DATE_REG = ESP32P4_DR_REG_PMU_BASE + 0x3fc; -const ESP32S31_SPI_REG_BASE = 0x20500000; -const ESP32S31_BASEFUSEADDR = 0x20715000; -const ESP32S31_EFUSE_BLOCK1_ADDR = ESP32S31_BASEFUSEADDR + 0x044; -const ESP32S31_MACFUSEADDR = 0x20715000 + 0x044; -const ESP32S31_SPI_USR_OFFS = 0x18; -const ESP32S31_SPI_USR1_OFFS = 0x1c; -const ESP32S31_SPI_USR2_OFFS = 0x20; -const ESP32S31_SPI_MOSI_DLEN_OFFS = 0x24; -const ESP32S31_SPI_MISO_DLEN_OFFS = 0x28; -const ESP32S31_SPI_W0_OFFS = 0x58; -const ESP32S31_UART_DATE_REG_ADDR = 0x2038a000 + 0x8c; -const ESP32S31_BOOTLOADER_FLASH_OFFSET = 0x2000; -const SYNC_PACKET = toByteArray("\x07\x07\x12 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"); -const CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000; -// Image Chip IDs (used by ESP32-C3 and later for chip detection) -// These values for the families are made up; nothing that esptool uses. -const CHIP_FAMILY_ESP8266 = 0x8266; -const CHIP_FAMILY_ESP32 = 0x32; -const CHIP_FAMILY_ESP32S2 = 0x3252; -const CHIP_FAMILY_ESP32S3 = 0x3253; -const CHIP_FAMILY_ESP32C2 = 0x32c2; -const CHIP_FAMILY_ESP32C3 = 0x32c3; -const CHIP_FAMILY_ESP32C5 = 0x32c5; -const CHIP_FAMILY_ESP32C6 = 0x32c6; -const CHIP_FAMILY_ESP32C61 = 0x32c61; -const CHIP_FAMILY_ESP32H2 = 0x3272; -const CHIP_FAMILY_ESP32H4 = 0x3274; -const CHIP_FAMILY_ESP32H21 = 0x3275; -const CHIP_FAMILY_ESP32P4 = 0x3280; -const CHIP_FAMILY_ESP32S31 = 0x3231; -const CHIP_ID_TO_INFO = { - 5: { name: "ESP32-C3", family: CHIP_FAMILY_ESP32C3 }, - 9: { name: "ESP32-S3", family: CHIP_FAMILY_ESP32S3 }, - 12: { name: "ESP32-C2", family: CHIP_FAMILY_ESP32C2 }, - 13: { name: "ESP32-C6", family: CHIP_FAMILY_ESP32C6 }, - 16: { name: "ESP32-H2", family: CHIP_FAMILY_ESP32H2 }, - 18: { name: "ESP32-P4", family: CHIP_FAMILY_ESP32P4 }, - 20: { name: "ESP32-C61", family: CHIP_FAMILY_ESP32C61 }, - 23: { name: "ESP32-C5", family: CHIP_FAMILY_ESP32C5 }, - 25: { name: "ESP32-H21", family: CHIP_FAMILY_ESP32H21 }, - 28: { name: "ESP32-H4", family: CHIP_FAMILY_ESP32H4 }, - 32: { name: "ESP32-S31", family: CHIP_FAMILY_ESP32S31 }, -}; -const CHIP_DETECT_MAGIC_VALUES = { - 0xfff0c101: { name: "ESP8266", family: CHIP_FAMILY_ESP8266 }, - 0x00f01d83: { name: "ESP32", family: CHIP_FAMILY_ESP32 }, - 0x000007c6: { name: "ESP32-S2", family: CHIP_FAMILY_ESP32S2 }, -}; -// Commands supported by ESP8266 ROM bootloader -const ESP_FLASH_BEGIN = 0x02; -const ESP_FLASH_DATA = 0x03; -const ESP_FLASH_END = 0x04; -const ESP_MEM_BEGIN = 0x05; -const ESP_MEM_END = 0x06; -const ESP_MEM_DATA = 0x07; -const ESP_SYNC = 0x08; -const ESP_WRITE_REG = 0x09; -const ESP_READ_REG = 0x0a; -const ESP_ERASE_FLASH = 0xd0; -const ESP_ERASE_REGION = 0xd1; -const ESP_READ_FLASH = 0xd2; -const ESP_SPI_SET_PARAMS = 0x0b; -const ESP_SPI_ATTACH = 0x0d; -const ESP_CHANGE_BAUDRATE = 0x0f; -const ESP_SPI_FLASH_MD5 = 0x13; -const ESP_GET_SECURITY_INFO = 0x14; -const ESP_CHECKSUM_MAGIC = 0xef; -const ESP_FLASH_DEFL_BEGIN = 0x10; -const ESP_FLASH_DEFL_DATA = 0x11; -const ESP_FLASH_DEFL_END = 0x12; -const ROM_INVALID_RECV_MSG = 0x05; -const USB_RAM_BLOCK = 0x800; -const ESP_RAM_BLOCK = 0x1800; -// Timeouts -const DEFAULT_TIMEOUT = 3000; -const CHIP_ERASE_TIMEOUT = 150000; // timeout for full chip erase in ms -const MAX_TIMEOUT = CHIP_ERASE_TIMEOUT * 2; // longest any command can run in ms -const SYNC_TIMEOUT = 100; // timeout for syncing with bootloader in ms -const ERASE_REGION_TIMEOUT_PER_MB = 30000; // timeout (per megabyte) for erasing a region in ms -const MEM_END_ROM_TIMEOUT = 500; -const FLASH_READ_TIMEOUT = 100; // timeout for reading flash in ms -/** - * @name timeoutPerMb - * Scales timeouts which are size-specific - */ -const timeoutPerMb = (secondsPerMb, sizeBytes) => { - const result = Math.floor(secondsPerMb * (sizeBytes / 0x1e6)); - if (result < DEFAULT_TIMEOUT) { - return DEFAULT_TIMEOUT; - } - return result; -}; -const getSpiFlashAddresses = (chipFamily) => { - switch (chipFamily) { - case CHIP_FAMILY_ESP32: - return { - regBase: ESP32_SPI_REG_BASE, - baseFuse: ESP32_BASEFUSEADDR, - macFuse: ESP32_MACFUSEADDR, - usrOffs: ESP32_SPI_USR_OFFS, - usr1Offs: ESP32_SPI_USR1_OFFS, - usr2Offs: ESP32_SPI_USR2_OFFS, - mosiDlenOffs: ESP32_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32_SPI_W0_OFFS, - uartDateReg: ESP32_UART_DATE_REG_ADDR, - flashOffs: ESP32_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32S2: - return { - regBase: ESP32S2_SPI_REG_BASE, - baseFuse: ESP32S2_BASEFUSEADDR, - macFuse: ESP32S2_MACFUSEADDR, - usrOffs: ESP32S2_SPI_USR_OFFS, - usr1Offs: ESP32S2_SPI_USR1_OFFS, - usr2Offs: ESP32S2_SPI_USR2_OFFS, - mosiDlenOffs: ESP32S2_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32S2_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32S2_SPI_W0_OFFS, - uartDateReg: ESP32S2_UART_DATE_REG_ADDR, - flashOffs: ESP32S2_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32S3: - return { - regBase: ESP32S3_SPI_REG_BASE, - usrOffs: ESP32S3_SPI_USR_OFFS, - baseFuse: ESP32S3_BASEFUSEADDR, - macFuse: ESP32S3_MACFUSEADDR, - usr1Offs: ESP32S3_SPI_USR1_OFFS, - usr2Offs: ESP32S3_SPI_USR2_OFFS, - mosiDlenOffs: ESP32S3_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32S3_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32S3_SPI_W0_OFFS, - uartDateReg: ESP32S3_UART_DATE_REG_ADDR, - flashOffs: ESP32S3_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP8266: - return { - regBase: ESP8266_SPI_REG_BASE, - usrOffs: ESP8266_SPI_USR_OFFS, - baseFuse: ESP8266_BASEFUSEADDR, - macFuse: ESP8266_MACFUSEADDR, - usr1Offs: ESP8266_SPI_USR1_OFFS, - usr2Offs: ESP8266_SPI_USR2_OFFS, - mosiDlenOffs: ESP8266_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP8266_SPI_MISO_DLEN_OFFS, - w0Offs: ESP8266_SPI_W0_OFFS, - uartDateReg: ESP8266_UART_DATE_REG_ADDR, - flashOffs: ESP8266_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32C2: - return { - regBase: ESP32C2_SPI_REG_BASE, - baseFuse: ESP32C2_BASEFUSEADDR, - macFuse: ESP32C2_MACFUSEADDR, - usrOffs: ESP32C2_SPI_USR_OFFS, - usr1Offs: ESP32C2_SPI_USR1_OFFS, - usr2Offs: ESP32C2_SPI_USR2_OFFS, - mosiDlenOffs: ESP32C2_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32C2_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32C2_SPI_W0_OFFS, - uartDateReg: ESP32C2_UART_DATE_REG_ADDR, - flashOffs: ESP32C2_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32C3: - return { - regBase: ESP32C3_SPI_REG_BASE, - baseFuse: ESP32C3_BASEFUSEADDR, - macFuse: ESP32C3_MACFUSEADDR, - usrOffs: ESP32C3_SPI_USR_OFFS, - usr1Offs: ESP32C3_SPI_USR1_OFFS, - usr2Offs: ESP32C3_SPI_USR2_OFFS, - mosiDlenOffs: ESP32C3_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32C3_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32C3_SPI_W0_OFFS, - uartDateReg: ESP32C3_UART_DATE_REG_ADDR, - flashOffs: ESP32C3_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32C5: - return { - regBase: ESP32C5_SPI_REG_BASE, - baseFuse: ESP32C5_BASEFUSEADDR, - macFuse: ESP32C5_MACFUSEADDR, - usrOffs: ESP32C5_SPI_USR_OFFS, - usr1Offs: ESP32C5_SPI_USR1_OFFS, - usr2Offs: ESP32C5_SPI_USR2_OFFS, - mosiDlenOffs: ESP32C5_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32C5_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32C5_SPI_W0_OFFS, - uartDateReg: ESP32C5_UART_DATE_REG_ADDR, - flashOffs: ESP32C5_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32C6: - return { - regBase: ESP32C6_SPI_REG_BASE, - baseFuse: ESP32C6_BASEFUSEADDR, - macFuse: ESP32C6_MACFUSEADDR, - usrOffs: ESP32C6_SPI_USR_OFFS, - usr1Offs: ESP32C6_SPI_USR1_OFFS, - usr2Offs: ESP32C6_SPI_USR2_OFFS, - mosiDlenOffs: ESP32C6_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32C6_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32C6_SPI_W0_OFFS, - uartDateReg: ESP32C6_UART_DATE_REG_ADDR, - flashOffs: ESP32C6_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32C61: - return { - regBase: ESP32C61_SPI_REG_BASE, - baseFuse: ESP32C61_BASEFUSEADDR, - macFuse: ESP32C61_MACFUSEADDR, - usrOffs: ESP32C61_SPI_USR_OFFS, - usr1Offs: ESP32C61_SPI_USR1_OFFS, - usr2Offs: ESP32C61_SPI_USR2_OFFS, - mosiDlenOffs: ESP32C61_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32C61_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32C61_SPI_W0_OFFS, - uartDateReg: ESP32C61_UART_DATE_REG_ADDR, - flashOffs: ESP32C61_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32H2: - return { - regBase: ESP32H2_SPI_REG_BASE, - baseFuse: ESP32H2_BASEFUSEADDR, - macFuse: ESP32H2_MACFUSEADDR, - usrOffs: ESP32H2_SPI_USR_OFFS, - usr1Offs: ESP32H2_SPI_USR1_OFFS, - usr2Offs: ESP32H2_SPI_USR2_OFFS, - mosiDlenOffs: ESP32H2_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32H2_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32H2_SPI_W0_OFFS, - uartDateReg: ESP32H2_UART_DATE_REG_ADDR, - flashOffs: ESP32H2_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32H4: - return { - regBase: ESP32H4_SPI_REG_BASE, - baseFuse: ESP32H4_BASEFUSEADDR, - macFuse: ESP32H4_MACFUSEADDR, - usrOffs: ESP32H4_SPI_USR_OFFS, - usr1Offs: ESP32H4_SPI_USR1_OFFS, - usr2Offs: ESP32H4_SPI_USR2_OFFS, - mosiDlenOffs: ESP32H4_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32H4_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32H4_SPI_W0_OFFS, - uartDateReg: ESP32H4_UART_DATE_REG_ADDR, - flashOffs: ESP32H4_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32H21: - return { - regBase: ESP32H21_SPI_REG_BASE, - baseFuse: ESP32H21_BASEFUSEADDR, - macFuse: ESP32H21_MACFUSEADDR, - usrOffs: ESP32H21_SPI_USR_OFFS, - usr1Offs: ESP32H21_SPI_USR1_OFFS, - usr2Offs: ESP32H21_SPI_USR2_OFFS, - mosiDlenOffs: ESP32H21_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32H21_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32H21_SPI_W0_OFFS, - uartDateReg: ESP32H21_UART_DATE_REG_ADDR, - flashOffs: ESP32H21_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32P4: - return { - regBase: ESP32P4_SPI_REG_BASE, - baseFuse: ESP32P4_BASEFUSEADDR, - macFuse: ESP32P4_MACFUSEADDR, - usrOffs: ESP32P4_SPI_USR_OFFS, - usr1Offs: ESP32P4_SPI_USR1_OFFS, - usr2Offs: ESP32P4_SPI_USR2_OFFS, - mosiDlenOffs: ESP32P4_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32P4_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32P4_SPI_W0_OFFS, - uartDateReg: ESP32P4_UART_DATE_REG_ADDR, - flashOffs: ESP32P4_BOOTLOADER_FLASH_OFFSET, - }; - case CHIP_FAMILY_ESP32S31: - return { - regBase: ESP32S31_SPI_REG_BASE, - baseFuse: ESP32S31_BASEFUSEADDR, - macFuse: ESP32S31_MACFUSEADDR, - usrOffs: ESP32S31_SPI_USR_OFFS, - usr1Offs: ESP32S31_SPI_USR1_OFFS, - usr2Offs: ESP32S31_SPI_USR2_OFFS, - mosiDlenOffs: ESP32S31_SPI_MOSI_DLEN_OFFS, - misoDlenOffs: ESP32S31_SPI_MISO_DLEN_OFFS, - w0Offs: ESP32S31_SPI_W0_OFFS, - uartDateReg: ESP32S31_UART_DATE_REG_ADDR, - flashOffs: ESP32S31_BOOTLOADER_FLASH_OFFSET, - }; - default: - return { - regBase: -1, - baseFuse: -1, - macFuse: -1, - usrOffs: -1, - usr1Offs: -1, - usr2Offs: -1, - mosiDlenOffs: -1, - misoDlenOffs: -1, - w0Offs: -1, - uartDateReg: -1, - flashOffs: -1, - }; - } -}; -class SlipReadError extends Error { - constructor(message) { - super(message); - this.name = "SlipReadError"; - } -} - -const getStubCode = async (chipFamily, chipRevision) => { - let stubcode; - // Chips without stub support yet - if (chipFamily == CHIP_FAMILY_ESP32H4 || - chipFamily == CHIP_FAMILY_ESP32H21 || - chipFamily == CHIP_FAMILY_ESP32S31) { - return null; - } - if (chipFamily == CHIP_FAMILY_ESP32) { - stubcode = await import('./esp32-BL5RXAvE.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP32S2) { - stubcode = await import('./esp32s2-t0j-Iiag.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP32S3) { - stubcode = await import('./esp32s3-B8l06aKE.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP8266) { - stubcode = await import('./esp8266-nEkNAo8K.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP32C2) { - stubcode = await import('./esp32c2-JZd7VMTK.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP32C3) { - stubcode = await import('./esp32c3--2RgnV8f.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP32C5) { - stubcode = await import('./esp32c5-D7Zxncy7.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP32C6) { - stubcode = await import('./esp32c6-B8dieLFx.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP32C61) { - stubcode = await import('./esp32c61-CVOVhUkw.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP32H2) { - stubcode = await import('./esp32h2-C7Y4kn-J.js'); - } - else if (chipFamily == CHIP_FAMILY_ESP32P4) { - // ESP32-P4: Use esp32p4r3.json for Rev. 300+, esp32p4.json for older revisions - if (chipRevision !== null && chipRevision !== undefined && chipRevision >= 300) { - stubcode = await import('./esp32p4r3-CW9u2O6_.js'); - } - else { - stubcode = await import('./esp32p4-BN3KBRYS.js'); - } - } - else { - // Unknown chip family - no stub available - return null; - } - // Base64 decode the text and data - return { - ...stubcode, - text: toByteArray(atob(stubcode.text)), - data: toByteArray(atob(stubcode.data)), - }; -}; - -const FLASH_MANUFACTURERS = { - 0xef: "Winbond", - 0xc8: "GigaDevice", - 0x9d: "ISSI", - 0xc2: "Macronix/MXIC", - 0x20: "XMC / Micron", - 0x1c: "EON", - 0x85: "Puya", - 0x68: "BOYA", - 0xa1: "Fudan Microelectronics (FM)", - 0x01: "Spansion/Cypress", - 0x5e: "Zbit", - 0x37: "AMIC", - 0xe0: "Berg Micro", -}; -const FLASH_DEVICES = { - 0x010219: "S25FL256S (256Mbit)", - 0x014015: "S25FL016K (16Mbit)", - 0x014016: "S25FL032K (32Mbit)", - 0x016017: "S25FL064L (64Mbit)", - 0x016018: "S25FL128L (128Mbit)", - 0x1c3013: "EN25Q40 (4Mbit)", - 0x1c3014: "EN25Q80A (8Mbit)", - 0x1c3015: "EN25Q16 (16Mbit)", - 0x1c3016: "EN25Q32B (32Mbit)", - 0x1c3017: "EN25Q64 (64Mbit)", - 0x1c3018: "EN25Q128 (128Mbit)", - 0x1c7015: "EN25QH16 (16Mbit)", - 0x1c7016: "EN25QH32 (32Mbit)", - 0x1c7017: "EN25QH64 (64Mbit)", - 0x1c7018: "EN25QH128 (128Mbit)", - 0x204015: "XM25QH16C (16Mbit)", - 0x204016: "XM25QH32B (32Mbit)", - 0x204017: "XM25QH64C (64Mbit)", - 0x204018: "XM25QH128C (128Mbit)", - 0x204019: "XM25QH256C (256Mbit)", - 0x204119: "XM25QU256C (256Mbit)", - 0x207017: "XM25QH64A (64Mbit)", - 0x207018: "XM25QH128A (128Mbit)", - 0x20ba16: "N25Q032A (32Mbit)", - 0x20ba17: "N25Q064A (64Mbit)", - 0x20ba18: "N25Q128A (128Mbit)", - 0x20bb15: "N25Q016A (16Mbit)", - 0x372015: "A25L016 (16Mbit)", - 0x372016: "A25L032 (32Mbit)", - 0x374016: "A25LQ032 (32Mbit)", - 0x5e4015: "ZB25VQ16 (16Mbit)", - 0x5e4016: "ZB25VQ32 (32Mbit)", - 0x5e4017: "ZB25VQ64 (64Mbit)", - 0x5e4018: "ZB25VQ128 (128Mbit)", - 0x684015: "BY25Q16 (16Mbit)", - 0x684016: "BY25Q32 (32Mbit)", - 0x684017: "BY25Q64 (64Mbit)", - 0x684018: "BY25Q128 (128Mbit)", - 0x856015: "P25Q16H (16Mbit)", - 0x856016: "P25Q32H (32Mbit)", - 0x856017: "P25Q64H (64Mbit)", - 0x856018: "P25Q128H (128Mbit)", - 0x9d6015: "IS25LP016 (16Mbit)", - 0x9d6016: "IS25LP032 (32Mbit)", - 0x9d6017: "IS25LP064 (64Mbit)", - 0x9d6018: "IS25LP128 (128Mbit)", - 0x9d6019: "IS25LP256 (256Mbit)", - 0x9d7015: "IS25WP016 (16Mbit)", - 0x9d7016: "IS25WP032 (32Mbit)", - 0x9d7017: "IS25WP064 (64Mbit)", - 0x9d7018: "IS25WP128 (128Mbit)", - 0x9d7019: "IS25WP256 (256Mbit)", - 0xa14014: "FM25Q08 (8Mbit)", - 0xa14015: "FM25Q16 (16Mbit)", - 0xa14016: "FM25Q32 (32Mbit)", - 0xa14017: "FM25Q64 (64Mbit)", - 0xa14018: "FM25Q128 (128Mbit)", - 0xc22010: "MX25L512E (512Kbit)", - 0xc22011: "MX25L1005C (1Mbit)", - 0xc22012: "MX25L2005C (2Mbit)", - 0xc22013: "MX25L4005 (4Mbit)", - 0xc22014: "MX25L8005 (8Mbit)", - 0xc22015: "MX25L1605D (16Mbit)", - 0xc22016: "MX25L3205D (32Mbit)", - 0xc22017: "MX25L6405D (64Mbit)", - 0xc22018: "MX25L12805D (128Mbit)", - 0xc22019: "MX25L25635E (256Mbit)", - 0xc2201a: "MX25L51245G (512Mbit)", - 0xc25e16: "MX25L3233F (32Mbit)", - 0xc84011: "GD25Q10 (1Mbit)", - 0xc84012: "GD25Q20 (2Mbit)", - 0xc84013: "GD25Q40 (4Mbit)", - 0xc84014: "GD25Q80 (8Mbit)", - 0xc84015: "GD25Q16 (16Mbit)", - 0xc84016: "GD25Q32 (32Mbit)", - 0xc84017: "GD25Q64 (64Mbit)", - 0xc84018: "GD25Q127C (128Mbit)", - 0xc84019: "GD25Q256 (256Mbit)", - 0xc84020: "GD25Q512 (512Mbit)", - 0xc86019: "GD25LQ256D (256Mbit)", - 0xe04015: "BG25Q16A (16Mbit)", - 0xe04016: "BG25Q32 (32Mbit)", - 0xe04017: "BG25Q64 (64Mbit)", - 0xe04018: "BG25Q128 (128Mbit)", - 0xef4014: "W25Q80 (8Mbit)", - 0xef4015: "W25Q16 (16Mbit)", - 0xef4016: "W25Q32 (32Mbit)", - 0xef4017: "W25Q64 (64Mbit)", - 0xef4018: "W25Q128 (128Mbit)", - 0xef4019: "W25Q256 (256Mbit)", - 0xef4020: "W25Q512JV (512Mbit)", - 0xef5012: "W25Q20BW (2Mbit)", - 0xef5013: "W25Q40BW (4Mbit)", - 0xef6011: "W25Q10EW (1Mbit)", - 0xef6012: "W25Q20EW (2Mbit)", - 0xef6013: "W25Q40EW (4Mbit)", -}; - -/*! pako 2.1.0 https://github.com/nodeca/pako @license (MIT AND Zlib) */ -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -/* eslint-disable space-unary-ops */ - -/* Public constants ==========================================================*/ -/* ===========================================================================*/ - - -//const Z_FILTERED = 1; -//const Z_HUFFMAN_ONLY = 2; -//const Z_RLE = 3; -const Z_FIXED$1 = 4; -//const Z_DEFAULT_STRATEGY = 0; - -/* Possible values of the data_type field (though see inflate()) */ -const Z_BINARY = 0; -const Z_TEXT = 1; -//const Z_ASCII = 1; // = Z_TEXT -const Z_UNKNOWN$1 = 2; - -/*============================================================================*/ - - -function zero$1(buf) { let len = buf.length; while (--len >= 0) { buf[len] = 0; } } - -// From zutil.h - -const STORED_BLOCK = 0; -const STATIC_TREES = 1; -const DYN_TREES = 2; -/* The three kinds of block type */ - -const MIN_MATCH$1 = 3; -const MAX_MATCH$1 = 258; -/* The minimum and maximum match lengths */ - -// From deflate.h -/* =========================================================================== - * Internal compression state. - */ - -const LENGTH_CODES$1 = 29; -/* number of length codes, not counting the special END_BLOCK code */ - -const LITERALS$1 = 256; -/* number of literal bytes 0..255 */ - -const L_CODES$1 = LITERALS$1 + 1 + LENGTH_CODES$1; -/* number of Literal or Length codes, including the END_BLOCK code */ - -const D_CODES$1 = 30; -/* number of distance codes */ - -const BL_CODES$1 = 19; -/* number of codes used to transfer the bit lengths */ - -const HEAP_SIZE$1 = 2 * L_CODES$1 + 1; -/* maximum heap size */ - -const MAX_BITS$1 = 15; -/* All codes must not exceed MAX_BITS bits */ - -const Buf_size = 16; -/* size of bit buffer in bi_buf */ - - -/* =========================================================================== - * Constants - */ - -const MAX_BL_BITS = 7; -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -const END_BLOCK = 256; -/* end of block literal code */ - -const REP_3_6 = 16; -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -const REPZ_3_10 = 17; -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -const REPZ_11_138 = 18; -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -/* eslint-disable comma-spacing,array-bracket-spacing */ -const extra_lbits = /* extra bits for each length code */ - new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]); - -const extra_dbits = /* extra bits for each distance code */ - new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]); - -const extra_blbits = /* extra bits for each bit length code */ - new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]); - -const bl_order = - new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]); -/* eslint-enable comma-spacing,array-bracket-spacing */ - -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -// We pre-fill arrays with 0 to avoid uninitialized gaps - -const DIST_CODE_LEN = 512; /* see definition of array dist_code below */ - -// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1 -const static_ltree = new Array((L_CODES$1 + 2) * 2); -zero$1(static_ltree); -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -const static_dtree = new Array(D_CODES$1 * 2); -zero$1(static_dtree); -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -const _dist_code = new Array(DIST_CODE_LEN); -zero$1(_dist_code); -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -const _length_code = new Array(MAX_MATCH$1 - MIN_MATCH$1 + 1); -zero$1(_length_code); -/* length code for each normalized match length (0 == MIN_MATCH) */ - -const base_length = new Array(LENGTH_CODES$1); -zero$1(base_length); -/* First normalized length for each code (0 = MIN_MATCH) */ - -const base_dist = new Array(D_CODES$1); -zero$1(base_dist); -/* First normalized distance for each code (0 = distance of 1) */ - - -function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) { - - this.static_tree = static_tree; /* static tree or NULL */ - this.extra_bits = extra_bits; /* extra bits for each code or NULL */ - this.extra_base = extra_base; /* base index for extra_bits */ - this.elems = elems; /* max number of elements in the tree */ - this.max_length = max_length; /* max bit length for the codes */ - - // show if `static_tree` has data or dummy - needed for monomorphic objects - this.has_stree = static_tree && static_tree.length; -} - - -let static_l_desc; -let static_d_desc; -let static_bl_desc; - - -function TreeDesc(dyn_tree, stat_desc) { - this.dyn_tree = dyn_tree; /* the dynamic tree */ - this.max_code = 0; /* largest code with non zero frequency */ - this.stat_desc = stat_desc; /* the corresponding static tree */ -} - - - -const d_code = (dist) => { - - return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; -}; - - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -const put_short = (s, w) => { -// put_byte(s, (uch)((w) & 0xff)); -// put_byte(s, (uch)((ush)(w) >> 8)); - s.pending_buf[s.pending++] = (w) & 0xff; - s.pending_buf[s.pending++] = (w >>> 8) & 0xff; -}; - - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -const send_bits = (s, value, length) => { - - if (s.bi_valid > (Buf_size - length)) { - s.bi_buf |= (value << s.bi_valid) & 0xffff; - put_short(s, s.bi_buf); - s.bi_buf = value >> (Buf_size - s.bi_valid); - s.bi_valid += length - Buf_size; - } else { - s.bi_buf |= (value << s.bi_valid) & 0xffff; - s.bi_valid += length; - } -}; - - -const send_code = (s, c, tree) => { - - send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/); -}; - - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -const bi_reverse = (code, len) => { - - let res = 0; - do { - res |= code & 1; - code >>>= 1; - res <<= 1; - } while (--len > 0); - return res >>> 1; -}; - - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -const bi_flush = (s) => { - - if (s.bi_valid === 16) { - put_short(s, s.bi_buf); - s.bi_buf = 0; - s.bi_valid = 0; - - } else if (s.bi_valid >= 8) { - s.pending_buf[s.pending++] = s.bi_buf & 0xff; - s.bi_buf >>= 8; - s.bi_valid -= 8; - } -}; - - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -const gen_bitlen = (s, desc) => { -// deflate_state *s; -// tree_desc *desc; /* the tree descriptor */ - - const tree = desc.dyn_tree; - const max_code = desc.max_code; - const stree = desc.stat_desc.static_tree; - const has_stree = desc.stat_desc.has_stree; - const extra = desc.stat_desc.extra_bits; - const base = desc.stat_desc.extra_base; - const max_length = desc.stat_desc.max_length; - let h; /* heap index */ - let n, m; /* iterate over the tree elements */ - let bits; /* bit length */ - let xbits; /* extra bits */ - let f; /* frequency */ - let overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS$1; bits++) { - s.bl_count[bits] = 0; - } - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */ - - for (h = s.heap_max + 1; h < HEAP_SIZE$1; h++) { - n = s.heap[h]; - bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; - if (bits > max_length) { - bits = max_length; - overflow++; - } - tree[n * 2 + 1]/*.Len*/ = bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) { continue; } /* not a leaf node */ - - s.bl_count[bits]++; - xbits = 0; - if (n >= base) { - xbits = extra[n - base]; - } - f = tree[n * 2]/*.Freq*/; - s.opt_len += f * (bits + xbits); - if (has_stree) { - s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits); - } - } - if (overflow === 0) { return; } - - // Tracev((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length - 1; - while (s.bl_count[bits] === 0) { bits--; } - s.bl_count[bits]--; /* move one leaf down the tree */ - s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ - s.bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits !== 0; bits--) { - n = s.bl_count[bits]; - while (n !== 0) { - m = s.heap[--h]; - if (m > max_code) { continue; } - if (tree[m * 2 + 1]/*.Len*/ !== bits) { - // Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/; - tree[m * 2 + 1]/*.Len*/ = bits; - } - n--; - } - } -}; - - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -const gen_codes = (tree, max_code, bl_count) => { -// ct_data *tree; /* the tree to decorate */ -// int max_code; /* largest code with non zero frequency */ -// ushf *bl_count; /* number of codes at each bit length */ - - const next_code = new Array(MAX_BITS$1 + 1); /* next code value for each bit length */ - let code = 0; /* running code value */ - let bits; /* bit index */ - let n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS$1; bits++) { - code = (code + bl_count[bits - 1]) << 1; - next_code[bits] = code; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - //Assert (code + bl_count[MAX_BITS]-1 == (1< { - - let n; /* iterates over tree elements */ - let bits; /* bit counter */ - let length; /* length value */ - let code; /* code value */ - let dist; /* distance index */ - const bl_count = new Array(MAX_BITS$1 + 1); - /* number of codes at each bit length for an optimal tree */ - - // do check in _tr_init() - //if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ -/*#ifdef NO_INIT_GLOBAL_POINTERS - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; -#endif*/ - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES$1 - 1; code++) { - base_length[code] = length; - for (n = 0; n < (1 << extra_lbits[code]); n++) { - _length_code[length++] = code; - } - } - //Assert (length == 256, "tr_static_init: length != 256"); - /* Note that the length 255 (match length 258) can be represented - * in two different ways: code 284 + 5 bits or code 285, so we - * overwrite length_code[255] to use the best encoding: - */ - _length_code[length - 1] = code; - - /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ - dist = 0; - for (code = 0; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1 << extra_dbits[code]); n++) { - _dist_code[dist++] = code; - } - } - //Assert (dist == 256, "tr_static_init: dist != 256"); - dist >>= 7; /* from now on, all distances are divided by 128 */ - for (; code < D_CODES$1; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { - _dist_code[256 + dist++] = code; - } - } - //Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS$1; bits++) { - bl_count[bits] = 0; - } - - n = 0; - while (n <= 143) { - static_ltree[n * 2 + 1]/*.Len*/ = 8; - n++; - bl_count[8]++; - } - while (n <= 255) { - static_ltree[n * 2 + 1]/*.Len*/ = 9; - n++; - bl_count[9]++; - } - while (n <= 279) { - static_ltree[n * 2 + 1]/*.Len*/ = 7; - n++; - bl_count[7]++; - } - while (n <= 287) { - static_ltree[n * 2 + 1]/*.Len*/ = 8; - n++; - bl_count[8]++; - } - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes(static_ltree, L_CODES$1 + 1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES$1; n++) { - static_dtree[n * 2 + 1]/*.Len*/ = 5; - static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5); - } - - // Now data ready and we can init static trees - static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS$1 + 1, L_CODES$1, MAX_BITS$1); - static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES$1, MAX_BITS$1); - static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES$1, MAX_BL_BITS); - - //static_init_done = true; -}; - - -/* =========================================================================== - * Initialize a new block. - */ -const init_block = (s) => { - - let n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES$1; n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; } - for (n = 0; n < D_CODES$1; n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; } - for (n = 0; n < BL_CODES$1; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; } - - s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1; - s.opt_len = s.static_len = 0; - s.sym_next = s.matches = 0; -}; - - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -const bi_windup = (s) => -{ - if (s.bi_valid > 8) { - put_short(s, s.bi_buf); - } else if (s.bi_valid > 0) { - //put_byte(s, (Byte)s->bi_buf); - s.pending_buf[s.pending++] = s.bi_buf; - } - s.bi_buf = 0; - s.bi_valid = 0; -}; - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -const smaller = (tree, n, m, depth) => { - - const _n2 = n * 2; - const _m2 = m * 2; - return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || - (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); -}; - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -const pqdownheap = (s, tree, k) => { -// deflate_state *s; -// ct_data *tree; /* the tree to restore */ -// int k; /* node to move down */ - - const v = s.heap[k]; - let j = k << 1; /* left son of k */ - while (j <= s.heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s.heap_len && - smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s.heap[j], s.depth)) { break; } - - /* Exchange v with the smallest son */ - s.heap[k] = s.heap[j]; - k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s.heap[k] = v; -}; - - -// inlined manually -// const SMALLEST = 1; - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -const compress_block = (s, ltree, dtree) => { -// deflate_state *s; -// const ct_data *ltree; /* literal tree */ -// const ct_data *dtree; /* distance tree */ - - let dist; /* distance of matched string */ - let lc; /* match length or unmatched char (if dist == 0) */ - let sx = 0; /* running index in sym_buf */ - let code; /* the code to send */ - let extra; /* number of extra bits to send */ - - if (s.sym_next !== 0) { - do { - dist = s.pending_buf[s.sym_buf + sx++] & 0xff; - dist += (s.pending_buf[s.sym_buf + sx++] & 0xff) << 8; - lc = s.pending_buf[s.sym_buf + sx++]; - if (dist === 0) { - send_code(s, lc, ltree); /* send a literal byte */ - //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code + LITERALS$1 + 1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra !== 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - //Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra !== 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and sym_buf is ok: */ - //Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); - - } while (sx < s.sym_next); - } - - send_code(s, END_BLOCK, ltree); -}; - - -/* =========================================================================== - * Construct one Huffman tree and assigns the code bit strings and lengths. - * Update the total bit length for the current block. - * IN assertion: the field freq is set for all tree elements. - * OUT assertions: the fields len and code are set to the optimal bit length - * and corresponding code. The length opt_len is updated; static_len is - * also updated if stree is not null. The field max_code is set. - */ -const build_tree = (s, desc) => { -// deflate_state *s; -// tree_desc *desc; /* the tree descriptor */ - - const tree = desc.dyn_tree; - const stree = desc.stat_desc.static_tree; - const has_stree = desc.stat_desc.has_stree; - const elems = desc.stat_desc.elems; - let n, m; /* iterate over heap elements */ - let max_code = -1; /* largest code with non zero frequency */ - let node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s.heap_len = 0; - s.heap_max = HEAP_SIZE$1; - - for (n = 0; n < elems; n++) { - if (tree[n * 2]/*.Freq*/ !== 0) { - s.heap[++s.heap_len] = max_code = n; - s.depth[n] = 0; - - } else { - tree[n * 2 + 1]/*.Len*/ = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s.heap_len < 2) { - node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); - tree[node * 2]/*.Freq*/ = 1; - s.depth[node] = 0; - s.opt_len--; - - if (has_stree) { - s.static_len -= stree[node * 2 + 1]/*.Len*/; - } - /* node is 0 or 1 so it does not have extra bits */ - } - desc.max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - //pqremove(s, tree, n); /* n = node of least frequency */ - /*** pqremove ***/ - n = s.heap[1/*SMALLEST*/]; - s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; - pqdownheap(s, tree, 1/*SMALLEST*/); - /***/ - - m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ - - s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ - s.heap[--s.heap_max] = m; - - /* Create a new node father of n and m */ - tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; - s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; - tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node; - - /* and insert the new node in the heap */ - s.heap[1/*SMALLEST*/] = node++; - pqdownheap(s, tree, 1/*SMALLEST*/); - - } while (s.heap_len >= 2); - - s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes(tree, max_code, s.bl_count); -}; - - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -const scan_tree = (s, tree, max_code) => { -// deflate_state *s; -// ct_data *tree; /* the tree to be scanned */ -// int max_code; /* and its largest code of non zero frequency */ - - let n; /* iterates over all tree elements */ - let prevlen = -1; /* last emitted length */ - let curlen; /* length of current code */ - - let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ - - let count = 0; /* repeat count of the current code */ - let max_count = 7; /* max repeat count */ - let min_count = 4; /* min repeat count */ - - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; - - if (++count < max_count && curlen === nextlen) { - continue; - - } else if (count < min_count) { - s.bl_tree[curlen * 2]/*.Freq*/ += count; - - } else if (curlen !== 0) { - - if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } - s.bl_tree[REP_3_6 * 2]/*.Freq*/++; - - } else if (count <= 10) { - s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++; - - } else { - s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++; - } - - count = 0; - prevlen = curlen; - - if (nextlen === 0) { - max_count = 138; - min_count = 3; - - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - - } else { - max_count = 7; - min_count = 4; - } - } -}; - - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -const send_tree = (s, tree, max_code) => { -// deflate_state *s; -// ct_data *tree; /* the tree to be scanned */ -// int max_code; /* and its largest code of non zero frequency */ - - let n; /* iterates over all tree elements */ - let prevlen = -1; /* last emitted length */ - let curlen; /* length of current code */ - - let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ - - let count = 0; /* repeat count of the current code */ - let max_count = 7; /* max repeat count */ - let min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; - - if (++count < max_count && curlen === nextlen) { - continue; - - } else if (count < min_count) { - do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); - - } else if (curlen !== 0) { - if (curlen !== prevlen) { - send_code(s, curlen, s.bl_tree); - count--; - } - //Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s.bl_tree); - send_bits(s, count - 3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s.bl_tree); - send_bits(s, count - 3, 3); - - } else { - send_code(s, REPZ_11_138, s.bl_tree); - send_bits(s, count - 11, 7); - } - - count = 0; - prevlen = curlen; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - - } else { - max_count = 7; - min_count = 4; - } - } -}; - - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -const build_bl_tree = (s) => { - - let max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, s.dyn_ltree, s.l_desc.max_code); - scan_tree(s, s.dyn_dtree, s.d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, s.bl_desc); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES$1 - 1; max_blindex >= 3; max_blindex--) { - if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) { - break; - } - } - /* Update opt_len to include the bit length tree and counts */ - s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; - //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - // s->opt_len, s->static_len)); - - return max_blindex; -}; - - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -const send_all_trees = (s, lcodes, dcodes, blcodes) => { -// deflate_state *s; -// int lcodes, dcodes, blcodes; /* number of codes for each tree */ - - let rank; /* index in bl_order */ - - //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - // "too many codes"); - //Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes - 1, 5); - send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3); - } - //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */ - //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */ - //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -}; - - -/* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "block list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ -const detect_data_type = (s) => { - /* block_mask is the bit mask of block-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - let block_mask = 0xf3ffc07f; - let n; - - /* Check for non-textual ("block-listed") bytes. */ - for (n = 0; n <= 31; n++, block_mask >>>= 1) { - if ((block_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) { - return Z_BINARY; - } - } - - /* Check for textual ("allow-listed") bytes. */ - if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || - s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { - return Z_TEXT; - } - for (n = 32; n < LITERALS$1; n++) { - if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { - return Z_TEXT; - } - } - - /* There are no "block-listed" or "allow-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; -}; - - -let static_init_done = false; - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -const _tr_init$1 = (s) => -{ - - if (!static_init_done) { - tr_static_init(); - static_init_done = true; - } - - s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); - s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); - s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); - - s.bi_buf = 0; - s.bi_valid = 0; - - /* Initialize the first block of the first file: */ - init_block(s); -}; - - -/* =========================================================================== - * Send a stored block - */ -const _tr_stored_block$1 = (s, buf, stored_len, last) => { -//DeflateState *s; -//charf *buf; /* input block */ -//ulg stored_len; /* length of input block */ -//int last; /* one if this is the last block for a file */ - - send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */ - bi_windup(s); /* align on byte boundary */ - put_short(s, stored_len); - put_short(s, ~stored_len); - if (stored_len) { - s.pending_buf.set(s.window.subarray(buf, buf + stored_len), s.pending); - } - s.pending += stored_len; -}; - - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - */ -const _tr_align$1 = (s) => { - send_bits(s, STATIC_TREES << 1, 3); - send_code(s, END_BLOCK, static_ltree); - bi_flush(s); -}; - - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and write out the encoded block. - */ -const _tr_flush_block$1 = (s, buf, stored_len, last) => { -//DeflateState *s; -//charf *buf; /* input block, or NULL if too old */ -//ulg stored_len; /* length of input block */ -//int last; /* one if this is the last block for a file */ - - let opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - let max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s.level > 0) { - - /* Check if the file is binary or text */ - if (s.strm.data_type === Z_UNKNOWN$1) { - s.strm.data_type = detect_data_type(s); - } - - /* Construct the literal and distance trees */ - build_tree(s, s.l_desc); - // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - // s->static_len)); - - build_tree(s, s.d_desc); - // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - // s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s.opt_len + 3 + 7) >>> 3; - static_lenb = (s.static_len + 3 + 7) >>> 3; - - // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - // s->sym_next / 3)); - - if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } - - } else { - // Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - - if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) { - /* 4: two words for the lengths */ - - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block$1(s, buf, stored_len, last); - - } else if (s.strategy === Z_FIXED$1 || static_lenb === opt_lenb) { - - send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3); - compress_block(s, static_ltree, static_dtree); - - } else { - send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); - send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); - compress_block(s, s.dyn_ltree, s.dyn_dtree); - } - // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (last) { - bi_windup(s); - } - // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - // s->compressed_len-7*last)); -}; - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -const _tr_tally$1 = (s, dist, lc) => { -// deflate_state *s; -// unsigned dist; /* distance of matched string */ -// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ - - s.pending_buf[s.sym_buf + s.sym_next++] = dist; - s.pending_buf[s.sym_buf + s.sym_next++] = dist >> 8; - s.pending_buf[s.sym_buf + s.sym_next++] = lc; - if (dist === 0) { - /* lc is the unmatched char */ - s.dyn_ltree[lc * 2]/*.Freq*/++; - } else { - s.matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - //Assert((ush)dist < (ush)MAX_DIST(s) && - // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s.dyn_ltree[(_length_code[lc] + LITERALS$1 + 1) * 2]/*.Freq*/++; - s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; - } - - return (s.sym_next === s.sym_end); -}; - -var _tr_init_1 = _tr_init$1; -var _tr_stored_block_1 = _tr_stored_block$1; -var _tr_flush_block_1 = _tr_flush_block$1; -var _tr_tally_1 = _tr_tally$1; -var _tr_align_1 = _tr_align$1; - -var trees = { - _tr_init: _tr_init_1, - _tr_stored_block: _tr_stored_block_1, - _tr_flush_block: _tr_flush_block_1, - _tr_tally: _tr_tally_1, - _tr_align: _tr_align_1 -}; - -// Note: adler32 takes 12% for level 0 and 2% for level 6. -// It isn't worth it to make additional optimizations as in original. -// Small size is preferable. - -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -const adler32 = (adler, buf, len, pos) => { - let s1 = (adler & 0xffff) |0, - s2 = ((adler >>> 16) & 0xffff) |0, - n = 0; - - while (len !== 0) { - // Set limit ~ twice less than 5552, to keep - // s2 in 31-bits, because we force signed ints. - // in other case %= will fail. - n = len > 2000 ? 2000 : len; - len -= n; - - do { - s1 = (s1 + buf[pos++]) |0; - s2 = (s2 + s1) |0; - } while (--n); - - s1 %= 65521; - s2 %= 65521; - } - - return (s1 | (s2 << 16)) |0; -}; - - -var adler32_1 = adler32; - -// Note: we can't get significant speed boost here. -// So write code to minimize size - no pregenerated tables -// and array tools dependencies. - -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -// Use ordinary array, since untyped makes no boost here -const makeTable = () => { - let c, table = []; - - for (var n = 0; n < 256; n++) { - c = n; - for (var k = 0; k < 8; k++) { - c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); - } - table[n] = c; - } - - return table; -}; - -// Create table on load. Just 255 signed longs. Not a problem. -const crcTable = new Uint32Array(makeTable()); - - -const crc32 = (crc, buf, len, pos) => { - const t = crcTable; - const end = pos + len; - - crc ^= -1; - - for (let i = pos; i < end; i++) { - crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; - } - - return (crc ^ (-1)); // >>> 0; -}; - - -var crc32_1 = crc32; - -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -var messages = { - 2: 'need dictionary', /* Z_NEED_DICT 2 */ - 1: 'stream end', /* Z_STREAM_END 1 */ - 0: '', /* Z_OK 0 */ - '-1': 'file error', /* Z_ERRNO (-1) */ - '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ - '-3': 'data error', /* Z_DATA_ERROR (-3) */ - '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ - '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ - '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ -}; - -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -var constants$2 = { - - /* Allowed flush values; see deflate() and inflate() below for details */ - Z_NO_FLUSH: 0, - Z_PARTIAL_FLUSH: 1, - Z_SYNC_FLUSH: 2, - Z_FULL_FLUSH: 3, - Z_FINISH: 4, - Z_BLOCK: 5, - /* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - Z_OK: 0, - Z_STREAM_END: 1, - Z_STREAM_ERROR: -2, - Z_DATA_ERROR: -3, - Z_BUF_ERROR: -5, - Z_DEFAULT_COMPRESSION: -1, - - - Z_FILTERED: 1, - Z_HUFFMAN_ONLY: 2, - Z_RLE: 3, - Z_FIXED: 4, - Z_DEFAULT_STRATEGY: 0, - - //Z_ASCII: 1, // = Z_TEXT (deprecated) - Z_UNKNOWN: 2, - - /* The deflate compression method */ - Z_DEFLATED: 8 - //Z_NULL: null // Use -1 or null inline, depending on var type -}; - -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -const { _tr_init, _tr_stored_block, _tr_flush_block, _tr_tally, _tr_align } = trees; - - - - -/* Public constants ==========================================================*/ -/* ===========================================================================*/ - -const { - Z_NO_FLUSH: Z_NO_FLUSH$2, Z_PARTIAL_FLUSH, Z_FULL_FLUSH: Z_FULL_FLUSH$1, Z_FINISH: Z_FINISH$3, Z_BLOCK: Z_BLOCK$1, - Z_OK: Z_OK$3, Z_STREAM_END: Z_STREAM_END$3, Z_STREAM_ERROR: Z_STREAM_ERROR$2, Z_DATA_ERROR: Z_DATA_ERROR$2, Z_BUF_ERROR: Z_BUF_ERROR$1, - Z_DEFAULT_COMPRESSION: Z_DEFAULT_COMPRESSION$1, - Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED, Z_DEFAULT_STRATEGY: Z_DEFAULT_STRATEGY$1, - Z_UNKNOWN, - Z_DEFLATED: Z_DEFLATED$2 -} = constants$2; - -/*============================================================================*/ - - -const MAX_MEM_LEVEL = 9; -/* Maximum value for memLevel in deflateInit2 */ -const MAX_WBITS$1 = 15; -/* 32K LZ77 window */ -const DEF_MEM_LEVEL = 8; - - -const LENGTH_CODES = 29; -/* number of length codes, not counting the special END_BLOCK code */ -const LITERALS = 256; -/* number of literal bytes 0..255 */ -const L_CODES = LITERALS + 1 + LENGTH_CODES; -/* number of Literal or Length codes, including the END_BLOCK code */ -const D_CODES = 30; -/* number of distance codes */ -const BL_CODES = 19; -/* number of codes used to transfer the bit lengths */ -const HEAP_SIZE = 2 * L_CODES + 1; -/* maximum heap size */ -const MAX_BITS = 15; -/* All codes must not exceed MAX_BITS bits */ - -const MIN_MATCH = 3; -const MAX_MATCH = 258; -const MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); - -const PRESET_DICT = 0x20; - -const INIT_STATE = 42; /* zlib header -> BUSY_STATE */ -//#ifdef GZIP -const GZIP_STATE = 57; /* gzip header -> BUSY_STATE | EXTRA_STATE */ -//#endif -const EXTRA_STATE = 69; /* gzip extra block -> NAME_STATE */ -const NAME_STATE = 73; /* gzip file name -> COMMENT_STATE */ -const COMMENT_STATE = 91; /* gzip comment -> HCRC_STATE */ -const HCRC_STATE = 103; /* gzip header CRC -> BUSY_STATE */ -const BUSY_STATE = 113; /* deflate -> FINISH_STATE */ -const FINISH_STATE = 666; /* stream complete */ - -const BS_NEED_MORE = 1; /* block not completed, need more input or more output */ -const BS_BLOCK_DONE = 2; /* block flush performed */ -const BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ -const BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ - -const OS_CODE = 0x03; // Unix :) . Don't detect, use this default. - -const err = (strm, errorCode) => { - strm.msg = messages[errorCode]; - return errorCode; -}; - -const rank = (f) => { - return ((f) * 2) - ((f) > 4 ? 9 : 0); -}; - -const zero = (buf) => { - let len = buf.length; while (--len >= 0) { buf[len] = 0; } -}; - -/* =========================================================================== - * Slide the hash table when sliding the window down (could be avoided with 32 - * bit values at the expense of memory usage). We slide even when level == 0 to - * keep the hash table consistent if we switch back to level > 0 later. - */ -const slide_hash = (s) => { - let n, m; - let p; - let wsize = s.w_size; - - n = s.hash_size; - p = n; - do { - m = s.head[--p]; - s.head[p] = (m >= wsize ? m - wsize : 0); - } while (--n); - n = wsize; -//#ifndef FASTEST - p = n; - do { - m = s.prev[--p]; - s.prev[p] = (m >= wsize ? m - wsize : 0); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -//#endif -}; - -/* eslint-disable new-cap */ -let HASH_ZLIB = (s, prev, data) => ((prev << s.hash_shift) ^ data) & s.hash_mask; -// This hash causes less collisions, https://github.com/nodeca/pako/issues/135 -// But breaks binary compatibility -//let HASH_FAST = (s, prev, data) => ((prev << 8) + (prev >> 8) + (data << 4)) & s.hash_mask; -let HASH = HASH_ZLIB; - - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output, except for - * some deflate_stored() output, goes through this function so some - * applications may wish to modify it to avoid allocating a large - * strm->next_out buffer and copying into it. (See also read_buf()). - */ -const flush_pending = (strm) => { - const s = strm.state; - - //_tr_flush_bits(s); - let len = s.pending; - if (len > strm.avail_out) { - len = strm.avail_out; - } - if (len === 0) { return; } - - strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len), strm.next_out); - strm.next_out += len; - s.pending_out += len; - strm.total_out += len; - strm.avail_out -= len; - s.pending -= len; - if (s.pending === 0) { - s.pending_out = 0; - } -}; - - -const flush_block_only = (s, last) => { - _tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); - s.block_start = s.strstart; - flush_pending(s.strm); -}; - - -const put_byte = (s, b) => { - s.pending_buf[s.pending++] = b; -}; - - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -const putShortMSB = (s, b) => { - - // put_byte(s, (Byte)(b >> 8)); -// put_byte(s, (Byte)(b & 0xff)); - s.pending_buf[s.pending++] = (b >>> 8) & 0xff; - s.pending_buf[s.pending++] = b & 0xff; -}; - - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->input buffer and copying from it. - * (See also flush_pending()). - */ -const read_buf = (strm, buf, start, size) => { - - let len = strm.avail_in; - - if (len > size) { len = size; } - if (len === 0) { return 0; } - - strm.avail_in -= len; - - // zmemcpy(buf, strm->next_in, len); - buf.set(strm.input.subarray(strm.next_in, strm.next_in + len), start); - if (strm.state.wrap === 1) { - strm.adler = adler32_1(strm.adler, buf, len, start); - } - - else if (strm.state.wrap === 2) { - strm.adler = crc32_1(strm.adler, buf, len, start); - } - - strm.next_in += len; - strm.total_in += len; - - return len; -}; - - -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -const longest_match = (s, cur_match) => { - - let chain_length = s.max_chain_length; /* max hash chain length */ - let scan = s.strstart; /* current string */ - let match; /* matched string */ - let len; /* length of current match */ - let best_len = s.prev_length; /* best match length so far */ - let nice_match = s.nice_match; /* stop if match long enough */ - const limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? - s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; - - const _win = s.window; // shortcut - - const wmask = s.w_mask; - const prev = s.prev; - - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - - const strend = s.strstart + MAX_MATCH; - let scan_end1 = _win[scan + best_len - 1]; - let scan_end = _win[scan + best_len]; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s.prev_length >= s.good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if (nice_match > s.lookahead) { nice_match = s.lookahead; } - - // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - // Assert(cur_match < s->strstart, "no future"); - match = cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ - - if (_win[match + best_len] !== scan_end || - _win[match + best_len - 1] !== scan_end1 || - _win[match] !== _win[scan] || - _win[++match] !== _win[scan + 1]) { - continue; - } - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2; - match++; - // Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - /*jshint noempty:false*/ - } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - scan < strend); - - // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (strend - scan); - scan = strend - MAX_MATCH; - - if (len > best_len) { - s.match_start = cur_match; - best_len = len; - if (len >= nice_match) { - break; - } - scan_end1 = _win[scan + best_len - 1]; - scan_end = _win[scan + best_len]; - } - } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); - - if (best_len <= s.lookahead) { - return best_len; - } - return s.lookahead; -}; - - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -const fill_window = (s) => { - - const _w_size = s.w_size; - let n, more, str; - - //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - - do { - more = s.window_size - s.lookahead - s.strstart; - - // JS ints have 32 bit, block below not needed - /* Deal with !@#$% 64K limit: */ - //if (sizeof(int) <= 2) { - // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - // more = wsize; - // - // } else if (more == (unsigned)(-1)) { - // /* Very unlikely, but possible on 16 bit machine if - // * strstart == 0 && lookahead == 1 (input done a byte at time) - // */ - // more--; - // } - //} - - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { - - s.window.set(s.window.subarray(_w_size, _w_size + _w_size - more), 0); - s.match_start -= _w_size; - s.strstart -= _w_size; - /* we now have strstart >= MAX_DIST */ - s.block_start -= _w_size; - if (s.insert > s.strstart) { - s.insert = s.strstart; - } - slide_hash(s); - more += _w_size; - } - if (s.strm.avail_in === 0) { - break; - } - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - //Assert(more >= 2, "more < 2"); - n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); - s.lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s.lookahead + s.insert >= MIN_MATCH) { - str = s.strstart - s.insert; - s.ins_h = s.window[str]; - - /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ - s.ins_h = HASH(s, s.ins_h, s.window[str + 1]); -//#if MIN_MATCH != 3 -// Call update_hash() MIN_MATCH-3 more times -//#endif - while (s.insert) { - /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ - s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]); - - s.prev[str & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = str; - str++; - s.insert--; - if (s.lookahead + s.insert < MIN_MATCH) { - break; - } - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); - - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ -// if (s.high_water < s.window_size) { -// const curr = s.strstart + s.lookahead; -// let init = 0; -// -// if (s.high_water < curr) { -// /* Previous high water mark below current data -- zero WIN_INIT -// * bytes or up to end of window, whichever is less. -// */ -// init = s.window_size - curr; -// if (init > WIN_INIT) -// init = WIN_INIT; -// zmemzero(s->window + curr, (unsigned)init); -// s->high_water = curr + init; -// } -// else if (s->high_water < (ulg)curr + WIN_INIT) { -// /* High water mark at or above current data, but below current data -// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up -// * to end of window, whichever is less. -// */ -// init = (ulg)curr + WIN_INIT - s->high_water; -// if (init > s->window_size - s->high_water) -// init = s->window_size - s->high_water; -// zmemzero(s->window + s->high_water, (unsigned)init); -// s->high_water += init; -// } -// } -// -// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, -// "not enough room for search"); -}; - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * - * In case deflateParams() is used to later switch to a non-zero compression - * level, s->matches (otherwise unused when storing) keeps track of the number - * of hash table slides to perform. If s->matches is 1, then one hash table - * slide will be done when switching. If s->matches is 2, the maximum value - * allowed here, then the hash table will be cleared, since two or more slides - * is the same as a clear. - * - * deflate_stored() is written to minimize the number of times an input byte is - * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunites to have a single copy from next_in to next_out. - */ -const deflate_stored = (s, flush) => { - - /* Smallest worthy block size when not flushing or finishing. By default - * this is 32K. This can be as small as 507 bytes for memLevel == 1. For - * large input and output buffers, the stored block size will be larger. - */ - let min_block = s.pending_buf_size - 5 > s.w_size ? s.w_size : s.pending_buf_size - 5; - - /* Copy as many min_block or larger stored blocks directly to next_out as - * possible. If flushing, copy the remaining available input to next_out as - * stored blocks, if there is enough space. - */ - let len, left, have, last = 0; - let used = s.strm.avail_in; - do { - /* Set len to the maximum size block that we can copy directly with the - * available input data and output space. Set left to how much of that - * would be copied from what's left in the window. - */ - len = 65535/* MAX_STORED */; /* maximum deflate stored block length */ - have = (s.bi_valid + 42) >> 3; /* number of header bytes */ - if (s.strm.avail_out < have) { /* need room for header */ - break; - } - /* maximum stored block length that will fit in avail_out: */ - have = s.strm.avail_out - have; - left = s.strstart - s.block_start; /* bytes left in window */ - if (len > left + s.strm.avail_in) { - len = left + s.strm.avail_in; /* limit len to the input */ - } - if (len > have) { - len = have; /* limit len to the output */ - } - - /* If the stored block would be less than min_block in length, or if - * unable to copy all of the available input when flushing, then try - * copying to the window and the pending buffer instead. Also don't - * write an empty block when flushing -- deflate() does that. - */ - if (len < min_block && ((len === 0 && flush !== Z_FINISH$3) || - flush === Z_NO_FLUSH$2 || - len !== left + s.strm.avail_in)) { - break; - } - - /* Make a dummy stored block in pending to get the header bytes, - * including any pending bits. This also updates the debugging counts. - */ - last = flush === Z_FINISH$3 && len === left + s.strm.avail_in ? 1 : 0; - _tr_stored_block(s, 0, 0, last); - - /* Replace the lengths in the dummy stored block with len. */ - s.pending_buf[s.pending - 4] = len; - s.pending_buf[s.pending - 3] = len >> 8; - s.pending_buf[s.pending - 2] = ~len; - s.pending_buf[s.pending - 1] = ~len >> 8; - - /* Write the stored block header bytes. */ - flush_pending(s.strm); - -//#ifdef ZLIB_DEBUG -// /* Update debugging counts for the data about to be copied. */ -// s->compressed_len += len << 3; -// s->bits_sent += len << 3; -//#endif - - /* Copy uncompressed bytes from the window to next_out. */ - if (left) { - if (left > len) { - left = len; - } - //zmemcpy(s->strm->next_out, s->window + s->block_start, left); - s.strm.output.set(s.window.subarray(s.block_start, s.block_start + left), s.strm.next_out); - s.strm.next_out += left; - s.strm.avail_out -= left; - s.strm.total_out += left; - s.block_start += left; - len -= left; - } - - /* Copy uncompressed bytes directly from next_in to next_out, updating - * the check value. - */ - if (len) { - read_buf(s.strm, s.strm.output, s.strm.next_out, len); - s.strm.next_out += len; - s.strm.avail_out -= len; - s.strm.total_out += len; - } - } while (last === 0); - - /* Update the sliding window with the last s->w_size bytes of the copied - * data, or append all of the copied data to the existing window if less - * than s->w_size bytes were copied. Also update the number of bytes to - * insert in the hash tables, in the event that deflateParams() switches to - * a non-zero compression level. - */ - used -= s.strm.avail_in; /* number of input bytes directly copied */ - if (used) { - /* If any input was used, then no unused input remains in the window, - * therefore s->block_start == s->strstart. - */ - if (used >= s.w_size) { /* supplant the previous history */ - s.matches = 2; /* clear hash */ - //zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); - s.window.set(s.strm.input.subarray(s.strm.next_in - s.w_size, s.strm.next_in), 0); - s.strstart = s.w_size; - s.insert = s.strstart; - } - else { - if (s.window_size - s.strstart <= used) { - /* Slide the window down. */ - s.strstart -= s.w_size; - //zmemcpy(s->window, s->window + s->w_size, s->strstart); - s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0); - if (s.matches < 2) { - s.matches++; /* add a pending slide_hash() */ - } - if (s.insert > s.strstart) { - s.insert = s.strstart; - } - } - //zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); - s.window.set(s.strm.input.subarray(s.strm.next_in - used, s.strm.next_in), s.strstart); - s.strstart += used; - s.insert += used > s.w_size - s.insert ? s.w_size - s.insert : used; - } - s.block_start = s.strstart; - } - if (s.high_water < s.strstart) { - s.high_water = s.strstart; - } - - /* If the last block was written to next_out, then done. */ - if (last) { - return BS_FINISH_DONE; - } - - /* If flushing and all input has been consumed, then done. */ - if (flush !== Z_NO_FLUSH$2 && flush !== Z_FINISH$3 && - s.strm.avail_in === 0 && s.strstart === s.block_start) { - return BS_BLOCK_DONE; - } - - /* Fill the window with any remaining input. */ - have = s.window_size - s.strstart; - if (s.strm.avail_in > have && s.block_start >= s.w_size) { - /* Slide the window down. */ - s.block_start -= s.w_size; - s.strstart -= s.w_size; - //zmemcpy(s->window, s->window + s->w_size, s->strstart); - s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0); - if (s.matches < 2) { - s.matches++; /* add a pending slide_hash() */ - } - have += s.w_size; /* more space now */ - if (s.insert > s.strstart) { - s.insert = s.strstart; - } - } - if (have > s.strm.avail_in) { - have = s.strm.avail_in; - } - if (have) { - read_buf(s.strm, s.window, s.strstart, have); - s.strstart += have; - s.insert += have > s.w_size - s.insert ? s.w_size - s.insert : have; - } - if (s.high_water < s.strstart) { - s.high_water = s.strstart; - } - - /* There was not enough avail_out to write a complete worthy or flushed - * stored block to next_out. Write a stored block to pending instead, if we - * have enough input for a worthy block, or if flushing and there is enough - * room for the remaining input as a stored block in the pending buffer. - */ - have = (s.bi_valid + 42) >> 3; /* number of header bytes */ - /* maximum stored block length that will fit in pending: */ - have = s.pending_buf_size - have > 65535/* MAX_STORED */ ? 65535/* MAX_STORED */ : s.pending_buf_size - have; - min_block = have > s.w_size ? s.w_size : have; - left = s.strstart - s.block_start; - if (left >= min_block || - ((left || flush === Z_FINISH$3) && flush !== Z_NO_FLUSH$2 && - s.strm.avail_in === 0 && left <= have)) { - len = left > have ? have : left; - last = flush === Z_FINISH$3 && s.strm.avail_in === 0 && - len === left ? 1 : 0; - _tr_stored_block(s, s.block_start, len, last); - s.block_start += len; - flush_pending(s.strm); - } - - /* We've done all we can with the available input and output. */ - return last ? BS_FINISH_STARTED : BS_NEED_MORE; -}; - - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -const deflate_fast = (s, flush) => { - - let hash_head; /* head of the hash chain */ - let bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { - break; /* flush the current block */ - } - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = 0/*NIL*/; - if (s.lookahead >= MIN_MATCH) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s.match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ - } - if (s.match_length >= MIN_MATCH) { - // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only - - /*** _tr_tally_dist(s, s.strstart - s.match_start, - s.match_length - MIN_MATCH, bflush); ***/ - bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); - - s.lookahead -= s.match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { - s.match_length--; /* string at strstart already in table */ - do { - s.strstart++; - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s.match_length !== 0); - s.strstart++; - } else - { - s.strstart += s.match_length; - s.match_length = 0; - s.ins_h = s.window[s.strstart]; - /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ - s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + 1]); - -//#if MIN_MATCH != 3 -// Call UPDATE_HASH() MIN_MATCH-3 more times -//#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - //Tracevv((stderr,"%c", s.window[s.strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart]); - - s.lookahead--; - s.strstart++; - } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1); - if (flush === Z_FINISH$3) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.sym_next) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; -}; - -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -const deflate_slow = (s, flush) => { - - let hash_head; /* head of hash chain */ - let bflush; /* set if current block must be flushed */ - - let max_insert; - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { break; } /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = 0/*NIL*/; - if (s.lookahead >= MIN_MATCH) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - - /* Find the longest match, discarding those <= prev_length. - */ - s.prev_length = s.match_length; - s.prev_match = s.match_start; - s.match_length = MIN_MATCH - 1; - - if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && - s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s.match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ - - if (s.match_length <= 5 && - (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s.match_length = MIN_MATCH - 1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { - max_insert = s.strstart + s.lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - //check_match(s, s.strstart-1, s.prev_match, s.prev_length); - - /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, - s.prev_length - MIN_MATCH, bflush);***/ - bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s.lookahead -= s.prev_length - 1; - s.prev_length -= 2; - do { - if (++s.strstart <= max_insert) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - } while (--s.prev_length !== 0); - s.match_available = 0; - s.match_length = MIN_MATCH - 1; - s.strstart++; - - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - - } else if (s.match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - //Tracevv((stderr,"%c", s->window[s->strstart-1])); - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); - - if (bflush) { - /*** FLUSH_BLOCK_ONLY(s, 0) ***/ - flush_block_only(s, false); - /***/ - } - s.strstart++; - s.lookahead--; - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s.match_available = 1; - s.strstart++; - s.lookahead--; - } - } - //Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s.match_available) { - //Tracevv((stderr,"%c", s->window[s->strstart-1])); - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); - - s.match_available = 0; - } - s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; - if (flush === Z_FINISH$3) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.sym_next) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - - return BS_BLOCK_DONE; -}; - - -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -const deflate_rle = (s, flush) => { - - let bflush; /* set if current block must be flushed */ - let prev; /* byte at distance one to match */ - let scan, strend; /* scan goes up to strend for length of run */ - - const _win = s.window; - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest run, plus one for the unrolled loop. - */ - if (s.lookahead <= MAX_MATCH) { - fill_window(s); - if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH$2) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { break; } /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - s.match_length = 0; - if (s.lookahead >= MIN_MATCH && s.strstart > 0) { - scan = s.strstart - 1; - prev = _win[scan]; - if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { - strend = s.strstart + MAX_MATCH; - do { - /*jshint noempty:false*/ - } while (prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - scan < strend); - s.match_length = MAX_MATCH - (strend - scan); - if (s.match_length > s.lookahead) { - s.match_length = s.lookahead; - } - } - //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (s.match_length >= MIN_MATCH) { - //check_match(s, s.strstart, s.strstart - 1, s.match_length); - - /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ - bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH); - - s.lookahead -= s.match_length; - s.strstart += s.match_length; - s.match_length = 0; - } else { - /* No match, output a literal byte */ - //Tracevv((stderr,"%c", s->window[s->strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart]); - - s.lookahead--; - s.strstart++; - } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = 0; - if (flush === Z_FINISH$3) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.sym_next) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; -}; - -/* =========================================================================== - * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. - * (It will be regenerated if this run of deflate switches away from Huffman.) - */ -const deflate_huff = (s, flush) => { - - let bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we have a literal to write. */ - if (s.lookahead === 0) { - fill_window(s); - if (s.lookahead === 0) { - if (flush === Z_NO_FLUSH$2) { - return BS_NEED_MORE; - } - break; /* flush the current block */ - } - } - - /* Output a literal byte */ - s.match_length = 0; - //Tracevv((stderr,"%c", s->window[s->strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = _tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = 0; - if (flush === Z_FINISH$3) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.sym_next) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; -}; - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -function Config(good_length, max_lazy, nice_length, max_chain, func) { - - this.good_length = good_length; - this.max_lazy = max_lazy; - this.nice_length = nice_length; - this.max_chain = max_chain; - this.func = func; -} - -const configuration_table = [ - /* good lazy nice chain */ - new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ - new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ - new Config(4, 5, 16, 8, deflate_fast), /* 2 */ - new Config(4, 6, 32, 32, deflate_fast), /* 3 */ - - new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ - new Config(8, 16, 32, 32, deflate_slow), /* 5 */ - new Config(8, 16, 128, 128, deflate_slow), /* 6 */ - new Config(8, 32, 128, 256, deflate_slow), /* 7 */ - new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ - new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ -]; - - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -const lm_init = (s) => { - - s.window_size = 2 * s.w_size; - - /*** CLEAR_HASH(s); ***/ - zero(s.head); // Fill with NIL (= 0); - - /* Set the default configuration parameters: - */ - s.max_lazy_match = configuration_table[s.level].max_lazy; - s.good_match = configuration_table[s.level].good_length; - s.nice_match = configuration_table[s.level].nice_length; - s.max_chain_length = configuration_table[s.level].max_chain; - - s.strstart = 0; - s.block_start = 0; - s.lookahead = 0; - s.insert = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - s.ins_h = 0; -}; - - -function DeflateState() { - this.strm = null; /* pointer back to this zlib stream */ - this.status = 0; /* as the name implies */ - this.pending_buf = null; /* output still pending */ - this.pending_buf_size = 0; /* size of pending_buf */ - this.pending_out = 0; /* next pending byte to output to the stream */ - this.pending = 0; /* nb of bytes in the pending buffer */ - this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ - this.gzhead = null; /* gzip header information to write */ - this.gzindex = 0; /* where in extra, name, or comment */ - this.method = Z_DEFLATED$2; /* can only be DEFLATED */ - this.last_flush = -1; /* value of flush param for previous deflate call */ - - this.w_size = 0; /* LZ77 window size (32K by default) */ - this.w_bits = 0; /* log2(w_size) (8..16) */ - this.w_mask = 0; /* w_size - 1 */ - - this.window = null; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. - */ - - this.window_size = 0; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - this.prev = null; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - this.head = null; /* Heads of the hash chains or NIL. */ - - this.ins_h = 0; /* hash index of string to be inserted */ - this.hash_size = 0; /* number of elements in hash table */ - this.hash_bits = 0; /* log2(hash_size) */ - this.hash_mask = 0; /* hash_size-1 */ - - this.hash_shift = 0; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - this.block_start = 0; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - this.match_length = 0; /* length of best match */ - this.prev_match = 0; /* previous match */ - this.match_available = 0; /* set if previous match exists */ - this.strstart = 0; /* start of string to insert */ - this.match_start = 0; /* start of matching string */ - this.lookahead = 0; /* number of valid bytes ahead in window */ - - this.prev_length = 0; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - this.max_chain_length = 0; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - this.max_lazy_match = 0; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ - // That's alias to max_lazy_match, don't use directly - //this.max_insert_length = 0; - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - this.level = 0; /* compression level (1..9) */ - this.strategy = 0; /* favor or force Huffman coding*/ - - this.good_match = 0; - /* Use a faster search when the previous match is longer than this */ - - this.nice_match = 0; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - - /* Didn't use ct_data typedef below to suppress compiler warning */ - - // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - // Use flat array of DOUBLE size, with interleaved fata, - // because JS does not support effective - this.dyn_ltree = new Uint16Array(HEAP_SIZE * 2); - this.dyn_dtree = new Uint16Array((2 * D_CODES + 1) * 2); - this.bl_tree = new Uint16Array((2 * BL_CODES + 1) * 2); - zero(this.dyn_ltree); - zero(this.dyn_dtree); - zero(this.bl_tree); - - this.l_desc = null; /* desc. for literal tree */ - this.d_desc = null; /* desc. for distance tree */ - this.bl_desc = null; /* desc. for bit length tree */ - - //ush bl_count[MAX_BITS+1]; - this.bl_count = new Uint16Array(MAX_BITS + 1); - /* number of codes at each bit length for an optimal tree */ - - //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - this.heap = new Uint16Array(2 * L_CODES + 1); /* heap used to build the Huffman trees */ - zero(this.heap); - - this.heap_len = 0; /* number of elements in the heap */ - this.heap_max = 0; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - this.depth = new Uint16Array(2 * L_CODES + 1); //uch depth[2*L_CODES+1]; - zero(this.depth); - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - this.sym_buf = 0; /* buffer for distances and literals/lengths */ - - this.lit_bufsize = 0; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - this.sym_next = 0; /* running index in sym_buf */ - this.sym_end = 0; /* symbol table full when sym_next reaches this */ - - this.opt_len = 0; /* bit length of current block with optimal trees */ - this.static_len = 0; /* bit length of current block with static trees */ - this.matches = 0; /* number of string matches in current block */ - this.insert = 0; /* bytes at end of window left to insert */ - - - this.bi_buf = 0; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - this.bi_valid = 0; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - - // Used for window memory init. We safely ignore it for JS. That makes - // sense only for pointers and memory check tools. - //this.high_water = 0; - /* High water mark offset in window for initialized bytes -- bytes above - * this are set to zero in order to avoid memory check warnings when - * longest match routines access bytes past the input. This is then - * updated to the new high water mark. - */ -} - - -/* ========================================================================= - * Check for a valid deflate stream state. Return 0 if ok, 1 if not. - */ -const deflateStateCheck = (strm) => { - - if (!strm) { - return 1; - } - const s = strm.state; - if (!s || s.strm !== strm || (s.status !== INIT_STATE && -//#ifdef GZIP - s.status !== GZIP_STATE && -//#endif - s.status !== EXTRA_STATE && - s.status !== NAME_STATE && - s.status !== COMMENT_STATE && - s.status !== HCRC_STATE && - s.status !== BUSY_STATE && - s.status !== FINISH_STATE)) { - return 1; - } - return 0; -}; - - -const deflateResetKeep = (strm) => { - - if (deflateStateCheck(strm)) { - return err(strm, Z_STREAM_ERROR$2); - } - - strm.total_in = strm.total_out = 0; - strm.data_type = Z_UNKNOWN; - - const s = strm.state; - s.pending = 0; - s.pending_out = 0; - - if (s.wrap < 0) { - s.wrap = -s.wrap; - /* was made negative by deflate(..., Z_FINISH); */ - } - s.status = -//#ifdef GZIP - s.wrap === 2 ? GZIP_STATE : -//#endif - s.wrap ? INIT_STATE : BUSY_STATE; - strm.adler = (s.wrap === 2) ? - 0 // crc32(0, Z_NULL, 0) - : - 1; // adler32(0, Z_NULL, 0) - s.last_flush = -2; - _tr_init(s); - return Z_OK$3; -}; - - -const deflateReset = (strm) => { - - const ret = deflateResetKeep(strm); - if (ret === Z_OK$3) { - lm_init(strm.state); - } - return ret; -}; - - -const deflateSetHeader = (strm, head) => { - - if (deflateStateCheck(strm) || strm.state.wrap !== 2) { - return Z_STREAM_ERROR$2; - } - strm.state.gzhead = head; - return Z_OK$3; -}; - - -const deflateInit2 = (strm, level, method, windowBits, memLevel, strategy) => { - - if (!strm) { // === Z_NULL - return Z_STREAM_ERROR$2; - } - let wrap = 1; - - if (level === Z_DEFAULT_COMPRESSION$1) { - level = 6; - } - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } - - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } - - - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED$2 || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED || (windowBits === 8 && wrap !== 1)) { - return err(strm, Z_STREAM_ERROR$2); - } - - - if (windowBits === 8) { - windowBits = 9; - } - /* until 256-byte window bug fixed */ - - const s = new DeflateState(); - - strm.state = s; - s.strm = strm; - s.status = INIT_STATE; /* to pass state test in deflateReset() */ - - s.wrap = wrap; - s.gzhead = null; - s.w_bits = windowBits; - s.w_size = 1 << s.w_bits; - s.w_mask = s.w_size - 1; - - s.hash_bits = memLevel + 7; - s.hash_size = 1 << s.hash_bits; - s.hash_mask = s.hash_size - 1; - s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); - - s.window = new Uint8Array(s.w_size * 2); - s.head = new Uint16Array(s.hash_size); - s.prev = new Uint16Array(s.w_size); - - // Don't need mem init magic for JS. - //s.high_water = 0; /* nothing written to s->window yet */ - - s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - /* We overlay pending_buf and sym_buf. This works since the average size - * for length/distance pairs over any compressed block is assured to be 31 - * bits or less. - * - * Analysis: The longest fixed codes are a length code of 8 bits plus 5 - * extra bits, for lengths 131 to 257. The longest fixed distance codes are - * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest - * possible fixed-codes length/distance pair is then 31 bits total. - * - * sym_buf starts one-fourth of the way into pending_buf. So there are - * three bytes in sym_buf for every four bytes in pending_buf. Each symbol - * in sym_buf is three bytes -- two for the distance and one for the - * literal/length. As each symbol is consumed, the pointer to the next - * sym_buf value to read moves forward three bytes. From that symbol, up to - * 31 bits are written to pending_buf. The closest the written pending_buf - * bits gets to the next sym_buf symbol to read is just before the last - * code is written. At that time, 31*(n-2) bits have been written, just - * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at - * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1 - * symbols are written.) The closest the writing gets to what is unread is - * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and - * can range from 128 to 32768. - * - * Therefore, at a minimum, there are 142 bits of space between what is - * written and what is read in the overlain buffers, so the symbols cannot - * be overwritten by the compressed data. That space is actually 139 bits, - * due to the three-bit fixed-code block header. - * - * That covers the case where either Z_FIXED is specified, forcing fixed - * codes, or when the use of fixed codes is chosen, because that choice - * results in a smaller compressed block than dynamic codes. That latter - * condition then assures that the above analysis also covers all dynamic - * blocks. A dynamic-code block will only be chosen to be emitted if it has - * fewer bits than a fixed-code block would for the same set of symbols. - * Therefore its average symbol length is assured to be less than 31. So - * the compressed data for a dynamic block also cannot overwrite the - * symbols from which it is being constructed. - */ - - s.pending_buf_size = s.lit_bufsize * 4; - s.pending_buf = new Uint8Array(s.pending_buf_size); - - // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`) - //s->sym_buf = s->pending_buf + s->lit_bufsize; - s.sym_buf = s.lit_bufsize; - - //s->sym_end = (s->lit_bufsize - 1) * 3; - s.sym_end = (s.lit_bufsize - 1) * 3; - /* We avoid equality with lit_bufsize*3 because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ - - s.level = level; - s.strategy = strategy; - s.method = method; - - return deflateReset(strm); -}; - -const deflateInit = (strm, level) => { - - return deflateInit2(strm, level, Z_DEFLATED$2, MAX_WBITS$1, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY$1); -}; - - -/* ========================================================================= */ -const deflate$2 = (strm, flush) => { - - if (deflateStateCheck(strm) || flush > Z_BLOCK$1 || flush < 0) { - return strm ? err(strm, Z_STREAM_ERROR$2) : Z_STREAM_ERROR$2; - } - - const s = strm.state; - - if (!strm.output || - (strm.avail_in !== 0 && !strm.input) || - (s.status === FINISH_STATE && flush !== Z_FINISH$3)) { - return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR$1 : Z_STREAM_ERROR$2); - } - - const old_flush = s.last_flush; - s.last_flush = flush; - - /* Flush as much pending output as possible */ - if (s.pending !== 0) { - flush_pending(strm); - if (strm.avail_out === 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s.last_flush = -1; - return Z_OK$3; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && - flush !== Z_FINISH$3) { - return err(strm, Z_BUF_ERROR$1); - } - - /* User must not provide more input after the first FINISH: */ - if (s.status === FINISH_STATE && strm.avail_in !== 0) { - return err(strm, Z_BUF_ERROR$1); - } - - /* Write the header */ - if (s.status === INIT_STATE && s.wrap === 0) { - s.status = BUSY_STATE; - } - if (s.status === INIT_STATE) { - /* zlib header */ - let header = (Z_DEFLATED$2 + ((s.w_bits - 8) << 4)) << 8; - let level_flags = -1; - - if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { - level_flags = 0; - } else if (s.level < 6) { - level_flags = 1; - } else if (s.level === 6) { - level_flags = 2; - } else { - level_flags = 3; - } - header |= (level_flags << 6); - if (s.strstart !== 0) { header |= PRESET_DICT; } - header += 31 - (header % 31); - - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s.strstart !== 0) { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 0xffff); - } - strm.adler = 1; // adler32(0L, Z_NULL, 0); - s.status = BUSY_STATE; - - /* Compression must start with an empty pending buffer */ - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return Z_OK$3; - } - } -//#ifdef GZIP - if (s.status === GZIP_STATE) { - /* gzip header */ - strm.adler = 0; //crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (!s.gzhead) { // s->gzhead == Z_NULL - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s.level === 9 ? 2 : - (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s.status = BUSY_STATE; - - /* Compression must start with an empty pending buffer */ - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return Z_OK$3; - } - } - else { - put_byte(s, (s.gzhead.text ? 1 : 0) + - (s.gzhead.hcrc ? 2 : 0) + - (!s.gzhead.extra ? 0 : 4) + - (!s.gzhead.name ? 0 : 8) + - (!s.gzhead.comment ? 0 : 16) - ); - put_byte(s, s.gzhead.time & 0xff); - put_byte(s, (s.gzhead.time >> 8) & 0xff); - put_byte(s, (s.gzhead.time >> 16) & 0xff); - put_byte(s, (s.gzhead.time >> 24) & 0xff); - put_byte(s, s.level === 9 ? 2 : - (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? - 4 : 0)); - put_byte(s, s.gzhead.os & 0xff); - if (s.gzhead.extra && s.gzhead.extra.length) { - put_byte(s, s.gzhead.extra.length & 0xff); - put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); - } - if (s.gzhead.hcrc) { - strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending, 0); - } - s.gzindex = 0; - s.status = EXTRA_STATE; - } - } - if (s.status === EXTRA_STATE) { - if (s.gzhead.extra/* != Z_NULL*/) { - let beg = s.pending; /* start of bytes to update crc */ - let left = (s.gzhead.extra.length & 0xffff) - s.gzindex; - while (s.pending + left > s.pending_buf_size) { - let copy = s.pending_buf_size - s.pending; - // zmemcpy(s.pending_buf + s.pending, - // s.gzhead.extra + s.gzindex, copy); - s.pending_buf.set(s.gzhead.extra.subarray(s.gzindex, s.gzindex + copy), s.pending); - s.pending = s.pending_buf_size; - //--- HCRC_UPDATE(beg) ---// - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); - } - //---// - s.gzindex += copy; - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return Z_OK$3; - } - beg = 0; - left -= copy; - } - // JS specific: s.gzhead.extra may be TypedArray or Array for backward compatibility - // TypedArray.slice and TypedArray.from don't exist in IE10-IE11 - let gzhead_extra = new Uint8Array(s.gzhead.extra); - // zmemcpy(s->pending_buf + s->pending, - // s->gzhead->extra + s->gzindex, left); - s.pending_buf.set(gzhead_extra.subarray(s.gzindex, s.gzindex + left), s.pending); - s.pending += left; - //--- HCRC_UPDATE(beg) ---// - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); - } - //---// - s.gzindex = 0; - } - s.status = NAME_STATE; - } - if (s.status === NAME_STATE) { - if (s.gzhead.name/* != Z_NULL*/) { - let beg = s.pending; /* start of bytes to update crc */ - let val; - do { - if (s.pending === s.pending_buf_size) { - //--- HCRC_UPDATE(beg) ---// - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); - } - //---// - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return Z_OK$3; - } - beg = 0; - } - // JS specific: little magic to add zero terminator to end of string - if (s.gzindex < s.gzhead.name.length) { - val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); - //--- HCRC_UPDATE(beg) ---// - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); - } - //---// - s.gzindex = 0; - } - s.status = COMMENT_STATE; - } - if (s.status === COMMENT_STATE) { - if (s.gzhead.comment/* != Z_NULL*/) { - let beg = s.pending; /* start of bytes to update crc */ - let val; - do { - if (s.pending === s.pending_buf_size) { - //--- HCRC_UPDATE(beg) ---// - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); - } - //---// - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return Z_OK$3; - } - beg = 0; - } - // JS specific: little magic to add zero terminator to end of string - if (s.gzindex < s.gzhead.comment.length) { - val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); - //--- HCRC_UPDATE(beg) ---// - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); - } - //---// - } - s.status = HCRC_STATE; - } - if (s.status === HCRC_STATE) { - if (s.gzhead.hcrc) { - if (s.pending + 2 > s.pending_buf_size) { - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return Z_OK$3; - } - } - put_byte(s, strm.adler & 0xff); - put_byte(s, (strm.adler >> 8) & 0xff); - strm.adler = 0; //crc32(0L, Z_NULL, 0); - } - s.status = BUSY_STATE; - - /* Compression must start with an empty pending buffer */ - flush_pending(strm); - if (s.pending !== 0) { - s.last_flush = -1; - return Z_OK$3; - } - } -//#endif - - /* Start a new block or continue the current one. - */ - if (strm.avail_in !== 0 || s.lookahead !== 0 || - (flush !== Z_NO_FLUSH$2 && s.status !== FINISH_STATE)) { - let bstate = s.level === 0 ? deflate_stored(s, flush) : - s.strategy === Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : - s.strategy === Z_RLE ? deflate_rle(s, flush) : - configuration_table[s.level].func(s, flush); - - if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { - s.status = FINISH_STATE; - } - if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { - if (strm.avail_out === 0) { - s.last_flush = -1; - /* avoid BUF_ERROR next call, see above */ - } - return Z_OK$3; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate === BS_BLOCK_DONE) { - if (flush === Z_PARTIAL_FLUSH) { - _tr_align(s); - } - else if (flush !== Z_BLOCK$1) { /* FULL_FLUSH or SYNC_FLUSH */ - - _tr_stored_block(s, 0, 0, false); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush === Z_FULL_FLUSH$1) { - /*** CLEAR_HASH(s); ***/ /* forget history */ - zero(s.head); // Fill with NIL (= 0); - - if (s.lookahead === 0) { - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - } - } - flush_pending(strm); - if (strm.avail_out === 0) { - s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK$3; - } - } - } - - if (flush !== Z_FINISH$3) { return Z_OK$3; } - if (s.wrap <= 0) { return Z_STREAM_END$3; } - - /* Write the trailer */ - if (s.wrap === 2) { - put_byte(s, strm.adler & 0xff); - put_byte(s, (strm.adler >> 8) & 0xff); - put_byte(s, (strm.adler >> 16) & 0xff); - put_byte(s, (strm.adler >> 24) & 0xff); - put_byte(s, strm.total_in & 0xff); - put_byte(s, (strm.total_in >> 8) & 0xff); - put_byte(s, (strm.total_in >> 16) & 0xff); - put_byte(s, (strm.total_in >> 24) & 0xff); - } - else - { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 0xffff); - } - - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s.wrap > 0) { s.wrap = -s.wrap; } - /* write the trailer only once! */ - return s.pending !== 0 ? Z_OK$3 : Z_STREAM_END$3; -}; - - -const deflateEnd = (strm) => { - - if (deflateStateCheck(strm)) { - return Z_STREAM_ERROR$2; - } - - const status = strm.state.status; - - strm.state = null; - - return status === BUSY_STATE ? err(strm, Z_DATA_ERROR$2) : Z_OK$3; -}; - - -/* ========================================================================= - * Initializes the compression dictionary from the given byte - * sequence without producing any compressed output. - */ -const deflateSetDictionary = (strm, dictionary) => { - - let dictLength = dictionary.length; - - if (deflateStateCheck(strm)) { - return Z_STREAM_ERROR$2; - } - - const s = strm.state; - const wrap = s.wrap; - - if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) { - return Z_STREAM_ERROR$2; - } - - /* when using zlib wrappers, compute Adler-32 for provided dictionary */ - if (wrap === 1) { - /* adler32(strm->adler, dictionary, dictLength); */ - strm.adler = adler32_1(strm.adler, dictionary, dictLength, 0); - } - - s.wrap = 0; /* avoid computing Adler-32 in read_buf */ - - /* if dictionary would fill window, just replace the history */ - if (dictLength >= s.w_size) { - if (wrap === 0) { /* already empty otherwise */ - /*** CLEAR_HASH(s); ***/ - zero(s.head); // Fill with NIL (= 0); - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - /* use the tail */ - // dictionary = dictionary.slice(dictLength - s.w_size); - let tmpDict = new Uint8Array(s.w_size); - tmpDict.set(dictionary.subarray(dictLength - s.w_size, dictLength), 0); - dictionary = tmpDict; - dictLength = s.w_size; - } - /* insert dictionary into window and hash */ - const avail = strm.avail_in; - const next = strm.next_in; - const input = strm.input; - strm.avail_in = dictLength; - strm.next_in = 0; - strm.input = dictionary; - fill_window(s); - while (s.lookahead >= MIN_MATCH) { - let str = s.strstart; - let n = s.lookahead - (MIN_MATCH - 1); - do { - /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ - s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]); - - s.prev[str & s.w_mask] = s.head[s.ins_h]; - - s.head[s.ins_h] = str; - str++; - } while (--n); - s.strstart = str; - s.lookahead = MIN_MATCH - 1; - fill_window(s); - } - s.strstart += s.lookahead; - s.block_start = s.strstart; - s.insert = s.lookahead; - s.lookahead = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - strm.next_in = next; - strm.input = input; - strm.avail_in = avail; - s.wrap = wrap; - return Z_OK$3; -}; - - -var deflateInit_1 = deflateInit; -var deflateInit2_1 = deflateInit2; -var deflateReset_1 = deflateReset; -var deflateResetKeep_1 = deflateResetKeep; -var deflateSetHeader_1 = deflateSetHeader; -var deflate_2$1 = deflate$2; -var deflateEnd_1 = deflateEnd; -var deflateSetDictionary_1 = deflateSetDictionary; -var deflateInfo = 'pako deflate (from Nodeca project)'; - -/* Not implemented -module.exports.deflateBound = deflateBound; -module.exports.deflateCopy = deflateCopy; -module.exports.deflateGetDictionary = deflateGetDictionary; -module.exports.deflateParams = deflateParams; -module.exports.deflatePending = deflatePending; -module.exports.deflatePrime = deflatePrime; -module.exports.deflateTune = deflateTune; -*/ - -var deflate_1$2 = { - deflateInit: deflateInit_1, - deflateInit2: deflateInit2_1, - deflateReset: deflateReset_1, - deflateResetKeep: deflateResetKeep_1, - deflateSetHeader: deflateSetHeader_1, - deflate: deflate_2$1, - deflateEnd: deflateEnd_1, - deflateSetDictionary: deflateSetDictionary_1, - deflateInfo: deflateInfo -}; - -const _has = (obj, key) => { - return Object.prototype.hasOwnProperty.call(obj, key); -}; - -var assign = function (obj /*from1, from2, from3, ...*/) { - const sources = Array.prototype.slice.call(arguments, 1); - while (sources.length) { - const source = sources.shift(); - if (!source) { continue; } - - if (typeof source !== 'object') { - throw new TypeError(source + 'must be non-object'); - } - - for (const p in source) { - if (_has(source, p)) { - obj[p] = source[p]; - } - } - } - - return obj; -}; - - -// Join array of chunks to single array. -var flattenChunks = (chunks) => { - // calculate data length - let len = 0; - - for (let i = 0, l = chunks.length; i < l; i++) { - len += chunks[i].length; - } - - // join chunks - const result = new Uint8Array(len); - - for (let i = 0, pos = 0, l = chunks.length; i < l; i++) { - let chunk = chunks[i]; - result.set(chunk, pos); - pos += chunk.length; - } - - return result; -}; - -var common = { - assign: assign, - flattenChunks: flattenChunks -}; - -// String encode/decode helpers - - -// Quick check if we can use fast array to bin string conversion -// -// - apply(Array) can fail on Android 2.2 -// - apply(Uint8Array) can fail on iOS 5.1 Safari -// -let STR_APPLY_UIA_OK = true; - -try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; } - - -// Table with utf8 lengths (calculated by first byte of sequence) -// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, -// because max possible codepoint is 0x10ffff -const _utf8len = new Uint8Array(256); -for (let q = 0; q < 256; q++) { - _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1); -} -_utf8len[254] = _utf8len[254] = 1; // Invalid sequence start - - -// convert string to array (typed, when possible) -var string2buf = (str) => { - if (typeof TextEncoder === 'function' && TextEncoder.prototype.encode) { - return new TextEncoder().encode(str); - } - - let buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; - - // count binary size - for (m_pos = 0; m_pos < str_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { - c2 = str.charCodeAt(m_pos + 1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; - } - - // allocate buffer - buf = new Uint8Array(buf_len); - - // convert - for (i = 0, m_pos = 0; i < buf_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { - c2 = str.charCodeAt(m_pos + 1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - if (c < 0x80) { - /* one byte */ - buf[i++] = c; - } else if (c < 0x800) { - /* two bytes */ - buf[i++] = 0xC0 | (c >>> 6); - buf[i++] = 0x80 | (c & 0x3f); - } else if (c < 0x10000) { - /* three bytes */ - buf[i++] = 0xE0 | (c >>> 12); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } else { - /* four bytes */ - buf[i++] = 0xf0 | (c >>> 18); - buf[i++] = 0x80 | (c >>> 12 & 0x3f); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } - } - - return buf; -}; - -// Helper -const buf2binstring = (buf, len) => { - // On Chrome, the arguments in a function call that are allowed is `65534`. - // If the length of the buffer is smaller than that, we can use this optimization, - // otherwise we will take a slower path. - if (len < 65534) { - if (buf.subarray && STR_APPLY_UIA_OK) { - return String.fromCharCode.apply(null, buf.length === len ? buf : buf.subarray(0, len)); - } - } - - let result = ''; - for (let i = 0; i < len; i++) { - result += String.fromCharCode(buf[i]); - } - return result; -}; - - -// convert array to string -var buf2string = (buf, max) => { - const len = max || buf.length; - - if (typeof TextDecoder === 'function' && TextDecoder.prototype.decode) { - return new TextDecoder().decode(buf.subarray(0, max)); - } - - let i, out; - - // Reserve max possible length (2 words per char) - // NB: by unknown reasons, Array is significantly faster for - // String.fromCharCode.apply than Uint16Array. - const utf16buf = new Array(len * 2); - - for (out = 0, i = 0; i < len;) { - let c = buf[i++]; - // quick process ascii - if (c < 0x80) { utf16buf[out++] = c; continue; } - - let c_len = _utf8len[c]; - // skip 5 & 6 byte codes - if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; } - - // apply mask on first byte - c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; - // join the rest - while (c_len > 1 && i < len) { - c = (c << 6) | (buf[i++] & 0x3f); - c_len--; - } - - // terminated by end of string? - if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } - - if (c < 0x10000) { - utf16buf[out++] = c; - } else { - c -= 0x10000; - utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); - utf16buf[out++] = 0xdc00 | (c & 0x3ff); - } - } - - return buf2binstring(utf16buf, out); -}; - - -// Calculate max possible position in utf8 buffer, -// that will not break sequence. If that's not possible -// - (very small limits) return max size as is. -// -// buf[] - utf8 bytes array -// max - length limit (mandatory); -var utf8border = (buf, max) => { - - max = max || buf.length; - if (max > buf.length) { max = buf.length; } - - // go back from last position, until start of sequence found - let pos = max - 1; - while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } - - // Very small and broken sequence, - // return max, because we should return something anyway. - if (pos < 0) { return max; } - - // If we came to start of buffer - that means buffer is too small, - // return max too. - if (pos === 0) { return max; } - - return (pos + _utf8len[buf[pos]] > max) ? pos : max; -}; - -var strings = { - string2buf: string2buf, - buf2string: buf2string, - utf8border: utf8border -}; - -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -function ZStream() { - /* next input byte */ - this.input = null; // JS specific, because we have no pointers - this.next_in = 0; - /* number of bytes available at input */ - this.avail_in = 0; - /* total number of input bytes read so far */ - this.total_in = 0; - /* next output byte should be put there */ - this.output = null; // JS specific, because we have no pointers - this.next_out = 0; - /* remaining free space at output */ - this.avail_out = 0; - /* total number of bytes output so far */ - this.total_out = 0; - /* last error message, NULL if no error */ - this.msg = ''/*Z_NULL*/; - /* not visible by applications */ - this.state = null; - /* best guess about the data type: binary or text */ - this.data_type = 2/*Z_UNKNOWN*/; - /* adler32 value of the uncompressed data */ - this.adler = 0; -} - -var zstream = ZStream; - -const toString$1 = Object.prototype.toString; - -/* Public constants ==========================================================*/ -/* ===========================================================================*/ - -const { - Z_NO_FLUSH: Z_NO_FLUSH$1, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH: Z_FINISH$2, - Z_OK: Z_OK$2, Z_STREAM_END: Z_STREAM_END$2, - Z_DEFAULT_COMPRESSION, - Z_DEFAULT_STRATEGY, - Z_DEFLATED: Z_DEFLATED$1 -} = constants$2; - -/* ===========================================================================*/ - - -/** - * class Deflate - * - * Generic JS-style wrapper for zlib calls. If you don't need - * streaming behaviour - use more simple functions: [[deflate]], - * [[deflateRaw]] and [[gzip]]. - **/ - -/* internal - * Deflate.chunks -> Array - * - * Chunks of output data, if [[Deflate#onData]] not overridden. - **/ - -/** - * Deflate.result -> Uint8Array - * - * Compressed result, generated by default [[Deflate#onData]] - * and [[Deflate#onEnd]] handlers. Filled after you push last chunk - * (call [[Deflate#push]] with `Z_FINISH` / `true` param). - **/ - -/** - * Deflate.err -> Number - * - * Error code after deflate finished. 0 (Z_OK) on success. - * You will not need it in real life, because deflate errors - * are possible only on wrong options or bad `onData` / `onEnd` - * custom handlers. - **/ - -/** - * Deflate.msg -> String - * - * Error message, if [[Deflate.err]] != 0 - **/ - - -/** - * new Deflate(options) - * - options (Object): zlib deflate options. - * - * Creates new deflator instance with specified params. Throws exception - * on bad params. Supported options: - * - * - `level` - * - `windowBits` - * - `memLevel` - * - `strategy` - * - `dictionary` - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * Additional options, for internal needs: - * - * - `chunkSize` - size of generated data chunks (16K by default) - * - `raw` (Boolean) - do raw deflate - * - `gzip` (Boolean) - create gzip wrapper - * - `header` (Object) - custom header for gzip - * - `text` (Boolean) - true if compressed data believed to be text - * - `time` (Number) - modification time, unix timestamp - * - `os` (Number) - operation system code - * - `extra` (Array) - array of bytes with extra data (max 65536) - * - `name` (String) - file name (binary string) - * - `comment` (String) - comment (binary string) - * - `hcrc` (Boolean) - true if header crc should be added - * - * ##### Example: - * - * ```javascript - * const pako = require('pako') - * , chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9]) - * , chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]); - * - * const deflate = new pako.Deflate({ level: 3}); - * - * deflate.push(chunk1, false); - * deflate.push(chunk2, true); // true -> last chunk - * - * if (deflate.err) { throw new Error(deflate.err); } - * - * console.log(deflate.result); - * ``` - **/ -function Deflate$1(options) { - this.options = common.assign({ - level: Z_DEFAULT_COMPRESSION, - method: Z_DEFLATED$1, - chunkSize: 16384, - windowBits: 15, - memLevel: 8, - strategy: Z_DEFAULT_STRATEGY - }, options || {}); - - let opt = this.options; - - if (opt.raw && (opt.windowBits > 0)) { - opt.windowBits = -opt.windowBits; - } - - else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) { - opt.windowBits += 16; - } - - this.err = 0; // error code, if happens (0 = Z_OK) - this.msg = ''; // error message - this.ended = false; // used to avoid multiple onEnd() calls - this.chunks = []; // chunks of compressed data - - this.strm = new zstream(); - this.strm.avail_out = 0; - - let status = deflate_1$2.deflateInit2( - this.strm, - opt.level, - opt.method, - opt.windowBits, - opt.memLevel, - opt.strategy - ); - - if (status !== Z_OK$2) { - throw new Error(messages[status]); - } - - if (opt.header) { - deflate_1$2.deflateSetHeader(this.strm, opt.header); - } - - if (opt.dictionary) { - let dict; - // Convert data if needed - if (typeof opt.dictionary === 'string') { - // If we need to compress text, change encoding to utf8. - dict = strings.string2buf(opt.dictionary); - } else if (toString$1.call(opt.dictionary) === '[object ArrayBuffer]') { - dict = new Uint8Array(opt.dictionary); - } else { - dict = opt.dictionary; - } - - status = deflate_1$2.deflateSetDictionary(this.strm, dict); - - if (status !== Z_OK$2) { - throw new Error(messages[status]); - } - - this._dict_set = true; - } -} - -/** - * Deflate#push(data[, flush_mode]) -> Boolean - * - data (Uint8Array|ArrayBuffer|String): input data. Strings will be - * converted to utf8 byte sequence. - * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. - * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. - * - * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with - * new compressed chunks. Returns `true` on success. The last data block must - * have `flush_mode` Z_FINISH (or `true`). That will flush internal pending - * buffers and call [[Deflate#onEnd]]. - * - * On fail call [[Deflate#onEnd]] with error code and return false. - * - * ##### Example - * - * ```javascript - * push(chunk, false); // push one of data chunks - * ... - * push(chunk, true); // push last chunk - * ``` - **/ -Deflate$1.prototype.push = function (data, flush_mode) { - const strm = this.strm; - const chunkSize = this.options.chunkSize; - let status, _flush_mode; - - if (this.ended) { return false; } - - if (flush_mode === ~~flush_mode) _flush_mode = flush_mode; - else _flush_mode = flush_mode === true ? Z_FINISH$2 : Z_NO_FLUSH$1; - - // Convert data if needed - if (typeof data === 'string') { - // If we need to compress text, change encoding to utf8. - strm.input = strings.string2buf(data); - } else if (toString$1.call(data) === '[object ArrayBuffer]') { - strm.input = new Uint8Array(data); - } else { - strm.input = data; - } - - strm.next_in = 0; - strm.avail_in = strm.input.length; - - for (;;) { - if (strm.avail_out === 0) { - strm.output = new Uint8Array(chunkSize); - strm.next_out = 0; - strm.avail_out = chunkSize; - } - - // Make sure avail_out > 6 to avoid repeating markers - if ((_flush_mode === Z_SYNC_FLUSH || _flush_mode === Z_FULL_FLUSH) && strm.avail_out <= 6) { - this.onData(strm.output.subarray(0, strm.next_out)); - strm.avail_out = 0; - continue; - } - - status = deflate_1$2.deflate(strm, _flush_mode); - - // Ended => flush and finish - if (status === Z_STREAM_END$2) { - if (strm.next_out > 0) { - this.onData(strm.output.subarray(0, strm.next_out)); - } - status = deflate_1$2.deflateEnd(this.strm); - this.onEnd(status); - this.ended = true; - return status === Z_OK$2; - } - - // Flush if out buffer full - if (strm.avail_out === 0) { - this.onData(strm.output); - continue; - } - - // Flush if requested and has data - if (_flush_mode > 0 && strm.next_out > 0) { - this.onData(strm.output.subarray(0, strm.next_out)); - strm.avail_out = 0; - continue; - } - - if (strm.avail_in === 0) break; - } - - return true; -}; - - -/** - * Deflate#onData(chunk) -> Void - * - chunk (Uint8Array): output data. - * - * By default, stores data blocks in `chunks[]` property and glue - * those in `onEnd`. Override this handler, if you need another behaviour. - **/ -Deflate$1.prototype.onData = function (chunk) { - this.chunks.push(chunk); -}; - - -/** - * Deflate#onEnd(status) -> Void - * - status (Number): deflate status. 0 (Z_OK) on success, - * other if not. - * - * Called once after you tell deflate that the input stream is - * complete (Z_FINISH). By default - join collected chunks, - * free memory and fill `results` / `err` properties. - **/ -Deflate$1.prototype.onEnd = function (status) { - // On success - join - if (status === Z_OK$2) { - this.result = common.flattenChunks(this.chunks); - } - this.chunks = []; - this.err = status; - this.msg = this.strm.msg; -}; - - -/** - * deflate(data[, options]) -> Uint8Array - * - data (Uint8Array|ArrayBuffer|String): input data to compress. - * - options (Object): zlib deflate options. - * - * Compress `data` with deflate algorithm and `options`. - * - * Supported options are: - * - * - level - * - windowBits - * - memLevel - * - strategy - * - dictionary - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * Sugar (options): - * - * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify - * negative windowBits implicitly. - * - * ##### Example: - * - * ```javascript - * const pako = require('pako') - * const data = new Uint8Array([1,2,3,4,5,6,7,8,9]); - * - * console.log(pako.deflate(data)); - * ``` - **/ -function deflate$1(input, options) { - const deflator = new Deflate$1(options); - - deflator.push(input, true); - - // That will never happens, if you don't cheat with options :) - if (deflator.err) { throw deflator.msg || messages[deflator.err]; } - - return deflator.result; -} -var deflate_2 = deflate$1; - -var deflate_1$1 = { - deflate: deflate_2}; - -const { deflate} = deflate_1$1; -var deflate_1 = deflate; - -const lut = { - b: { u: DataView.prototype.getInt8, p: DataView.prototype.setInt8, bytes: 1 }, - B: { - u: DataView.prototype.getUint8, - p: DataView.prototype.setUint8, - bytes: 1, - }, - h: { - u: DataView.prototype.getInt16, - p: DataView.prototype.setInt16, - bytes: 2, - }, - H: { - u: DataView.prototype.getUint16, - p: DataView.prototype.setUint16, - bytes: 2, - }, - i: { - u: DataView.prototype.getInt32, - p: DataView.prototype.setInt32, - bytes: 4, - }, - I: { - u: DataView.prototype.getUint32, - p: DataView.prototype.setUint32, - bytes: 4, - }, -}; -const pack = (format, ...data) => { - let pointer = 0; - if (format.replace(/[<>]/, "").length != data.length) { - throw "Pack format to Argument count mismatch"; - } - const bytes = []; - let littleEndian = true; - for (let i = 0; i < format.length; i++) { - if (format[i] == "<") { - littleEndian = true; - } - else if (format[i] == ">") { - littleEndian = false; - } - else { - pushBytes(format[i], data[pointer]); - pointer++; - } - } - function pushBytes(formatChar, value) { - if (!(formatChar in lut)) { - throw "Unhandled character '" + formatChar + "' in pack format"; - } - const dataSize = lut[formatChar].bytes; - const view = new DataView(new ArrayBuffer(dataSize)); - const dataViewFn = lut[formatChar].p.bind(view); - dataViewFn(0, value, littleEndian); - for (let i = 0; i < dataSize; i++) { - bytes.push(view.getUint8(i)); - } - } - return bytes; -}; -const unpack = (format, bytes) => { - let pointer = 0; - const data = []; - let littleEndian = true; - for (const c of format) { - if (c == "<") { - littleEndian = true; - } - else if (c == ">") { - littleEndian = false; - } - else { - pushData(c); - } - } - function pushData(formatChar) { - if (!(formatChar in lut)) { - throw "Unhandled character '" + formatChar + "' in unpack format"; - } - const dataSize = lut[formatChar].bytes; - const view = new DataView(new ArrayBuffer(dataSize)); - for (let i = 0; i < dataSize; i++) { - view.setUint8(i, bytes[pointer + i] & 0xff); - } - const dataViewFn = lut[formatChar].u.bind(view); - data.push(dataViewFn(0, littleEndian)); - pointer += dataSize; - } - return data; -}; - -/// -class ESPLoader extends EventTarget { - /** - * Check if device is using USB-JTAG or USB-OTG (not external serial chip) - * Returns undefined if not yet determined - */ - get isUsbJtagOrOtg() { - return this._parent ? this._parent._isUsbJtagOrOtg : this._isUsbJtagOrOtg; - } - constructor(port, logger, _parent) { - super(); - this.port = port; - this.logger = logger; - this._parent = _parent; - this.__chipName = null; - this.__chipRevision = null; - this.__chipVariant = null; - this._efuses = new Array(4).fill(0); - this._flashsize = 4 * 1024 * 1024; - this.debug = false; - this.IS_STUB = false; - this.connected = true; - this.flashSize = null; - this.currentBaudRate = ESP_ROM_BAUD; - this.SLIP_END = 0xc0; - this.SLIP_ESC = 0xdb; - this.SLIP_ESC_END = 0xdc; - this.SLIP_ESC_ESC = 0xdd; - this._isESP32S2NativeUSB = false; - this._initializationSucceeded = false; - this.__commandLock = Promise.resolve([0, []]); - this.__isReconfiguring = false; - this.__abandonCurrentOperation = false; - this._suppressDisconnect = false; - this.__consoleMode = false; - this._isUsbJtagOrOtg = undefined; - // Adaptive speed adjustment for flash read operations - this.__adaptiveBlockMultiplier = 1; - this.__adaptiveMaxInFlightMultiplier = 1; - this.__consecutiveSuccessfulChunks = 0; - this.__lastAdaptiveAdjustment = 0; - this.__isCDCDevice = false; - this.state_DTR = false; - this.state_RTS = false; - this.__writeChain = Promise.resolve(); - } - // Chip properties with parent delegation - // chipFamily accessed before initialization as designed - get chipFamily() { - return this._parent ? this._parent.chipFamily : this.__chipFamily; - } - set chipFamily(value) { - if (this._parent) { - this._parent.chipFamily = value; - } - else { - this.__chipFamily = value; - } - } - get chipName() { - return this._parent ? this._parent.chipName : this.__chipName; - } - set chipName(value) { - if (this._parent) { - this._parent.chipName = value; - } - else { - this.__chipName = value; - } - } - get chipRevision() { - return this._parent ? this._parent.chipRevision : this.__chipRevision; - } - set chipRevision(value) { - if (this._parent) { - this._parent.chipRevision = value; - } - else { - this.__chipRevision = value; - } - } - get chipVariant() { - return this._parent ? this._parent.chipVariant : this.__chipVariant; - } - set chipVariant(value) { - if (this._parent) { - this._parent.chipVariant = value; - } - else { - this.__chipVariant = value; - } - } - // Console mode with parent delegation - get _consoleMode() { - return this._parent ? this._parent._consoleMode : this.__consoleMode; - } - set _consoleMode(value) { - if (this._parent) { - this._parent._consoleMode = value; - } - else { - this.__consoleMode = value; - } - } - // Public setter for console mode (used by script.js) - setConsoleMode(value) { - this._consoleMode = value; - } - get _inputBuffer() { - if (this._parent) { - return this._parent._inputBuffer; - } - if (this.__inputBuffer === undefined) { - throw new Error("_inputBuffer accessed before initialization"); - } - return this.__inputBuffer; - } - get _inputBufferReadIndex() { - return this._parent - ? this._parent._inputBufferReadIndex - : this.__inputBufferReadIndex || 0; - } - set _inputBufferReadIndex(value) { - if (this._parent) { - this._parent._inputBufferReadIndex = value; - } - else { - this.__inputBufferReadIndex = value; - } - } - // Get available bytes in buffer (from read index to end) - get _inputBufferAvailable() { - return this._inputBuffer.length - this._inputBufferReadIndex; - } - // Read one byte from buffer (ring-buffer style with index pointer) - _readByte() { - if (this._inputBufferReadIndex >= this._inputBuffer.length) { - return undefined; - } - return this._inputBuffer[this._inputBufferReadIndex++]; - } - // Clear input buffer and reset read index - _clearInputBuffer() { - this._inputBuffer.length = 0; - this._inputBufferReadIndex = 0; - } - // Compact buffer when read index gets too large (prevent memory growth) - _compactInputBuffer() { - if (this._inputBufferReadIndex > 1000 && - this._inputBufferReadIndex > this._inputBuffer.length / 2) { - // Remove already-read bytes and reset index - this._inputBuffer.splice(0, this._inputBufferReadIndex); - this._inputBufferReadIndex = 0; - } - } - get _totalBytesRead() { - return this._parent - ? this._parent._totalBytesRead - : this.__totalBytesRead || 0; - } - set _totalBytesRead(value) { - if (this._parent) { - this._parent._totalBytesRead = value; - } - else { - this.__totalBytesRead = value; - } - } - get _commandLock() { - return this._parent ? this._parent._commandLock : this.__commandLock; - } - set _commandLock(value) { - if (this._parent) { - this._parent._commandLock = value; - } - else { - this.__commandLock = value; - } - } - get _isReconfiguring() { - return this._parent - ? this._parent._isReconfiguring - : this.__isReconfiguring; - } - set _isReconfiguring(value) { - if (this._parent) { - this._parent._isReconfiguring = value; - } - else { - this.__isReconfiguring = value; - } - } - get _abandonCurrentOperation() { - return this._parent - ? this._parent._abandonCurrentOperation - : this.__abandonCurrentOperation; - } - set _abandonCurrentOperation(value) { - if (this._parent) { - this._parent._abandonCurrentOperation = value; - } - else { - this.__abandonCurrentOperation = value; - } - } - get _adaptiveBlockMultiplier() { - return this._parent - ? this._parent._adaptiveBlockMultiplier - : this.__adaptiveBlockMultiplier; - } - set _adaptiveBlockMultiplier(value) { - if (this._parent) { - this._parent._adaptiveBlockMultiplier = value; - } - else { - this.__adaptiveBlockMultiplier = value; - } - } - get _adaptiveMaxInFlightMultiplier() { - return this._parent - ? this._parent._adaptiveMaxInFlightMultiplier - : this.__adaptiveMaxInFlightMultiplier; - } - set _adaptiveMaxInFlightMultiplier(value) { - if (this._parent) { - this._parent._adaptiveMaxInFlightMultiplier = value; - } - else { - this.__adaptiveMaxInFlightMultiplier = value; - } - } - get _consecutiveSuccessfulChunks() { - return this._parent - ? this._parent._consecutiveSuccessfulChunks - : this.__consecutiveSuccessfulChunks; - } - set _consecutiveSuccessfulChunks(value) { - if (this._parent) { - this._parent._consecutiveSuccessfulChunks = value; - } - else { - this.__consecutiveSuccessfulChunks = value; - } - } - get _lastAdaptiveAdjustment() { - return this._parent - ? this._parent._lastAdaptiveAdjustment - : this.__lastAdaptiveAdjustment; - } - set _lastAdaptiveAdjustment(value) { - if (this._parent) { - this._parent._lastAdaptiveAdjustment = value; - } - else { - this.__lastAdaptiveAdjustment = value; - } - } - get _isCDCDevice() { - return this._parent ? this._parent._isCDCDevice : this.__isCDCDevice; - } - set _isCDCDevice(value) { - if (this._parent) { - this._parent._isCDCDevice = value; - } - else { - this.__isCDCDevice = value; - } - } - detectUSBSerialChip(vendorId, productId) { - // Common USB-Serial chip vendors and their products - const chips = { - 0x1a86: { - // QinHeng Electronics - 0x7522: { name: "CH340", maxBaudrate: 460800 }, - 0x7523: { name: "CH340", maxBaudrate: 460800 }, - 0x7584: { name: "CH340", maxBaudrate: 460800 }, - 0x5523: { name: "CH341", maxBaudrate: 2000000 }, - 0x55d3: { name: "CH343", maxBaudrate: 6000000 }, - 0x55d4: { name: "CH9102", maxBaudrate: 6000000 }, - 0x55d8: { name: "CH9101", maxBaudrate: 3000000 }, - }, - 0x10c4: { - // Silicon Labs - 0xea60: { name: "CP2102(n)", maxBaudrate: 3000000 }, - 0xea70: { name: "CP2105", maxBaudrate: 2000000 }, - 0xea71: { name: "CP2108", maxBaudrate: 2000000 }, - }, - 0x0403: { - // FTDI - 0x6001: { name: "FT232R", maxBaudrate: 3000000 }, - 0x6010: { name: "FT2232", maxBaudrate: 3000000 }, - 0x6011: { name: "FT4232", maxBaudrate: 3000000 }, - 0x6014: { name: "FT232H", maxBaudrate: 12000000 }, - 0x6015: { name: "FT230X", maxBaudrate: 3000000 }, - }, - 0x303a: { - // Espressif (native USB) - 0x2: { name: "ESP32-S2 Native USB", maxBaudrate: 2000000 }, - 0x12: { name: "ESP32-P4 Native USB", maxBaudrate: 2000000 }, - 0x1001: { name: "ESP32 Native USB", maxBaudrate: 2000000 }, - }, - }; - const vendor = chips[vendorId]; - if (vendor && vendor[productId]) { - return vendor[productId]; - } - return { - name: `Unknown (VID: 0x${vendorId.toString(16)}, PID: 0x${productId.toString(16)})`, - }; - } - async initialize() { - if (!this._parent) { - this.__inputBuffer = []; - this.__inputBufferReadIndex = 0; - this.__totalBytesRead = 0; - // Detect and log USB-Serial chip info - const portInfo = this.port.getInfo(); - if (portInfo.usbVendorId && portInfo.usbProductId) { - const chipInfo = this.detectUSBSerialChip(portInfo.usbVendorId, portInfo.usbProductId); - this.logger.log(`USB-Serial: ${chipInfo.name} (VID: 0x${portInfo.usbVendorId.toString(16)}, PID: 0x${portInfo.usbProductId.toString(16)})`); - if (chipInfo.maxBaudrate) { - this._maxUSBSerialBaudrate = chipInfo.maxBaudrate; - this.logger.log(`Max baudrate: ${chipInfo.maxBaudrate}`); - } - // Detect ESP32-S2 Native USB - if (portInfo.usbVendorId === 0x303a && portInfo.usbProductId === 0x2) { - this._isESP32S2NativeUSB = true; - } - // Detect CDC devices for adaptive speed adjustment - // Espressif Native USB (VID: 0x303a) or CH343 (VID: 0x1a86, PID: 0x55d3) - if (portInfo.usbVendorId === 0x303a || - (portInfo.usbVendorId === 0x1a86 && portInfo.usbProductId === 0x55d3)) { - this._isCDCDevice = true; - } - } - // Don't await this promise so it doesn't block rest of method. - this.readLoop(); - } - // Try to connect with different reset strategies - await this.connectWithResetStrategies(); - // Detect chip type - await this.detectChip(); - // Power on flash for ESP32-P4 Rev 301 (must be done before loading stub) - if (this.chipFamily === CHIP_FAMILY_ESP32P4 && this.chipRevision === 301) { - await this.powerOnFlash(); - } - // Detect if device is using USB-JTAG/Serial or USB-OTG (not external serial chip) - // This is needed to determine the correct reset strategy for console mode - try { - this._isUsbJtagOrOtg = await this.detectUsbConnectionType(); - this.logger.debug(`USB connection type: ${this._isUsbJtagOrOtg ? "USB-JTAG/OTG" : "External Serial Chip"}`); - } - catch (err) { - this.logger.debug(`Could not detect USB connection type: ${err}`); - } - try { - const usbMode = await this.getUsbMode(); - this.logger.debug(`USB mode (register): ${usbMode.mode} (uartNo=${usbMode.uartNo})`); - } - catch (err) { - this.logger.debug(`Could not detect USB mode: ${err}`); - } - // Read the OTP data for this chip and store into this.efuses array - const FlAddr = getSpiFlashAddresses(this.getChipFamily()); - const AddrMAC = FlAddr.macFuse; - for (let i = 0; i < 4; i++) { - this._efuses[i] = await this.readRegister(AddrMAC + 4 * i); - } - const revisionInfo = this.chipRevision !== null && this.chipRevision !== undefined - ? ` (revision ${this.chipRevision})` - : ""; - this.logger.log(`Connected to ${this.chipName}${revisionInfo}`); - this.logger.debug(`Bootloader flash offset: 0x${FlAddr.flashOffs.toString(16)}`); - // Mark initialization as successful - this._initializationSucceeded = true; - } - /** - * Detect chip type using GET_SECURITY_INFO (for newer chips) or magic value (for older chips) - */ - async detectChip() { - try { - // Try GET_SECURITY_INFO command first (ESP32-C3 and later) - const securityInfo = await this.getSecurityInfo(); - const chipId = securityInfo.chipId; - const chipInfo = CHIP_ID_TO_INFO[chipId]; - if (chipInfo) { - this.chipName = chipInfo.name; - this.chipFamily = chipInfo.family; - this.chipRevision = await this.getChipRevision(); - this.logger.debug(`${this.chipName} revision: ${this.chipRevision}`); - if (this.chipFamily === CHIP_FAMILY_ESP32P4 && - this.chipRevision >= 300) { - this.chipVariant = "rev300"; - } - else if (this.chipFamily === CHIP_FAMILY_ESP32P4) { - this.chipVariant = "rev0"; - } - this.logger.debug(`Detected chip via IMAGE_CHIP_ID: ${chipId} (${this.chipName})`); - return; - } - this.logger.debug(`Unknown IMAGE_CHIP_ID: ${chipId}, falling back to magic value detection`); - } - catch (error) { - // GET_SECURITY_INFO not supported, fall back to magic value detection - this.logger.debug(`GET_SECURITY_INFO failed, using magic value detection: ${error}`); - // Drain input buffer for CP210x compatibility on Windows - // This ensures all error responses are cleared before continuing - await this.drainInputBuffer(200); - // Clear input buffer and re-sync to recover from failed command - this._clearInputBuffer(); - await sleep(SYNC_TIMEOUT); - // Re-sync with the chip to ensure clean communication - try { - await this.sync(); - } - catch (syncErr) { - this.logger.debug(`Re-sync after GET_SECURITY_INFO failure: ${syncErr}`); - } - } - // Fallback: Use magic value detection for ESP8266, ESP32, ESP32-S2 - const chipMagicValue = await this.readRegister(CHIP_DETECT_MAGIC_REG_ADDR); - const chip = CHIP_DETECT_MAGIC_VALUES[chipMagicValue >>> 0]; - if (chip === undefined) { - throw new Error(`Unknown Chip: Hex: ${toHex(chipMagicValue >>> 0, 8).toLowerCase()} Number: ${chipMagicValue}`); - } - this.chipName = chip.name; - this.chipFamily = chip.family; - this.chipRevision = await this.getChipRevision(); - this.logger.debug(`${this.chipName} revision: ${this.chipRevision}`); - if (this.chipFamily === CHIP_FAMILY_ESP32P4) { - this.chipVariant = this.chipRevision >= 300 ? "rev300" : "rev0"; - this.logger.debug(`ESP32-P4 variant: ${this.chipVariant}`); - } - this.logger.debug(`Detected chip via magic value: ${toHex(chipMagicValue >>> 0, 8)} (${this.chipName})`); - } - async getChipRevision() { - var _a; - let minor = 0; - let major = 0; - switch (this.chipFamily) { - case CHIP_FAMILY_ESP32: { - const efuse3 = await this.readRegister(ESP32_BASEFUSEADDR + 4 * 3); - const efuse5 = await this.readRegister(ESP32_BASEFUSEADDR + 4 * 5); - minor = (efuse5 >> 24) & 0x3; - const revBit0 = (efuse3 >> 15) & 0x1; - const revBit1 = (efuse5 >> 20) & 0x1; - const apb = await this.readRegister(ESP32_APB_CTL_DATE_ADDR); - const revBit2 = (apb >> 31) & 0x1; - const combined = (revBit2 << 2) | (revBit1 << 1) | revBit0; - major = - (_a = { 0: 0, 1: 1, 3: 2, 7: 3 }[combined]) !== null && _a !== void 0 ? _a : 0; - break; - } - case CHIP_FAMILY_ESP32S2: { - const w3 = await this.readRegister(ESP32S2_EFUSE_BLOCK1_ADDR + 4 * 3); - const w4 = await this.readRegister(ESP32S2_EFUSE_BLOCK1_ADDR + 4 * 4); - const hi = (w3 >> 20) & 0x01; - const lo = (w4 >> 4) & 0x07; - minor = (hi << 3) + lo; - major = (w3 >> 18) & 0x03; - break; - } - case CHIP_FAMILY_ESP32S3: { - const w3 = await this.readRegister(ESP32S3_EFUSE_BLOCK1_ADDR + 4 * 3); - const w5 = await this.readRegister(ESP32S3_EFUSE_BLOCK1_ADDR + 4 * 5); - const hi = (w5 >> 23) & 0x01; - const lo = (w3 >> 18) & 0x07; - minor = (hi << 3) + lo; - major = (w5 >> 24) & 0x03; - break; - } - case CHIP_FAMILY_ESP32C2: { - const w1 = await this.readRegister(ESP32C2_EFUSE_BLOCK2_ADDR + 4 * 1); - minor = (w1 >> 16) & 0x0f; - major = (w1 >> 20) & 0x03; - break; - } - case CHIP_FAMILY_ESP32C3: { - const w3 = await this.readRegister(ESP32C3_EFUSE_RD_MAC_SPI_SYS_3_REG); - const w5 = await this.readRegister(ESP32C3_EFUSE_RD_MAC_SPI_SYS_5_REG); - const hi = (w5 >> 23) & 0x01; - const lo = (w3 >> 18) & 0x07; - minor = (hi << 3) + lo; - major = (w5 >> 24) & 0x03; - break; - } - case CHIP_FAMILY_ESP32C5: { - const w2 = await this.readRegister(ESP32C5_EFUSE_BLOCK1_ADDR + 4 * 2); - minor = w2 & 0x0f; - major = (w2 >> 4) & 0x03; - break; - } - case CHIP_FAMILY_ESP32C6: { - const w3 = await this.readRegister(ESP32C6_EFUSE_BLOCK1_ADDR + 4 * 3); - minor = (w3 >> 18) & 0x0f; - major = (w3 >> 22) & 0x03; - break; - } - case CHIP_FAMILY_ESP32C61: { - const w2 = await this.readRegister(ESP32C61_EFUSE_BLOCK1_ADDR + 4 * 2); - minor = w2 & 0x0f; - major = (w2 >> 4) & 0x03; - break; - } - case CHIP_FAMILY_ESP32H2: { - const w3 = await this.readRegister(ESP32H2_EFUSE_BLOCK1_ADDR + 4 * 3); - minor = (w3 >> 18) & 0x07; - major = (w3 >> 21) & 0x03; - break; - } - case CHIP_FAMILY_ESP32H4: { - break; - } - case CHIP_FAMILY_ESP32H21: { - break; - } - case CHIP_FAMILY_ESP32P4: { - const w2 = await this.readRegister(ESP32P4_EFUSE_BLOCK1_ADDR + 4 * 2); - minor = w2 & 0x0f; - major = (((w2 >> 23) & 1) << 2) | ((w2 >> 4) & 0x03); - break; - } - case CHIP_FAMILY_ESP32S31: { - const w2 = await this.readRegister(ESP32S31_EFUSE_BLOCK1_ADDR + 4 * 2); - minor = w2 & 0x0f; - major = (w2 >> 4) & 0x03; - break; - } - } - return major * 100 + minor; - } - /** - * Power on the flash chip for ESP32-P4 Rev 301 (ECO6) - * The flash chip is powered off by default on ECO6, when the default flash - * voltage changed from 1.8V to 3.3V. This is to prevent damage to 1.8V flash chips. - */ - async powerOnFlash() { - if (this.chipFamily !== CHIP_FAMILY_ESP32P4) { - return; // Only needed for ESP32-P4 - } - if (this.chipRevision !== 301) { - return; // Only needed for Rev 301 (ECO6) - } - this.logger.debug("Powering on flash for ESP32-P4 Rev 301 (ECO6)"); - // Power up pad group - await this.writeRegister(ESP32P4_LP_SYSTEM_REG_ANA_XPD_PAD_GROUP_REG, 1); - await sleep(10); // 0.01 seconds - // Flash power up sequence - const pmuAnaReg = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG); - await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG, pmuAnaReg | ESP32P4_PMU_ANA_0P1A_EN_CUR_LIM_0); - const pmuReg = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG); - await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG, pmuReg | ESP32P4_PMU_0P1A_FORCE_TIEH_SEL_0); - const pmuDateReg = await this.readRegister(ESP32P4_PMU_DATE_REG); - await this.writeRegister(ESP32P4_PMU_DATE_REG, pmuDateReg | (3 << 0)); - await sleep(0.05); // 0.00005 seconds = 0.05 ms - const pmuAnaReg2 = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG); - await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG, pmuAnaReg2 & ~ESP32P4_PMU_ANA_0P1A_EN_CUR_LIM_0); - const pmuReg2 = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG); - await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG, pmuReg2 & -2139095041); - // Update eFuse voltage to PMU - const pmuReg3 = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG); - await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG, pmuReg3 | 0x80); - const pmuReg4 = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG); - await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG, pmuReg4 & ~ESP32P4_PMU_0P1A_FORCE_TIEH_SEL_0); - await sleep(2); // 0.0018 seconds = 1.8 ms, rounded to 2ms - this.logger.debug("Flash powered on successfully"); - } - /** - * Get security info including chip ID (ESP32-C3 and later) - */ - async getSecurityInfo() { - const [, responseData] = await this.checkCommand(ESP_GET_SECURITY_INFO, [], 0); - // Some chips/ROM versions return empty response or don't support this command - if (responseData.length === 0) { - throw new Error(`GET_SECURITY_INFO not supported or returned empty response`); - } - if (responseData.length < 12) { - throw new Error(`Invalid security info response length: ${responseData.length} (expected at least 12 bytes)`); - } - const flags = unpack("= 16 - ? unpack("= 20 - ? unpack(" b.toString(16).padStart(2, "0").toUpperCase()) - .join(":"); - } - /** - * @name readLoop - * Reads data from the input stream and places it in the inputBuffer - */ - async readLoop() { - if (this.debug) { - this.logger.debug("Starting read loop"); - } - this._reader = this.port.readable.getReader(); - try { - let keepReading = true; - while (keepReading) { - const { value, done } = await this._reader.read(); - if (done) { - this._reader.releaseLock(); - keepReading = false; - break; - } - if (!value || value.length === 0) { - continue; - } - // Always read from browser's serial buffer immediately - // to prevent browser buffer overflow. Don't apply back-pressure here. - const chunk = Array.from(value); - Array.prototype.push.apply(this._inputBuffer, chunk); - // Track total bytes read from serial port - this._totalBytesRead += value.length; - } - } - catch { - // this.logger.error("Read loop got disconnected"); - } - finally { - // Always reset reconfiguring flag when read loop ends - // This prevents "Cannot write during port reconfiguration" errors - // when the read loop dies unexpectedly - this._isReconfiguring = false; - // Release reader if still locked - if (this._reader) { - try { - this._reader.releaseLock(); - this.logger.debug("Reader released in readLoop cleanup"); - } - catch (err) { - this.logger.debug(`Reader release error in readLoop: ${err}`); - } - this._reader = undefined; - } - } - // Disconnected! - this.connected = false; - // Check if this is ESP32-S2 Native USB that needs port reselection - // Only trigger reconnect if initialization did NOT succeed (wrong port) - if (this._isESP32S2NativeUSB && !this._initializationSucceeded) { - this.logger.log("ESP32-S2 Native USB detected - requesting port reselection"); - this.dispatchEvent(new CustomEvent("esp32s2-usb-reconnect", { - detail: { message: "ESP32-S2 Native USB requires port reselection" }, - })); - } - // Only dispatch disconnect event if not suppressed - if (!this._suppressDisconnect) { - this.dispatchEvent(new Event("disconnect")); - } - this._suppressDisconnect = false; - this.logger.debug("Finished read loop"); - } - // ============================================================================ - // Web Serial (Desktop) - DTR/RTS Signal Handling & Reset Strategies - // ============================================================================ - async setRTS(state) { - await this.port.setSignals({ requestToSend: state }); - // Work-around for adapters on Windows using the usbser.sys driver: - // generate a dummy change to DTR so that the set-control-line-state - // request is sent with the updated RTS state and the same DTR state - // Referenced to esptool.py - await this.setDTR(this.state_DTR); - } - async setDTR(state) { - this.state_DTR = state; - await this.port.setSignals({ dataTerminalReady: state }); - } - async setDTRandRTS(dtr, rts) { - this.state_DTR = dtr; - this.state_RTS = rts; - await this.port.setSignals({ - dataTerminalReady: dtr, - requestToSend: rts, - }); - } - async runSignalSequence(steps) { - const webusb = this.port.isWebUSB === true; - for (const step of steps) { - if (step.dtr !== undefined && step.rts !== undefined) { - if (webusb) { - await this.setDTRandRTSWebUSB(step.dtr, step.rts); - } - else { - await this.setDTRandRTS(step.dtr, step.rts); - } - } - else { - if (step.dtr !== undefined) { - if (webusb) { - await this.setDTRWebUSB(step.dtr); - } - else { - await this.setDTR(step.dtr); - } - } - if (step.rts !== undefined) { - if (webusb) { - await this.setRTSWebUSB(step.rts); - } - else { - await this.setRTS(step.rts); - } - } - } - if (step.delayMs) - await sleep(step.delayMs); - } - } - /** - * @name hardResetUSBJTAGSerial - * USB-JTAG/Serial reset for Web Serial (Desktop) - */ - async hardResetUSBJTAGSerial() { - await this.runSignalSequence([ - { rts: false }, - { dtr: false, delayMs: 100 }, - { dtr: true, rts: false, delayMs: 100 }, - { rts: true }, - { dtr: false, rts: true, delayMs: 100 }, - { dtr: false, rts: false, delayMs: 200 }, - ]); - } - /** - * @name hardResetClassic - * Classic reset for Web Serial (Desktop) DTR = IO0, RTS = EN - */ - async hardResetClassic() { - await this.runSignalSequence([ - { dtr: false, rts: true, delayMs: 100 }, - { dtr: true, rts: false, delayMs: 50 }, - { dtr: false, delayMs: 200 }, - ]); - } - /** - * Reset to firmware mode (not bootloader) for Web Serial - * Keeps IO0=HIGH during reset so chip boots into firmware - */ - async hardResetToFirmware() { - await this.runSignalSequence([ - { dtr: false, rts: true, delayMs: 100 }, - { rts: false, delayMs: 50 }, - { delayMs: 200 }, - ]); - } - /** - * @name hardResetUnixTight - * Unix Tight reset for Web Serial (Desktop) - sets DTR and RTS simultaneously - */ - async hardResetUnixTight() { - await this.runSignalSequence([ - { dtr: true, rts: true }, - { dtr: false, rts: false }, - { dtr: false, rts: true, delayMs: 100 }, - { dtr: true, rts: false, delayMs: 50 }, - { dtr: false, rts: false }, - { dtr: false, delayMs: 200 }, - ]); - } - // ============================================================================ - // WebUSB (Android) - DTR/RTS Signal Handling & Reset Strategies - // ============================================================================ - async setRTSWebUSB(state) { - this.state_RTS = state; - // Always specify both signals to avoid flipping the other line - // The WebUSB setSignals() now preserves unspecified signals, but being explicit is safer - await this.port.setSignals({ - requestToSend: state, - dataTerminalReady: this.state_DTR, - }); - } - async setDTRWebUSB(state) { - this.state_DTR = state; - // Always specify both signals to avoid flipping the other line - await this.port.setSignals({ - dataTerminalReady: state, - requestToSend: this.state_RTS, // Explicitly preserve current RTS state - }); - } - async setDTRandRTSWebUSB(dtr, rts) { - this.state_DTR = dtr; - this.state_RTS = rts; - await this.port.setSignals({ - dataTerminalReady: dtr, - requestToSend: rts, - }); - } - /** - * @name hardResetUSBJTAGSerialInvertedDTRWebUSB - * USB-JTAG/Serial reset with inverted DTR for WebUSB (Android) - */ - async hardResetUSBJTAGSerialInvertedDTRWebUSB() { - await this.runSignalSequence([ - { rts: false, dtr: true, delayMs: 100 }, - { dtr: false, rts: false, delayMs: 100 }, - { rts: true, dtr: true, delayMs: 100 }, - { dtr: true, rts: false, delayMs: 200 }, - ]); - } - /** - * @name hardResetClassicLongDelayWebUSB - * Classic reset with longer delays for WebUSB (Android) - * Specifically for CP2102/CH340 which may need more time - */ - async hardResetClassicLongDelayWebUSB() { - await this.runSignalSequence([ - { dtr: false, rts: true, delayMs: 500 }, - { dtr: true, rts: false, delayMs: 200 }, - { dtr: false, delayMs: 500 }, - ]); - } - /** - * @name hardResetClassicShortDelayWebUSB - * Classic reset with shorter delays for WebUSB (Android) - */ - async hardResetClassicShortDelayWebUSB() { - await this.runSignalSequence([ - { dtr: false, rts: true, delayMs: 50 }, - { dtr: true, rts: false, delayMs: 25 }, - { dtr: false, delayMs: 100 }, - ]); - } - /** - * @name hardResetInvertedWebUSB - * Inverted reset sequence for WebUSB (Android) - both signals inverted - */ - async hardResetInvertedWebUSB() { - await this.runSignalSequence([ - { dtr: true, rts: false, delayMs: 100 }, - { dtr: false, rts: true, delayMs: 50 }, - { dtr: true, delayMs: 200 }, - ]); - } - /** - * @name hardResetInvertedDTRWebUSB - * Only DTR inverted for WebUSB (Android) - */ - async hardResetInvertedDTRWebUSB() { - await this.runSignalSequence([ - { dtr: true, rts: true, delayMs: 100 }, - { dtr: false, rts: false, delayMs: 50 }, - { dtr: true, delayMs: 200 }, - ]); - } - /** - * @name hardResetInvertedRTSWebUSB - * Only RTS inverted for WebUSB (Android) - */ - async hardResetInvertedRTSWebUSB() { - await this.runSignalSequence([ - { dtr: false, rts: false, delayMs: 100 }, - { dtr: true, rts: true, delayMs: 50 }, - { dtr: false, delayMs: 200 }, - ]); - } - /** - * Check if we're using WebUSB (Android) or Web Serial (Desktop) - */ - isWebUSB() { - // WebUSBSerial class has isWebUSB flag - this is the most reliable check - return this.port.isWebUSB === true; - } - /** - * @name connectWithResetStrategies - * Try different reset strategies to enter bootloader mode - * Similar to esptool.py's connect() method with multiple reset strategies - */ - async connectWithResetStrategies() { - const portInfo = this.port.getInfo(); - const isUSBJTAGSerial = portInfo.usbProductId === USB_JTAG_SERIAL_PID; - const isEspressifUSB = portInfo.usbVendorId === 0x303a; - // this.logger.log( - // `Detected USB: VID=0x${portInfo.usbVendorId?.toString(16) || "unknown"}, PID=0x${portInfo.usbProductId?.toString(16) || "unknown"}`, - // ); - // Define reset strategies to try in order - const resetStrategies = []; - // eslint-disable-next-line @typescript-eslint/no-this-alias - const self = this; - // Detect if this is a USB-Serial chip (needs different sync approach) - const isUSBSerialChip = !isUSBJTAGSerial && !isEspressifUSB; - // WebUSB (Android) uses different reset methods than Web Serial (Desktop) - if (this.isWebUSB()) { - // For USB-Serial chips (CP2102, CH340, etc.), try inverted strategies first - // Detect specific chip types once - const isCP2102 = portInfo.usbVendorId === 0x10c4; - const isCH34x = portInfo.usbVendorId === 0x1a86; - // Check for ESP32-S2 Native USB (VID: 0x303a, PID: 0x0002) - const isESP32S2NativeUSB = portInfo.usbVendorId === 0x303a && portInfo.usbProductId === 0x0002; - // WebUSB Strategy 1: USB-JTAG/Serial reset (for Native USB only) - if (isUSBJTAGSerial || isEspressifUSB) { - if (isESP32S2NativeUSB) { - // ESP32-S2 Native USB: Try multiple strategies - // The device might be in JTAG mode OR CDC mode - // Strategy 1: USB-JTAG/Serial (works in CDC mode on Desktop) - resetStrategies.push({ - name: "USB-JTAG/Serial (WebUSB) - ESP32-S2", - fn: async () => { - return await self.hardResetUSBJTAGSerial(); - }, - }); - // Strategy 2: USB-JTAG/Serial Inverted DTR (works in JTAG mode) - resetStrategies.push({ - name: "USB-JTAG/Serial Inverted DTR (WebUSB) - ESP32-S2", - fn: async () => { - return await self.hardResetUSBJTAGSerialInvertedDTRWebUSB(); - }, - }); - // Strategy 3: UnixTight (CDC fallback) - resetStrategies.push({ - name: "UnixTight (WebUSB) - ESP32-S2 CDC", - fn: async () => { - return await self.hardResetUnixTight(); - }, - }); - // Strategy 4: Classic reset (CDC fallback) - resetStrategies.push({ - name: "Classic (WebUSB) - ESP32-S2 CDC", - fn: async () => { - return await self.hardResetClassic(); - }, - }); - } - else { - // Other USB-JTAG chips: Try Inverted DTR first - works best for ESP32-H2 and other JTAG chips - resetStrategies.push({ - name: "USB-JTAG/Serial Inverted DTR (WebUSB)", - fn: async () => { - return await self.hardResetUSBJTAGSerialInvertedDTRWebUSB(); - }, - }); - resetStrategies.push({ - name: "USB-JTAG/Serial (WebUSB)", - fn: async () => { - return await self.hardResetUSBJTAGSerial(); - }, - }); - resetStrategies.push({ - name: "Inverted DTR Classic (WebUSB)", - fn: async () => { - return await self.hardResetInvertedDTRWebUSB(); - }, - }); - } - } - // For USB-Serial chips, try inverted strategies first - if (isUSBSerialChip) { - if (isCH34x) { - // CH340/CH343: UnixTight works best (like CP2102) - resetStrategies.push({ - name: "UnixTight (WebUSB) - CH34x", - fn: async () => { - return await self.hardResetUnixTight(); - }, - }); - resetStrategies.push({ - name: "Classic (WebUSB) - CH34x", - fn: async () => { - return await self.hardResetClassic(); - }, - }); - resetStrategies.push({ - name: "Inverted Both (WebUSB) - CH34x", - fn: async () => { - return await self.hardResetInvertedWebUSB(); - }, - }); - resetStrategies.push({ - name: "Inverted RTS (WebUSB) - CH34x", - fn: async () => { - return await self.hardResetInvertedRTSWebUSB(); - }, - }); - resetStrategies.push({ - name: "Inverted DTR (WebUSB) - CH34x", - fn: async () => { - return await self.hardResetInvertedDTRWebUSB(); - }, - }); - } - else if (isCP2102) { - // CP2102: UnixTight works best (tested and confirmed) - // Try it first, then fallback to other strategies - resetStrategies.push({ - name: "UnixTight (WebUSB) - CP2102", - fn: async () => { - return await self.hardResetUnixTight(); - }, - }); - resetStrategies.push({ - name: "Classic (WebUSB) - CP2102", - fn: async () => { - return await self.hardResetClassic(); - }, - }); - resetStrategies.push({ - name: "Inverted Both (WebUSB) - CP2102", - fn: async () => { - return await self.hardResetInvertedWebUSB(); - }, - }); - resetStrategies.push({ - name: "Inverted RTS (WebUSB) - CP2102", - fn: async () => { - return await self.hardResetInvertedRTSWebUSB(); - }, - }); - resetStrategies.push({ - name: "Inverted DTR (WebUSB) - CP2102", - fn: async () => { - return await self.hardResetInvertedDTRWebUSB(); - }, - }); - } - else { - // For other USB-Serial chips, try UnixTight first, then multiple strategies - resetStrategies.push({ - name: "UnixTight (WebUSB)", - fn: async () => { - return await self.hardResetUnixTight(); - }, - }); - resetStrategies.push({ - name: "Classic (WebUSB)", - fn: async function () { - return await self.hardResetClassic(); - }, - }); - resetStrategies.push({ - name: "Inverted Both (WebUSB)", - fn: async function () { - return await self.hardResetInvertedWebUSB(); - }, - }); - resetStrategies.push({ - name: "Inverted RTS (WebUSB)", - fn: async function () { - return await self.hardResetInvertedRTSWebUSB(); - }, - }); - resetStrategies.push({ - name: "Inverted DTR (WebUSB)", - fn: async function () { - return await self.hardResetInvertedDTRWebUSB(); - }, - }); - } - } - // Add general fallback strategies only for Native USB chips (not USB-Serial) - // and only for chips not already handled by specific blocks above - if (!isUSBSerialChip && - !isCP2102 && - !isESP32S2NativeUSB && - !isUSBJTAGSerial) { - // Classic reset (for chips not handled above) - if (portInfo.usbVendorId !== 0x1a86) { - resetStrategies.push({ - name: "Classic (WebUSB)", - fn: async function () { - return await self.hardResetClassic(); - }, - }); - } - // UnixTight reset (sets DTR/RTS simultaneously) - resetStrategies.push({ - name: "UnixTight (WebUSB)", - fn: async function () { - return await self.hardResetUnixTight(); - }, - }); - // WebUSB Strategy: Classic with long delays - resetStrategies.push({ - name: "Classic Long Delay (WebUSB)", - fn: async function () { - return await self.hardResetClassicLongDelayWebUSB(); - }, - }); - // WebUSB Strategy: Classic with short delays - resetStrategies.push({ - name: "Classic Short Delay (WebUSB)", - fn: async function () { - return await self.hardResetClassicShortDelayWebUSB(); - }, - }); - // WebUSB Strategy: USB-JTAG/Serial fallback - if (!isEspressifUSB) { - resetStrategies.push({ - name: "USB-JTAG/Serial fallback (WebUSB)", - fn: async function () { - return await self.hardResetUSBJTAGSerial(); - }, - }); - } - } - } - else { - // Strategy: USB-JTAG/Serial reset - if (isUSBJTAGSerial || isEspressifUSB) { - resetStrategies.push({ - name: "USB-JTAG/Serial", - fn: async function () { - return await self.hardResetUSBJTAGSerial(); - }, - }); - } - // Strategy: UnixTight reset - resetStrategies.push({ - name: "UnixTight", - fn: async function () { - return await self.hardResetUnixTight(); - }, - }); - // Strategy: USB-JTAG/Serial fallback - if (!isUSBJTAGSerial && !isEspressifUSB) { - resetStrategies.push({ - name: "USB-JTAG/Serial (fallback)", - fn: async function () { - return await self.hardResetUSBJTAGSerial(); - }, - }); - } - } - let lastError = null; - // Try each reset strategy with timeout - for (const strategy of resetStrategies) { - try { - // Check if port is still open, if not, skip this strategy - if (!this.connected || !this.port.writable) { - this.logger.debug(`Port disconnected, skipping ${strategy.name} reset`); - continue; - } - // Clear abandon flag before starting new strategy - this._abandonCurrentOperation = false; - await strategy.fn(); - // Try to sync after reset - // USB-Serial / native USB chips needs different sync approaches - if (isUSBSerialChip) { - // USB-Serial chips: Use timeout strategy (2 seconds) - // this.logger.log(`USB-Serial chip detected, using sync with timeout.`); - const syncSuccess = await this.syncWithTimeout(2000); - if (syncSuccess) { - // Sync succeeded - this.logger.log(`Connected USB Serial successfully with ${strategy.name} reset.`); - return; - } - else { - throw new Error("Sync timeout or abandoned"); - } - } - else { - // Native USB chips - // Note: We use Promise.race with sync() directly instead of syncWithTimeout() - // because syncWithTimeout causes CDC/JTAG devices to hang for unknown reasons. - // The abandon flag in readPacket() prevents overlapping I/O. - // this.logger.log(`Native USB chip detected, using CDC/JTAG sync.`); - const syncPromise = this.sync(); - const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("Sync timeout")), 1000)); - try { - await Promise.race([syncPromise, timeoutPromise]); - // Sync succeeded - this.logger.debug(`Connected CDC/JTAG successfully with ${strategy.name} reset.`); - return; - } - catch (_error) { - throw new Error("Sync timeout or abandoned"); - } - } - } - catch (error) { - lastError = error; - // this.logger.debug( - // `${strategy.name} reset failed: ${(error as Error).message}`, - // ); - // Set abandon flag to stop any in-flight operations - this._abandonCurrentOperation = true; - // Wait a bit for in-flight operations to abort - await sleep(100); - // If port got disconnected, we can't try more strategies - if (!this.connected || !this.port.writable) { - this.logger.log(`Port disconnected during reset attempt`); - break; - } - // Clear buffers before trying next strategy - this._clearInputBuffer(); - await this.drainInputBuffer(200); - await this.flushSerialBuffers(); - } - } - // All strategies failed - reset abandon flag before throwing - this._abandonCurrentOperation = false; - throw new Error(`Couldn't sync to ESP. Try resetting manually. Last error: ${lastError === null || lastError === void 0 ? void 0 : lastError.message}`); - } - /** - * @name watchdogReset - * Watchdog reset for ESP32-S2/S3/C3 with USB-OTG or USB-JTAG/Serial - * Uses RTC watchdog timer to reset the chip - works when DTR/RTS signals are not available - * This is an alias for rtcWdtResetChipSpecific() for backwards compatibility - */ - async watchdogReset() { - await this.rtcWdtResetChipSpecific(); - } - /** - * RTC watchdog timer reset for ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C5, ESP32-C6, and ESP32-P4 - * Uses specific registers for each chip family - * Note: ESP32-H2 does NOT support WDT reset - */ - async rtcWdtResetChipSpecific() { - this.logger.debug("Hard resetting with watchdog timer..."); - let WDTWPROTECT_REG; - let WDTCONFIG0_REG; - let WDTCONFIG1_REG; - let WDT_WKEY; - if (this.chipFamily === CHIP_FAMILY_ESP32S2) { - WDTWPROTECT_REG = ESP32S2_RTC_CNTL_WDTWPROTECT_REG; - WDTCONFIG0_REG = ESP32S2_RTC_CNTL_WDTCONFIG0_REG; - WDTCONFIG1_REG = ESP32S2_RTC_CNTL_WDTCONFIG1_REG; - WDT_WKEY = ESP32S2_RTC_CNTL_WDT_WKEY; - } - else if (this.chipFamily === CHIP_FAMILY_ESP32S3) { - WDTWPROTECT_REG = ESP32S3_RTC_CNTL_WDTWPROTECT_REG; - WDTCONFIG0_REG = ESP32S3_RTC_CNTL_WDTCONFIG0_REG; - WDTCONFIG1_REG = ESP32S3_RTC_CNTL_WDTCONFIG1_REG; - WDT_WKEY = ESP32S3_RTC_CNTL_WDT_WKEY; - } - else if (this.chipFamily === CHIP_FAMILY_ESP32C3) { - WDTWPROTECT_REG = ESP32C3_RTC_CNTL_WDTWPROTECT_REG; - WDTCONFIG0_REG = ESP32C3_RTC_CNTL_WDTCONFIG0_REG; - WDTCONFIG1_REG = ESP32C3_RTC_CNTL_WDTCONFIG1_REG; - WDT_WKEY = ESP32C3_RTC_CNTL_WDT_WKEY; - } - else if (this.chipFamily === CHIP_FAMILY_ESP32C5 || - this.chipFamily === CHIP_FAMILY_ESP32C6) { - // C5 and C6 use LP_WDT (Low Power Watchdog Timer) - WDTWPROTECT_REG = ESP32C5_C6_RTC_CNTL_WDTWPROTECT_REG; - WDTCONFIG0_REG = ESP32C5_C6_RTC_CNTL_WDTCONFIG0_REG; - WDTCONFIG1_REG = ESP32C5_C6_RTC_CNTL_WDTCONFIG1_REG; - WDT_WKEY = ESP32C5_C6_RTC_CNTL_WDT_WKEY; - } - else if (this.chipFamily === CHIP_FAMILY_ESP32P4) { - // P4 uses LP_WDT (Low Power Watchdog Timer) - WDTWPROTECT_REG = ESP32P4_RTC_CNTL_WDTWPROTECT_REG; - WDTCONFIG0_REG = ESP32P4_RTC_CNTL_WDTCONFIG0_REG; - WDTCONFIG1_REG = ESP32P4_RTC_CNTL_WDTCONFIG1_REG; - WDT_WKEY = ESP32P4_RTC_CNTL_WDT_WKEY; - } - else { - throw new Error(`rtcWdtResetChipSpecific() is not supported for ${this.chipFamily}`); - } - // Unlock watchdog registers - await this.writeRegister(WDTWPROTECT_REG, WDT_WKEY, undefined, 0); - // Set WDT timeout to 2000ms (matches Python esptool) - await this.writeRegister(WDTCONFIG1_REG, 2000, undefined, 0); - // Enable WDT: bit 31 = enable, bits 28-30 = stage, bit 8 = sys reset, bits 0-2 = prescaler - const wdtConfig = (1 << 31) | (5 << 28) | (1 << 8) | 2; - await this.writeRegister(WDTCONFIG0_REG, wdtConfig, undefined, 0); - // Lock watchdog registers - await this.writeRegister(WDTWPROTECT_REG, 0, undefined, 0); - // Wait for reset to take effect - await sleep(500); - } - /** - * Reset device from bootloader mode to firmware mode - * Automatically selects the correct reset strategy based on USB connection type - * @param clearForceDownloadFlag - If true, clears the force download boot flag (USB-OTG only) - * @returns true if port will change (USB-OTG), false otherwise - */ - async resetToFirmwareMode(clearForceDownloadFlag = true) { - this.logger.debug("Resetting from bootloader to firmware mode..."); - try { - // Detect USB connection type - const isUsbJtagOrOtg = await this.detectUsbConnectionType(); - if (isUsbJtagOrOtg) { - // USB-JTAG/OTG devices need special handling - this.logger.debug("USB-JTAG/OTG detected - checking WDT reset support"); - // Get detailed USB mode information - let usbMode; - try { - usbMode = await this.getUsbMode(); - this.logger.debug(`USB mode: ${usbMode.mode} (uartNo=${usbMode.uartNo})`); - } - catch (err) { - this.logger.debug(`Could not get USB mode: ${err}`); - // Fall back to generic USB-JTAG/OTG handling - usbMode = { mode: "usb-jtag-serial", uartNo: 0 }; - } - // Check if chip supports WDT reset - // WDT reset is not needed for ESP32-C3 - // WDT reset is supported by: ESP32-S2, ESP32-S3, ESP32-P4 - // WDT reset is NOT supported by: ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 - const supportsWdtReset = this.chipFamily === CHIP_FAMILY_ESP32S2 || - this.chipFamily === CHIP_FAMILY_ESP32S3 || - this.chipFamily === CHIP_FAMILY_ESP32P4; - if (!supportsWdtReset) { - this.logger.debug(`${this.chipName} does not support WDT reset - using classic reset instead`); - // Use classic reset for chips without WDT support - await this.hardResetToFirmware(); - this.logger.debug("Classic reset to firmware complete"); - return false; // Port stays open - } - // WDT reset is supported - proceed with WDT reset logic - this.logger.debug(`${this.chipName} supports WDT reset - using WDT reset strategy`); - // CRITICAL: WDT register writes require ROM (not stub) and baudrate 115200 - // If on stub, need to return to ROM first - if (this.IS_STUB) { - this.logger.debug("On stub - returning to ROM before WDT reset"); - // Change baudrate back to ROM baudrate if needed - if (this.currentBaudRate !== ESP_ROM_BAUD) { - this.logger.debug(`Changing baudrate from ${this.currentBaudRate} to ${ESP_ROM_BAUD}`); - await this.reconfigurePort(ESP_ROM_BAUD); - this.currentBaudRate = ESP_ROM_BAUD; - this.logger.debug("Baudrate changed to 115200"); - } - // CRITICAL: Temporarily clear console mode flag so hardReset(true) works - const wasInConsoleMode = this._consoleMode; - this._consoleMode = false; - // Reset to bootloader (ROM) - await this.hardReset(true); - await sleep(200); - // Restore console mode flag - this._consoleMode = wasInConsoleMode; - // Sync with ROM - await this.sync(); - this.IS_STUB = false; - this.logger.debug("Now on ROM"); - } - else { - // Even if not on stub, ensure baudrate is 115200 for WDT register writes - if (this.currentBaudRate !== ESP_ROM_BAUD) { - this.logger.debug(`Not on stub, but baudrate is ${this.currentBaudRate} - changing to ${ESP_ROM_BAUD} for WDT reset`); - await this.reconfigurePort(ESP_ROM_BAUD); - this.currentBaudRate = ESP_ROM_BAUD; - this.logger.debug("Baudrate changed to 115200"); - } - } - // Clear force download boot flag if requested (USB-OTG only) - if (clearForceDownloadFlag && usbMode.mode === "usb-otg") { - const flagCleared = await this._clearForceDownloadBootIfNeeded(); - if (flagCleared) { - this.logger.debug("Force download boot flag cleared"); - } - } - // Perform WDT reset to boot into firmware - await this.rtcWdtResetChipSpecific(); - this.logger.debug("WDT reset performed - device will boot to firmware"); - // Check if port will change after WDT reset - // USB-OTG (ESP32-S2/P4): Port always changes - // USB-JTAG/Serial (ESP32-S3/C3/C5/C6/C61/H2/P4): Port may change depending on platform - const portWillChange = usbMode.mode === "usb-otg" || usbMode.mode === "usb-jtag-serial"; - if (portWillChange) { - this.logger.debug(`Port will change after WDT reset (${usbMode.mode}) - port reselection needed`); - return true; - } - return false; - } - else { - // External serial chip - use classic reset to firmware - this.logger.debug("External serial chip detected - using classic reset"); - await this.hardResetToFirmware(); - this.logger.debug("Classic reset to firmware complete"); - return false; - } - } - catch (err) { - this.logger.error(`Failed to reset to firmware mode: ${err}`); - throw err; - } - } - async hardReset(bootloader = false) { - // In console mode, only allow simple hardware reset (no bootloader entry) - if (this._consoleMode) { - if (bootloader) { - this.logger.debug("Skipping bootloader reset - device is in console mode"); - return; - } - // Simple hardware reset to restart firmware (IO0=HIGH) - this.logger.debug("Performing hardware reset (console mode)..."); - await this.resetInConsoleMode(); - this.logger.debug("Hardware reset complete"); - return; - } - if (bootloader) { - // Enter bootloader/flash mode - if (this.port.getInfo().usbProductId === USB_JTAG_SERIAL_PID) { - await this.hardResetUSBJTAGSerial(); - this.logger.debug("USB-JTAG/Serial reset to bootloader."); - } - else { - await this.hardResetClassic(); - this.logger.debug("Classic reset to bootloader."); - } - } - else { - // Reset to firmware mode (exit bootloader) - // Use intelligent reset strategy based on USB connection type - this.logger.debug("Resetting to firmware mode..."); - // Detect USB connection type to choose correct reset method - const isUsbJtagOrOtg = await this.detectUsbConnectionType(); - if (isUsbJtagOrOtg) { - // USB-JTAG/OTG devices: Use WDT reset - this.logger.debug("USB-JTAG/OTG detected - using WDT reset"); - // Get USB mode details - let usbMode; - try { - usbMode = await this.getUsbMode(); - this.logger.debug(`USB mode: ${usbMode.mode} (uartNo=${usbMode.uartNo})`); - } - catch (err) { - this.logger.debug(`Could not get USB mode: ${err}`); - usbMode = { mode: "usb-jtag-serial", uartNo: 0 }; - } - // Clear force download flag for USB-OTG devices - if (usbMode.mode === "usb-otg") { - try { - const flagCleared = await this._clearForceDownloadBootIfNeeded(); - if (flagCleared) { - this.logger.debug("Force download boot flag cleared"); - } - } - catch (err) { - this.logger.debug(`Could not clear force download flag: ${err}`); - } - } - // Perform WDT reset - await this.rtcWdtResetChipSpecific(); - this.logger.debug(`${this.chipName}: WDT reset to firmware complete`); - return; - } - else { - // External serial chip: Use classic reset - this.logger.debug("External serial chip detected - using classic reset"); - if (this.isWebUSB()) { - // WebUSB: Use longer delays for better compatibility - await this.setRTSWebUSB(true); // EN->LOW - await sleep(200); - await this.setRTSWebUSB(false); - await sleep(200); - this.logger.debug("Hard reset to firmware (WebUSB)."); - } - else { - // Web Serial: Standard reset - await this.setRTS(true); // EN->LOW - await sleep(100); - await this.setRTS(false); - this.logger.debug("Hard reset to firmware."); - } - } - } - await new Promise((resolve) => setTimeout(resolve, 1000)); - } - /** - * @name macAddr - * The MAC address burned into the OTP memory of the ESP chip - */ - macAddr() { - const macAddr = new Array(6).fill(0); - const mac0 = this._efuses[0]; - const mac1 = this._efuses[1]; - const mac2 = this._efuses[2]; - const mac3 = this._efuses[3]; - let oui; - if (this.chipFamily == CHIP_FAMILY_ESP8266) { - if (mac3 != 0) { - oui = [(mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff]; - } - else if (((mac1 >> 16) & 0xff) == 0) { - oui = [0x18, 0xfe, 0x34]; - } - else if (((mac1 >> 16) & 0xff) == 1) { - oui = [0xac, 0xd0, 0x74]; - } - else { - throw new Error("Couldnt determine OUI"); - } - macAddr[0] = oui[0]; - macAddr[1] = oui[1]; - macAddr[2] = oui[2]; - macAddr[3] = (mac1 >> 8) & 0xff; - macAddr[4] = mac1 & 0xff; - macAddr[5] = (mac0 >> 24) & 0xff; - } - else if (this.chipFamily == CHIP_FAMILY_ESP32) { - macAddr[0] = (mac2 >> 8) & 0xff; - macAddr[1] = mac2 & 0xff; - macAddr[2] = (mac1 >> 24) & 0xff; - macAddr[3] = (mac1 >> 16) & 0xff; - macAddr[4] = (mac1 >> 8) & 0xff; - macAddr[5] = mac1 & 0xff; - } - else if (this.chipFamily == CHIP_FAMILY_ESP32S2 || - this.chipFamily == CHIP_FAMILY_ESP32S3 || - this.chipFamily == CHIP_FAMILY_ESP32C2 || - this.chipFamily == CHIP_FAMILY_ESP32C3 || - this.chipFamily == CHIP_FAMILY_ESP32C5 || - this.chipFamily == CHIP_FAMILY_ESP32C6 || - this.chipFamily == CHIP_FAMILY_ESP32C61 || - this.chipFamily == CHIP_FAMILY_ESP32H2 || - this.chipFamily == CHIP_FAMILY_ESP32H4 || - this.chipFamily == CHIP_FAMILY_ESP32H21 || - this.chipFamily == CHIP_FAMILY_ESP32P4 || - this.chipFamily == CHIP_FAMILY_ESP32S31) { - macAddr[0] = (mac1 >> 8) & 0xff; - macAddr[1] = mac1 & 0xff; - macAddr[2] = (mac0 >> 24) & 0xff; - macAddr[3] = (mac0 >> 16) & 0xff; - macAddr[4] = (mac0 >> 8) & 0xff; - macAddr[5] = mac0 & 0xff; - } - else { - throw new Error("Unknown chip family"); - } - return macAddr; - } - async readRegister(reg) { - if (this.debug) { - this.logger.debug("Reading from Register " + toHex(reg, 8)); - } - const packet = pack(" { - timeout = Math.min(timeout, MAX_TIMEOUT); - await this.sendCommand(opcode, buffer, checksum); - const [value, responseData] = await this.getResponse(opcode, timeout); - if (responseData === null) { - throw new Error("Didn't get enough status bytes"); - } - let data = responseData; - let statusLen = 0; - if (this.IS_STUB || this.chipFamily == CHIP_FAMILY_ESP8266) { - statusLen = 2; - } - else if ([ - CHIP_FAMILY_ESP32, - CHIP_FAMILY_ESP32S2, - CHIP_FAMILY_ESP32S3, - CHIP_FAMILY_ESP32C2, - CHIP_FAMILY_ESP32C3, - CHIP_FAMILY_ESP32C5, - CHIP_FAMILY_ESP32C6, - CHIP_FAMILY_ESP32C61, - CHIP_FAMILY_ESP32H2, - CHIP_FAMILY_ESP32H4, - CHIP_FAMILY_ESP32H21, - CHIP_FAMILY_ESP32P4, - CHIP_FAMILY_ESP32S31, - ].includes(this.chipFamily)) { - statusLen = 4; - } - else { - // When chipFamily is not yet set (e.g., during GET_SECURITY_INFO in detectChip), - // assume modern chips use 4-byte status - if (opcode === ESP_GET_SECURITY_INFO) { - statusLen = 4; - } - else if ([2, 4].includes(data.length)) { - statusLen = data.length; - } - else { - // Default to 2-byte status if we can't determine - // This prevents silent data corruption when statusLen would be 0 - statusLen = 2; - this.logger.debug(`Unknown chip family, defaulting to 2-byte status (opcode: ${toHex(opcode)}, data.length: ${data.length})`); - } - } - if (data.length < statusLen) { - throw new Error("Didn't get enough status bytes"); - } - const status = data.slice(-statusLen, data.length); - data = data.slice(0, -statusLen); - if (this.debug) { - this.logger.debug("status", status); - this.logger.debug("value", value); - this.logger.debug("data", data); - } - if (status[0] == 1) { - if (status[1] == ROM_INVALID_RECV_MSG) { - // Unsupported command can result in more than one error response - // Use drainInputBuffer for CP210x compatibility on Windows - await this.drainInputBuffer(200); - throw new Error("Invalid (unsupported) command " + toHex(opcode)); - } - else { - throw new Error("Command failure error code " + toHex(status[1])); - } - } - return [value, data]; - }; - // Chain command execution through the lock - // Use both .then() handlers to ensure lock continues even on error - this._commandLock = this._commandLock.then(executeCommand, executeCommand); - return this._commandLock; - } - /** - * @name sendCommand - * Send a slip-encoded, checksummed command over the UART, - * does not check response - */ - async sendCommand(opcode, buffer, checksum = 0) { - const packet = slipEncode([ - ...pack(" timeout) { - const waitingFor = partialPacket === null ? "header" : "content"; - throw new SlipReadError("Timed out waiting for packet " + waitingFor); - } - // If no data available, wait a bit - if (this._inputBufferAvailable === 0) { - await sleep(1); - continue; - } - // Process all available bytes without going back to outer loop - // This is critical for handling high-speed burst transfers - while (this._inputBufferAvailable > 0) { - // Periodic timeout check to prevent hang on slow data - if (Date.now() - startTime > timeout) { - const waitingFor = partialPacket === null ? "header" : "content"; - throw new SlipReadError("Timed out waiting for packet " + waitingFor); - } - const byte = this._readByte(); - if (partialPacket === null) { - // waiting for packet header - if (byte == this.SLIP_END) { - partialPacket = []; - } - else { - if (this.debug) { - this.logger.debug("Read invalid data: " + toHex(byte)); - this.logger.debug("Remaining data in serial buffer: " + - hexFormatter(this._inputBuffer)); - } - throw new SlipReadError("Invalid head of packet (" + toHex(byte) + ")"); - } - } - else if (inEscape) { - // part-way through escape sequence - inEscape = false; - if (byte == this.SLIP_ESC_END) { - partialPacket.push(this.SLIP_END); - } - else if (byte == this.SLIP_ESC_ESC) { - partialPacket.push(this.SLIP_ESC); - } - else { - if (this.debug) { - this.logger.debug("Read invalid data: " + toHex(byte)); - this.logger.debug("Remaining data in serial buffer: " + - hexFormatter(this._inputBuffer)); - } - throw new SlipReadError("Invalid SLIP escape (0xdb, " + toHex(byte) + ")"); - } - } - else if (byte == this.SLIP_ESC) { - // start of escape sequence - inEscape = true; - } - else if (byte == this.SLIP_END) { - // end of packet - if (this.debug) - this.logger.debug("Received full packet: " + hexFormatter(partialPacket)); - // Compact buffer periodically to prevent memory growth - this._compactInputBuffer(); - return partialPacket; - } - else { - // normal byte in packet - partialPacket.push(byte); - } - } - } - } - else { - // Byte-by-byte version: Stable for non CDC USB-Serial adapters (CH340, CP2102, etc.) - let readBytes = []; - while (true) { - // Check abandon flag (for reset strategy timeout) - if (this._abandonCurrentOperation) { - throw new SlipReadError("Operation abandoned (reset strategy timeout)"); - } - const stamp = Date.now(); - readBytes = []; - while (Date.now() - stamp < timeout) { - if (this._inputBufferAvailable > 0) { - readBytes.push(this._readByte()); - break; - } - else { - // Reduced sleep time for faster response during high-speed transfers - await sleep(1); - } - } - if (readBytes.length == 0) { - const waitingFor = partialPacket === null ? "header" : "content"; - throw new SlipReadError("Timed out waiting for packet " + waitingFor); - } - if (this.debug) - this.logger.debug("Read " + readBytes.length + " bytes: " + hexFormatter(readBytes)); - for (const byte of readBytes) { - if (partialPacket === null) { - // waiting for packet header - if (byte == this.SLIP_END) { - partialPacket = []; - } - else { - if (this.debug) { - this.logger.debug("Read invalid data: " + toHex(byte)); - this.logger.debug("Remaining data in serial buffer: " + - hexFormatter(this._inputBuffer)); - } - throw new SlipReadError("Invalid head of packet (" + toHex(byte) + ")"); - } - } - else if (inEscape) { - // part-way through escape sequence - inEscape = false; - if (byte == this.SLIP_ESC_END) { - partialPacket.push(this.SLIP_END); - } - else if (byte == this.SLIP_ESC_ESC) { - partialPacket.push(this.SLIP_ESC); - } - else { - if (this.debug) { - this.logger.debug("Read invalid data: " + toHex(byte)); - this.logger.debug("Remaining data in serial buffer: " + - hexFormatter(this._inputBuffer)); - } - throw new SlipReadError("Invalid SLIP escape (0xdb, " + toHex(byte) + ")"); - } - } - else if (byte == this.SLIP_ESC) { - // start of escape sequence - inEscape = true; - } - else if (byte == this.SLIP_END) { - // end of packet - if (this.debug) - this.logger.debug("Received full packet: " + hexFormatter(partialPacket)); - // Compact buffer periodically to prevent memory growth - this._compactInputBuffer(); - return partialPacket; - } - else { - // normal byte in packet - partialPacket.push(byte); - } - } - } - } - } - /** - * @name getResponse - * Read response data and decodes the slip packet, then parses - * out the value/data and returns as a tuple of (value, data) where - * each is a list of bytes - */ - async getResponse(opcode, timeout = DEFAULT_TIMEOUT) { - for (let i = 0; i < 100; i++) { - const packet = await this.readPacket(timeout); - if (packet.length < 8) { - continue; - } - const [resp, opRet, , val] = unpack(">> ESP32C5_PCR_SYSCLK_XTAL_FREQ_S); - } - async getC5CrystalFreqDetected() { - const UART_CLKDIV_MASK = 0xfffff; - const uartDiv = (await this.readRegister(ESP32C5_UART_CLKDIV_REG)) & UART_CLKDIV_MASK; - const estXtal = (ESP_ROM_BAUD * uartDiv) / 1e6; - if (estXtal > 45) - return 48; - if (estXtal > 33) - return 40; - return 26; - } - async setBaudrate(baud) { - const chipFamily = this._parent ? this._parent.chipFamily : this.chipFamily; - if (!this.IS_STUB && chipFamily === CHIP_FAMILY_ESP32C5) { - await this.setBaudrateC5Rom(baud); - } - else { - try { - const buffer = pack(" maxBaud) { - this.logger.log(`⚠️ WARNING: Baudrate ${baud} exceeds USB-Serial chip limit (${maxBaud})!`); - this.logger.log(`⚠️ This may cause data corruption or connection failures!`); - } - this.logger.debug(`Changed baud rate to ${baud}`); - } - async setBaudrateC5Rom(baud) { - const crystalFreqRomExpect = await this.getC5CrystalFreqRomExpect(); - const crystalFreqDetect = await this.getC5CrystalFreqDetected(); - this.logger.log(`ROM expects crystal freq: ${crystalFreqRomExpect} MHz, detected ${crystalFreqDetect} MHz.`); - let baudRate = baud; - if (crystalFreqDetect === 48 && crystalFreqRomExpect === 40) { - baudRate = Math.trunc((baud * 40) / 48); - } - else if (crystalFreqDetect === 40 && crystalFreqRomExpect === 48) { - baudRate = Math.trunc((baud * 48) / 40); - } - this.logger.log(`Changing baud rate to ${baudRate}...`); - try { - const buffer = pack(" timeoutMs) { - return false; - } - // Check abandon flag - if (this._abandonCurrentOperation) { - return false; - } - this._clearInputBuffer(); - try { - const response = await this._sync(); - if (response) { - await sleep(SYNC_TIMEOUT); - return true; - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } - catch (e) { - // Check abandon flag after error - if (this._abandonCurrentOperation) { - return false; - } - } - await sleep(SYNC_TIMEOUT); - } - return false; - } - /** - * @name sync - * Put into ROM bootload mode & attempt to synchronize with the - * ESP ROM bootloader, we will retry a few times - */ - async sync() { - for (let i = 0; i < 5; i++) { - this._clearInputBuffer(); - const response = await this._sync(); - if (response) { - await sleep(SYNC_TIMEOUT); - return true; - } - await sleep(SYNC_TIMEOUT); - } - throw new Error("Couldn't sync to ESP. Try resetting."); - } - /** - * @name _sync - * Perform a soft-sync using AT sync packets, does not perform - * any hardware resetting - */ - async _sync() { - await this.sendCommand(ESP_SYNC, SYNC_PACKET); - for (let i = 0; i < 8; i++) { - try { - const [, data] = await this.getResponse(ESP_SYNC, SYNC_TIMEOUT); - if (data.length > 1 && data[0] == 0 && data[1] == 0) { - return true; - } - } - catch (e) { - if (this.debug) { - this.logger.debug(`Sync attempt ${i + 1} failed: ${e}`); - } - } - } - return false; - } - /** - * @name getFlashWriteSize - * Get the Flash write size based on the chip - */ - getFlashWriteSize() { - if (this.IS_STUB) { - return STUB_FLASH_WRITE_SIZE; - } - return FLASH_WRITE_SIZE; - } - /** - * @name flashData - * Program a full, uncompressed binary file into SPI Flash at - * a given offset. If an ESP32 and md5 string is passed in, will also - * verify memory. ESP8266 does not have checksum memory verification in - * ROM - */ - async flashData(binaryData, updateProgress, offset = 0, compress = false) { - if (binaryData.byteLength >= 8) { - // unpack the (potential) image header - const header = Array.from(new Uint8Array(binaryData, 0, 4)); - const headerMagic = header[0]; - const headerFlashMode = header[2]; - const headerFlashSizeFreq = header[3]; - this.logger.log(`Image header, Magic=${toHex(headerMagic)}, FlashMode=${toHex(headerFlashMode)}, FlashSizeFreq=${toHex(headerFlashSizeFreq)}`); - } - const paddedData = padTo(new Uint8Array(binaryData), 4); - binaryData = paddedData.buffer; - const uncompressedFilesize = binaryData.byteLength; - let compressedFilesize = 0; - let dataToFlash; - let timeout = DEFAULT_TIMEOUT; - if (compress) { - dataToFlash = deflate_1(new Uint8Array(binaryData), { - level: 9, - }).buffer; - compressedFilesize = dataToFlash.byteLength; - this.logger.log(`Writing data with filesize: ${uncompressedFilesize}. Compressed Size: ${compressedFilesize}`); - timeout = await this.flashDeflBegin(uncompressedFilesize, compressedFilesize, offset); - } - else { - this.logger.log(`Writing data with filesize: ${uncompressedFilesize}`); - dataToFlash = binaryData; - await this.flashBegin(uncompressedFilesize, offset); - } - let block = []; - let seq = 0; - let written = 0; - let position = 0; - const stamp = Date.now(); - const flashWriteSize = this.getFlashWriteSize(); - const filesize = compress ? compressedFilesize : uncompressedFilesize; - while (filesize - position > 0) { - if (this.debug) { - this.logger.log(`Writing at ${toHex(offset + seq * flashWriteSize, 8)} `); - } - if (filesize - position >= flashWriteSize) { - block = Array.from(new Uint8Array(dataToFlash, position, flashWriteSize)); - } - else { - // Pad the last block only if we are sending uncompressed data. - block = Array.from(new Uint8Array(dataToFlash, position, filesize - position)); - if (!compress) { - block = block.concat(new Array(flashWriteSize - block.length).fill(0xff)); - } - } - if (compress) { - await this.flashDeflBlock(block, seq, timeout); - } - else { - await this.flashBlock(block, seq); - } - seq += 1; - // If using compression we update the progress with the proportional size of the block taking into account the compression ratio. - // This way we report progress on the uncompressed size - written += compress - ? Math.round((block.length * uncompressedFilesize) / compressedFilesize) - : block.length; - position += flashWriteSize; - updateProgress(Math.min(written, uncompressedFilesize), uncompressedFilesize); - } - this.logger.log("Took " + (Date.now() - stamp) + "ms to write " + filesize + " bytes"); - // Only send flashF finish if running the stub because ir causes the ROM to exit and run user code - if (this.IS_STUB) { - await this.flashBegin(0, 0); - if (compress) { - await this.flashDeflFinish(); - } - else { - await this.flashFinish(); - } - } - } - /** - * @name flashBlock - * Send one block of data to program into SPI Flash memory - */ - async flashBlock(data, seq, timeout = DEFAULT_TIMEOUT) { - await this.checkCommand(ESP_FLASH_DATA, pack(" 0) { - // add a dummy write to a date register as an excuse to have a delay - buffer = buffer.concat(pack(" 0) { - await this.writeRegister(SPI_MOSI_DLEN_REG, mosiBits - 1); - } - if (misoBits > 0) { - await this.writeRegister(SPI_MISO_DLEN_REG, misoBits - 1); - } - } - else { - const SPI_DATA_LEN_REG = spiAddresses.regBase + spiAddresses.usr1Offs; - const SPI_MOSI_BITLEN_S = 17; - const SPI_MISO_BITLEN_S = 8; - const mosiMask = mosiBits == 0 ? 0 : mosiBits - 1; - const misoMask = misoBits == 0 ? 0 : misoBits - 1; - const value = (misoMask << SPI_MISO_BITLEN_S) | (mosiMask << SPI_MOSI_BITLEN_S); - await this.writeRegister(SPI_DATA_LEN_REG, value); - } - } - async waitDone(spiCmdReg, spiCmdUsr) { - for (let i = 0; i < 10; i++) { - const cmdValue = await this.readRegister(spiCmdReg); - if ((cmdValue & spiCmdUsr) == 0) { - return; - } - } - throw Error("SPI command did not complete in time"); - } - async runSpiFlashCommand(spiflashCommand, data, readBits = 0) { - // Run an arbitrary SPI flash command. - // This function uses the "USR_COMMAND" functionality in the ESP - // SPI hardware, rather than the precanned commands supported by - // hardware. So the value of spiflash_command is an actual command - // byte, sent over the wire. - // After writing command byte, writes 'data' to MOSI and then - // reads back 'read_bits' of reply on MISO. Result is a number. - // SPI_USR register flags - const SPI_USR_COMMAND = 1 << 31; - const SPI_USR_MISO = 1 << 28; - const SPI_USR_MOSI = 1 << 27; - // SPI registers, base address differs - const spiAddresses = getSpiFlashAddresses(this.getChipFamily()); - const base = spiAddresses.regBase; - const SPI_CMD_REG = base; - const SPI_USR_REG = base + spiAddresses.usrOffs; - const SPI_USR2_REG = base + spiAddresses.usr2Offs; - const SPI_W0_REG = base + spiAddresses.w0Offs; - // SPI peripheral "command" bitmasks for SPI_CMD_REG - const SPI_CMD_USR = 1 << 18; - // shift values - const SPI_USR2_COMMAND_LEN_SHIFT = 28; - if (readBits > 32) { - throw new Error("Reading more than 32 bits back from a SPI flash operation is unsupported"); - } - if (data.length > 64) { - throw new Error("Writing more than 64 bytes of data with one SPI command is unsupported"); - } - const dataBits = data.length * 8; - const oldSpiUsr = await this.readRegister(SPI_USR_REG); - const oldSpiUsr2 = await this.readRegister(SPI_USR2_REG); - let flags = SPI_USR_COMMAND; - if (readBits > 0) { - flags |= SPI_USR_MISO; - } - if (dataBits > 0) { - flags |= SPI_USR_MOSI; - } - await this.setDataLengths(spiAddresses, dataBits, readBits); - await this.writeRegister(SPI_USR_REG, flags); - await this.writeRegister(SPI_USR2_REG, (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand); - if (dataBits == 0) { - await this.writeRegister(SPI_W0_REG, 0); // clear data register before we read it - } - else { - const padLen = (4 - (data.length % 4)) % 4; - data = data.concat(new Array(padLen).fill(0x00)); // pad to 32-bit multiple - const words = unpack("I".repeat(Math.floor(data.length / 4)), data); - let nextReg = SPI_W0_REG; - this.logger.debug(`Words Length: ${words.length}`); - for (const word of words) { - this.logger.debug(`Writing word ${toHex(word)} to register offset ${toHex(nextReg)}`); - await this.writeRegister(nextReg, word); - nextReg += 4; - } - } - await this.writeRegister(SPI_CMD_REG, SPI_CMD_USR); - await this.waitDone(SPI_CMD_REG, SPI_CMD_USR); - const status = await this.readRegister(SPI_W0_REG); - // restore some SPI controller registers - await this.writeRegister(SPI_USR_REG, oldSpiUsr); - await this.writeRegister(SPI_USR2_REG, oldSpiUsr2); - return status; - } - async detectFlashSize() { - this.logger.debug("Detecting Flash Size"); - const flashId = await this.flashId(); - const manufacturer = flashId & 0xff; - const flashIdLowbyte = (flashId >> 16) & 0xff; - const deviceTypeByte = (flashId >> 8) & 0xff; - const deviceId = (deviceTypeByte << 8) | flashIdLowbyte; - const jedecId = (manufacturer << 16) | deviceId; - const mfrName = FLASH_MANUFACTURERS[manufacturer]; - const deviceName = FLASH_DEVICES[jedecId]; - this.logger.log(`Flash Manufacturer: ${mfrName || "Unknown"} (0x${manufacturer.toString(16)})`); - this.logger.log(`Flash Device: ${deviceName || `Unknown (0x${deviceId.toString(16)})`}`); - this.flashSize = DETECTED_FLASH_SIZES[flashIdLowbyte]; - this.logger.log(`Auto-detected Flash size: ${this.flashSize}`); - } - /** - * @name getEraseSize - * Calculate an erase size given a specific size in bytes. - * Provides a workaround for the bootloader erase bug on ESP8266. - */ - getEraseSize(offset, size) { - const sectorsPerBlock = 16; - const sectorSize = FLASH_SECTOR_SIZE; - const numSectors = Math.floor((size + sectorSize - 1) / sectorSize); - const startSector = Math.floor(offset / sectorSize); - let headSectors = sectorsPerBlock - (startSector % sectorsPerBlock); - if (numSectors < headSectors) { - headSectors = numSectors; - } - if (numSectors < 2 * headSectors) { - return Math.floor(((numSectors + 1) / 2) * sectorSize); - } - return (numSectors - headSectors) * sectorSize; - } - /** - * @name memBegin (592) - * Start downloading an application image to RAM - */ - async memBegin(size, blocks, blocksize, offset) { - return await this.checkCommand(ESP_MEM_BEGIN, pack(" length) { - toOffs = length; - } - await this.memBlock(fieldData.slice(fromOffs, toOffs), seq); - } - } - await this.memFinish(stub.entry); - const p = await this.readPacket(500); - const pChar = String.fromCharCode(...p); - if (pChar != "OHAI") { - throw new Error("Failed to start stub. Unexpected response: " + pChar); - } - this.logger.debug("Stub is now running..."); - const espStubLoader = new EspStubLoader(this.port, this.logger, this); - // Try to autodetect the flash size. - if (!skipFlashDetection) { - await espStubLoader.detectFlashSize(); - } - return espStubLoader; - } - get _writer() { - return this._parent ? this._parent._writer : this.__writer; - } - set _writer(value) { - if (this._parent) { - this._parent._writer = value; - } - else { - this.__writer = value; - } - } - get _writeChain() { - return this._parent ? this._parent._writeChain : this.__writeChain; - } - set _writeChain(value) { - if (this._parent) { - this._parent._writeChain = value; - } - else { - this.__writeChain = value; - } - } - async writeToStream(data) { - if (!this.port.writable) { - this.logger.debug("Port writable stream not available, skipping write"); - return; - } - if (this._isReconfiguring) { - throw new Error("Cannot write during port reconfiguration"); - } - // Queue writes to prevent lock contention (critical for CP2102 on Windows) - this._writeChain = this._writeChain - .then(async () => { - // Check if port is still writable before attempting write - if (!this.port.writable) { - throw new Error("Port became unavailable during write"); - } - // Get or create persistent writer - if (!this._writer) { - try { - this._writer = this.port.writable.getWriter(); - } - catch (err) { - this.logger.error(`Failed to get writer: ${err}`); - throw err; - } - } - // Perform the write - await this._writer.write(new Uint8Array(data)); - }, async () => { - // Previous write failed, but still attempt this write - this.logger.debug("Previous write failed, attempting recovery for current write"); - if (!this.port.writable) { - throw new Error("Port became unavailable during write"); - } - // Writer was likely cleaned up by previous error, create new one - if (!this._writer) { - try { - this._writer = this.port.writable.getWriter(); - } - catch (err) { - this.logger.debug(`Failed to get writer in recovery: ${err}`); - throw new Error("Cannot acquire writer lock"); - } - } - await this._writer.write(new Uint8Array(data)); - }) - .catch((err) => { - this.logger.error(`Write error: ${err}`); - // Ensure writer is cleaned up on any error - if (this._writer) { - try { - this._writer.releaseLock(); - } - catch { - // Ignore release errors - } - this._writer = undefined; - } - // Re-throw to propagate error - throw err; - }); - // Always await the write chain to ensure errors are caught - await this._writeChain; - } - async disconnect() { - if (this._parent) { - await this._parent.disconnect(); - return; - } - if (!this.port.writable) { - // this.logger.debug("Port already closed, skipping disconnect"); - return; - } - // Wait for pending writes to complete - try { - await this._writeChain; - } - catch (_err) { - // this.logger.debug(`Pending write error during disconnect: ${err}`); - } - // Release persistent writer before closing - if (this._writer) { - try { - await this._writer.close(); - this._writer.releaseLock(); - } - catch (_err) { - // this.logger.debug(`Writer close/release error: ${err}`); - } - this._writer = undefined; - } - else { - // No persistent writer exists, close stream directly - // This path is taken when no writes have been queued - try { - const writer = this.port.writable.getWriter(); - await writer.close(); - writer.releaseLock(); - } - catch (_err) { - // this.logger.debug(`Direct writer close error: ${err}`); - } - } - await new Promise((resolve) => { - if (!this._reader) { - resolve(undefined); - return; - } - // Set a timeout to prevent hanging (important for node-usb) - const timeout = setTimeout(() => { - this.logger.debug("Disconnect timeout - forcing resolution"); - resolve(undefined); - }, 1000); - this.addEventListener("disconnect", () => { - clearTimeout(timeout); - resolve(undefined); - }, { once: true }); - // Only cancel if reader is still active - try { - this._reader.cancel(); - } - catch (_err) { - // Reader already released, resolve immediately - clearTimeout(timeout); - resolve(undefined); - } - }); - this.connected = false; - // Close the port (important for node-usb adapter) - try { - await this.port.close(); - this.logger.debug("Port closed successfully"); - } - catch (err) { - this.logger.debug(`Port close error: ${err}`); - } - } - /** - * @name releaseReaderWriter - * Release reader and writer locks without closing the port - * Used when switching to console mode - */ - async releaseReaderWriter() { - if (this._parent) { - await this._parent.releaseReaderWriter(); - return; - } - // Wait for pending writes to complete - try { - await this._writeChain; - } - catch (_err) { - // this.logger.debug(`Pending write error during release: ${err}`); - } - // Release writer - if (this._writer) { - try { - this._writer.releaseLock(); - this.logger.debug("Writer released"); - } - catch (err) { - this.logger.debug(`Writer release error: ${err}`); - } - this._writer = undefined; - } - // Cancel reader - let readLoop's finally block handle releaseLock() - if (this._reader) { - try { - // Suppress disconnect event during console mode switching - this._suppressDisconnect = true; - // Cancel will cause readLoop to exit and call releaseLock() in its finally block - await this._reader.cancel(); - this.logger.debug("Reader cancelled - waiting for readLoop to finish"); - // CRITICAL: Wait a bit for readLoop's finally block to complete - // The finally block needs time to call releaseLock() and set _reader = undefined - // This is much faster than waiting for browser to unlock (just waiting for JS execution) - await sleep(50); - this.logger.debug("ReadLoop cleanup should be complete"); - } - catch (err) { - this.logger.debug(`Reader cancel error: ${err}`); - } - // Don't call releaseLock() or set _reader to undefined here - // Let readLoop's finally block handle it to avoid race conditions - } - } - /** - * @name resetToFirmware - * Public method to reset device from bootloader to firmware for console mode - * Automatically detects USB-JTAG/Serial and USB-OTG devices and performs appropriate reset - * @returns true if reset was performed, false if not needed - */ - async resetToFirmware() { - return await this._resetToFirmwareIfNeeded(); - } - /** - * @name detectUsbConnectionType - * Detect if device is using USB-JTAG/Serial or USB-OTG (not external serial chip) - * Uses USB PID (Product ID) for reliable detection - does NOT require chipFamily - * @returns true if USB-JTAG or USB-OTG, false if external serial chip - */ - async detectUsbConnectionType() { - // Use PID-based detection - const portInfo = this.port.getInfo(); - const pid = portInfo.usbProductId; - const vid = portInfo.usbVendorId; - // Check if this is an Espressif device - const isEspressif = vid === 0x303a; - if (!isEspressif) { - this.logger.debug("Not Espressif VID - external serial chip"); - return false; - } - // ESP32-S2/S3/C3/C5/C6/C61/H2/P4 USB-JTAG/OTG PIDs - // According to official Espressif documentation: - // https://docs.espressif.com/projects/esp-iot-solution/en/latest/usb/usb_overview/usb_device_const_COM.html - // 0x0002 = ESP32-S2 USB-OTG, 0x0012 = ESP32-P4 USB-Serial-JTAG - // 0x1001 = ESP32-S3, C3, C5, C6, C61, H2 USB-Serial-JTAG - const usbJtagPids = [0x0002, 0x0012, 0x1001]; - const isUsbJtag = usbJtagPids.includes(pid || 0); - this.logger.debug(`USB-JTAG/OTG detection: ${isUsbJtag ? "YES" : "NO"} (PID=0x${pid === null || pid === void 0 ? void 0 : pid.toString(16)})`); - return isUsbJtag; - } - async getUsbMode() { - var _a, _b; - const family = this._parent ? this._parent.chipFamily : this.chipFamily; - const revision = this._parent - ? ((_a = this._parent.chipRevision) !== null && _a !== void 0 ? _a : 0) - : ((_b = this.chipRevision) !== null && _b !== void 0 ? _b : 0); - let bufNoAddr = null; - let jtagSerialVal = null; - let otgVal = null; - switch (family) { - case CHIP_FAMILY_ESP32S2: - bufNoAddr = ESP32S2_UARTDEV_BUF_NO; - otgVal = ESP32S2_UARTDEV_BUF_NO_USB_OTG; - break; - case CHIP_FAMILY_ESP32S3: - bufNoAddr = ESP32S3_UARTDEV_BUF_NO; - jtagSerialVal = ESP32S3_UARTDEV_BUF_NO_USB_JTAG_SERIAL; - otgVal = ESP32S3_UARTDEV_BUF_NO_USB_OTG; - break; - case CHIP_FAMILY_ESP32C3: { - const bssAddr = revision < 101 ? 0x3fcdf064 : 0x3fcdf060; - bufNoAddr = bssAddr + ESP32C3_BUF_UART_NO_OFFSET; - jtagSerialVal = ESP32C3_UARTDEV_BUF_NO_USB_JTAG_SERIAL; - break; - } - case CHIP_FAMILY_ESP32C5: - bufNoAddr = ESP32C5_UARTDEV_BUF_NO; - jtagSerialVal = ESP32C5_UARTDEV_BUF_NO_USB_JTAG_SERIAL; - break; - case CHIP_FAMILY_ESP32C6: - bufNoAddr = ESP32C6_UARTDEV_BUF_NO; - jtagSerialVal = ESP32C6_UARTDEV_BUF_NO_USB_JTAG_SERIAL; - break; - case CHIP_FAMILY_ESP32C61: - bufNoAddr = - revision <= 200 - ? ESP32C61_UARTDEV_BUF_NO_REV_LE2 - : ESP32C61_UARTDEV_BUF_NO_REV_GT2; - jtagSerialVal = - revision <= 200 - ? ESP32C61_UARTDEV_BUF_NO_USB_JTAG_SERIAL_REV_LE2 - : ESP32C61_UARTDEV_BUF_NO_USB_JTAG_SERIAL_REV_GT2; - break; - case CHIP_FAMILY_ESP32H2: - bufNoAddr = ESP32H2_UARTDEV_BUF_NO; - jtagSerialVal = ESP32H2_UARTDEV_BUF_NO_USB_JTAG_SERIAL; - break; - case CHIP_FAMILY_ESP32H4: - bufNoAddr = ESP32H4_UARTDEV_BUF_NO; - jtagSerialVal = ESP32H4_UARTDEV_BUF_NO_USB_JTAG_SERIAL; - break; - case CHIP_FAMILY_ESP32P4: - bufNoAddr = - revision < 300 - ? ESP32P4_UARTDEV_BUF_NO_REV0 - : ESP32P4_UARTDEV_BUF_NO_REV300; - jtagSerialVal = ESP32P4_UARTDEV_BUF_NO_USB_JTAG_SERIAL; - otgVal = ESP32P4_UARTDEV_BUF_NO_USB_OTG; - break; - } - if (bufNoAddr === null) { - return { mode: "uart", uartNo: 0 }; - } - const uartNo = (await this.readRegister(bufNoAddr)) & 0xff; - if (otgVal !== null && uartNo === otgVal) { - this.logger.debug(`USB mode: USB-OTG (uartNo=${uartNo})`); - return { mode: "usb-otg", uartNo }; - } - if (jtagSerialVal !== null && uartNo === jtagSerialVal) { - this.logger.debug(`USB mode: USB-JTAG/Serial (uartNo=${uartNo})`); - return { mode: "usb-jtag-serial", uartNo }; - } - this.logger.debug(`USB mode: UART (uartNo=${uartNo})`); - return { mode: "uart", uartNo }; - } - /** - * Check if the current chip supports USB-JTAG or USB-OTG - * @returns true if chip has native USB support (JTAG or OTG) - */ - supportsNativeUsb() { - const family = this._parent ? this._parent.chipFamily : this.chipFamily; - // Chips with USB-JTAG/Serial or USB-OTG support - const usbChips = [ - CHIP_FAMILY_ESP32S2, // USB-OTG - CHIP_FAMILY_ESP32S3, // USB-OTG + USB-JTAG/Serial - CHIP_FAMILY_ESP32C3, // USB-JTAG/Serial - CHIP_FAMILY_ESP32C5, // USB-JTAG/Serial - CHIP_FAMILY_ESP32C6, // USB-JTAG/Serial - CHIP_FAMILY_ESP32C61, // USB-JTAG/Serial - CHIP_FAMILY_ESP32H2, // USB-JTAG/Serial - CHIP_FAMILY_ESP32H4, // USB-JTAG/Serial - CHIP_FAMILY_ESP32P4, // USB-OTG + USB-JTAG/Serial - ]; - return usbChips.includes(family); - } - /** - * @name _ensureStreamsReady - * After a hardware reset, ensure port streams are available. - * On WebUSB, recreates streams since they break after reset. - * On Web Serial, waits for streams to become available. - */ - async _ensureStreamsReady() { - if (this.isWebUSB()) { - try { - await this.port.recreateStreams(); - this.logger.debug("WebUSB streams recreated"); - let retries = 30; - while (retries > 0 && !this.port.readable) { - await sleep(100); - retries--; - } - if (!this.port.readable) { - throw new Error("Readable stream not available after recreating streams"); - } - this.logger.debug("WebUSB streams are ready"); - } - catch (err) { - this.logger.error(`Failed to recreate WebUSB streams: ${err}`); - this._consoleMode = false; - throw err; - } - } - else { - let retries = 20; - while (retries > 0 && !this.port.readable) { - await sleep(100); - retries--; - } - if (!this.port.readable) { - this._consoleMode = false; - throw new Error("Readable stream not available after reset"); - } - this.logger.debug("Port streams are ready"); - } - } - /** - * @name enterConsoleMode - * Prepare device for console mode by resetting to firmware - * Handles both USB-JTAG/OTG devices (closes port) and external serial chips (keeps port open) - * @returns true if port was closed (USB-JTAG), false if port stays open (serial chip) - */ - async enterConsoleMode() { - // Check if port is open - if not, we need a new port selection - if (!this.port.writable || !this.port.readable) { - this.logger.debug("Port is not open - port selection needed"); - // Return true to signal that port selection is needed - // The caller should handle port selection and try again - return true; - } - // Re-detect USB connection type to ensure we have a definitive value - let isUsbJtag; - try { - isUsbJtag = await this.detectUsbConnectionType(); - this.logger.debug(`USB connection type detected: ${isUsbJtag ? "USB-JTAG/OTG" : "External Serial Chip"}`); - // CRITICAL: Set the cached value so _resetToFirmwareIfNeeded() can use it - this._isUsbJtagOrOtg = isUsbJtag; - } - catch (err) { - // If detection fails, fall back to cached value or fail-fast - if (this.isUsbJtagOrOtg === undefined) { - throw new Error(`Cannot enter console mode: USB connection type unknown and detection failed: ${err}`); - } - this.logger.debug(`USB detection failed, using cached value: ${this.isUsbJtagOrOtg}`); - isUsbJtag = this.isUsbJtagOrOtg; - } - // Set console mode flag BEFORE any operations - this._consoleMode = true; - if (isUsbJtag) { - // USB-JTAG/OTG devices: Use reset which may close port - const wasReset = await this._resetToFirmwareIfNeeded(); - if (wasReset) { - return true; // port closed, caller must reopen - } - // Port stayed open (e.g. C3/C5/C6/H2 classic reset) - await this._ensureStreamsReady(); - return false; - } - else { - // External serial chip devices: Release locks and do simple reset - try { - await this.releaseReaderWriter(); - await sleep(100); - } - catch (err) { - this.logger.debug(`Failed to release locks: ${err}`); - } - try { - await this.hardResetToFirmware(); - this.logger.debug("Device reset to firmware mode"); - } - catch (err) { - this.logger.debug(`Could not reset device: ${err}`); - } - await this._ensureStreamsReady(); - return false; - } - } - /** - * @name _clearForceDownloadBootIfNeeded - * Read and clear the force download boot flag if it is set - * This should ONLY be called when on ROM (not stub) and before WDT reset - * Clearing it on every connect causes issues with flash operations - * Returns true if the flag was cleared, false if it was already clear - */ - async _clearForceDownloadBootIfNeeded() { - try { - let regAddr; - let mask; - let chipName; - // Get register address and mask for this chip - if (this.chipFamily === CHIP_FAMILY_ESP32S2) { - regAddr = ESP32S2_RTC_CNTL_OPTION1_REG; - mask = ESP32S2_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK; - chipName = "ESP32-S2"; - } - else if (this.chipFamily === CHIP_FAMILY_ESP32S3) { - regAddr = ESP32S3_RTC_CNTL_OPTION1_REG; - mask = ESP32S3_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK; - chipName = "ESP32-S3"; - } - else if (this.chipFamily === CHIP_FAMILY_ESP32P4) { - regAddr = ESP32P4_RTC_CNTL_OPTION1_REG; - mask = ESP32P4_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK; - chipName = "ESP32-P4"; - } - else { - // Not a chip that needs this - return false; - } - // Read current register value - const currentValue = await this.readRegister(regAddr); - this.logger.debug(`${chipName} force download boot register: 0x${currentValue.toString(16)} (mask: 0x${mask.toString(16)})`); - // Check if the flag is set - const isFlagSet = (currentValue & mask) !== 0; - if (isFlagSet) { - this.logger.debug(`${chipName} force download boot flag is SET - clearing it`); - // Clear the flag by writing 0 to the masked bits - await this.writeRegister(regAddr, 0, mask, 0); - this.logger.debug(`${chipName} force download boot flag cleared`); - return true; - } - else { - this.logger.debug(`${chipName} force download boot flag is already CLEAR - no action needed`); - return false; - } - } - catch (err) { - this.logger.debug(`Error checking/clearing force download flag: ${err}`); - return false; - } - } - /** - * @name _resetToFirmwareIfNeeded - * Reset device from bootloader to firmware when switching to console mode - * Detects USB-JTAG/Serial and USB-OTG devices and performs appropriate reset - * @returns true if reconnect was performed, false otherwise - */ - async _resetToFirmwareIfNeeded() { - // Detect if we need WDT reset (USB-JTAG/OTG) or classic reset - const isUsbJtagOrOtg = await this.detectUsbConnectionType(); - try { - // Check if port is open - if not, assume device is already in firmware mode - if (!this.port.writable || !this.port.readable) { - this.logger.debug("Port is not open - assuming device is already in firmware mode"); - return false; - } - if (isUsbJtagOrOtg) { - // USB-JTAG/OTG: DON'T release reader/writer before WDT reset - // The WDT reset needs active communication to send register write commands - // The port will close automatically after the WDT reset anyway - this.logger.debug("USB-JTAG/OTG: Keeping reader/writer active for WDT reset"); - } - else { - // External serial chip: Release reader/writer before classic reset - await this.releaseReaderWriter(); - this.logger.debug("External serial: Reader/writer released before reset"); - } - // Use the new resetToFirmwareMode method which handles all the logic - const portWillChange = await this.resetToFirmwareMode(true); - if (portWillChange) { - this.logger.debug(`${this.chipName}: Port will change after WDT reset - user must reselect port`); - // Dispatch event to signal port change - this.dispatchEvent(new CustomEvent("usb-otg-port-change", { - detail: { - chipName: this.chipName, - message: `${this.chipName} USB port changed after reset. Please select the new port.`, - reason: "wdt-reset-to-firmware", - }, - })); - return true; - } - else { - // Port stays the same - release reader/writer now if not already done - if (isUsbJtagOrOtg) { - await this.releaseReaderWriter(); - this.logger.debug("Reader/writer released after reset"); - } - return false; - } - } - catch (err) { - this.logger.error(`Reset to firmware mode failed: ${err}`); - // For USB-JTAG/OTG, the port is likely dead after a failed reset - // For external serial, the port is usually still fine - if (isUsbJtagOrOtg) { - this.logger.debug("Forcing port reselection due to USB-JTAG/OTG reset failure"); - return true; - } - this.logger.debug("External serial reset failed, but port should still be usable"); - return false; - } - } - /** - * @name reconnectAndResume - * Reconnect the serial port to flush browser buffers and reload stub - */ - async reconnect() { - if (this._parent) { - await this._parent.reconnect(); - return; - } - try { - this.logger.log("Reconnecting serial port..."); - const savedBaudRate = this.currentBaudRate; - this.connected = false; - this.__inputBuffer = []; - this.__inputBufferReadIndex = 0; - // Wait for pending writes to complete - try { - await this._writeChain; - } - catch (err) { - this.logger.debug(`Pending write error during reconnect: ${err}`); - } - // Block new writes during port close/open - this._isReconfiguring = true; - // Release persistent writer - if (this._writer) { - try { - this._writer.releaseLock(); - } - catch (err) { - this.logger.debug(`Writer release error during reconnect: ${err}`); - } - this._writer = undefined; - } - // Cancel reader - if (this._reader) { - try { - await this._reader.cancel(); - } - catch (err) { - this.logger.debug(`Reader cancel error: ${err}`); - } - this._reader = undefined; - } - // Close port - try { - await this.port.close(); - this.logger.debug("Port closed"); - } - catch (err) { - this.logger.debug(`Port close error: ${err}`); - } - // Open the port - this.logger.debug("Opening port..."); - try { - await this.port.open({ baudRate: ESP_ROM_BAUD }); - this.connected = true; - this.currentBaudRate = ESP_ROM_BAUD; - } - catch (err) { - throw new Error(`Failed to open port: ${err}`); - } - // Verify port streams are available - if (!this.port.readable || !this.port.writable) { - throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`); - } - // Port is now open and ready - allow writes for initialization - this._isReconfiguring = false; - // Save chip info and flash size (no need to detect again) - const savedChipFamily = this.chipFamily; - const savedChipName = this.chipName; - const savedChipRevision = this.chipRevision; - const savedChipVariant = this.chipVariant; - const savedFlashSize = this.flashSize; - // Reinitialize - await this.hardReset(true); - if (!this._parent) { - this.__inputBuffer = []; - this.__inputBufferReadIndex = 0; - this.__totalBytesRead = 0; - this.readLoop(); - } - await this.flushSerialBuffers(); - await this.sync(); - // Restore chip info - this.chipFamily = savedChipFamily; - this.chipName = savedChipName; - this.chipRevision = savedChipRevision; - this.chipVariant = savedChipVariant; - this.flashSize = savedFlashSize; - this.logger.debug(`Reconnect complete (chip: ${this.chipName})`); - // Verify port is ready - if (!this.port.writable || !this.port.readable) { - throw new Error("Port not ready after reconnect"); - } - // Power on flash for ESP32-P4 Rev 301 (must be done before loading stub) - if (this.chipFamily === CHIP_FAMILY_ESP32P4 && - this.chipRevision === 301) { - await this.powerOnFlash(); - } - // Load stub - const stubLoader = await this.runStub(true); - this.logger.debug("Stub loaded"); - // Restore baudrate if it was changed - if (savedBaudRate !== ESP_ROM_BAUD) { - await stubLoader.setBaudrate(savedBaudRate); - // Verify port is still ready after baudrate change - if (!this.port.writable || !this.port.readable) { - throw new Error(`Port not ready after baudrate change (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`); - } - } - // The stub is now running on the chip - // stubLoader has this instance as _parent, so all operations go through this - // We just need to mark this instance as running stub code - this.IS_STUB = true; - this.logger.debug("Reconnection successful"); - } - catch (err) { - // Ensure flag is reset on error - this._isReconfiguring = false; - throw err; - } - } - /** - * @name reconnectToBootloader - * Close and reopen the port, then reset ESP to bootloader mode - * This is needed after Improv or other operations that leave ESP in firmware mode - */ - async reconnectToBootloader() { - if (this._parent) { - await this._parent.reconnectToBootloader(); - return; - } - try { - this.logger.log("Reconnecting to bootloader mode..."); - // Clear console mode flag when reconnecting to bootloader - this._consoleMode = false; - this.connected = false; - this.__inputBuffer = []; - this.__inputBufferReadIndex = 0; - // Wait for pending writes to complete - try { - await this._writeChain; - } - catch (err) { - this.logger.debug(`Pending write error during reconnect: ${err}`); - } - // Block new writes during port close/open - this._isReconfiguring = true; - // Release persistent writer - if (this._writer) { - try { - this._writer.releaseLock(); - } - catch (err) { - this.logger.debug(`Writer release error during reconnect: ${err}`); - } - this._writer = undefined; - } - // Cancel reader - if (this._reader) { - try { - await this._reader.cancel(); - } - catch (err) { - this.logger.debug(`Reader cancel error: ${err}`); - } - this._reader = undefined; - } - // Close port - try { - await this.port.close(); - this.logger.debug("Port closed"); - } - catch (err) { - this.logger.debug(`Port close error: ${err}`); - } - // Open the port - this.logger.debug("Opening port..."); - try { - await this.port.open({ baudRate: ESP_ROM_BAUD }); - this.connected = true; - this.currentBaudRate = ESP_ROM_BAUD; - } - catch (err) { - throw new Error(`Failed to open port: ${err}`); - } - // Verify port streams are available - if (!this.port.readable || !this.port.writable) { - throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`); - } - // Port is now open and ready - allow writes for initialization - this._isReconfiguring = false; - // Reset chip info and stub state - this.__chipFamily = undefined; - this.chipName = "Unknown Chip"; - this.chipRevision = null; - this.chipVariant = null; - this.IS_STUB = false; - // Start read loop - if (!this._parent) { - this.__inputBuffer = []; - this.__inputBufferReadIndex = 0; - this.__totalBytesRead = 0; - this.readLoop(); - } - // Wait for readLoop to start - await sleep(100); - // Reset to bootloader mode using multiple strategies - await this.connectWithResetStrategies(); - // Detect chip type - await this.detectChip(); - this.logger.debug(`Reconnected to bootloader: ${this.chipName}`); - } - catch (err) { - // Ensure flag is reset on error - this._isReconfiguring = false; - throw err; - } - } - /** - * @name exitConsoleMode - * Exit console mode and return to bootloader - * For ESP32-S2, uses reconnectToBootloader which will trigger port change - * @returns true if manual reconnection is needed (ESP32-S2), false otherwise - */ - async exitConsoleMode() { - if (this._parent) { - return await this._parent.exitConsoleMode(); - } - // Clear console mode flag - this._consoleMode = false; - // Check if this is a USB-OTG device (ESP32-S2 or ESP32-P4) - const isUsbOtgChip = this.chipFamily === CHIP_FAMILY_ESP32S2 || - this.chipFamily === CHIP_FAMILY_ESP32P4; - // For USB-OTG chips: if _isUsbJtagOrOtg is undefined, try to detect it - // If detection fails or is undefined, assume USB-JTAG/OTG (conservative/safe path) - let isUsbJtagOrOtg = this._isUsbJtagOrOtg; - if (isUsbOtgChip && isUsbJtagOrOtg === undefined) { - try { - isUsbJtagOrOtg = await this.detectUsbConnectionType(); - } - catch (err) { - this.logger.debug(`USB detection failed, assuming USB-JTAG/OTG for ${this.chipName}: ${err}`); - isUsbJtagOrOtg = true; // Conservative fallback - } - } - if (isUsbOtgChip && isUsbJtagOrOtg) { - // USB-OTG devices: Need to reset to bootloader, which will cause port change - this.logger.debug(`${this.chipName} USB: Resetting to bootloader mode`); - // Perform hardware reset to bootloader (GPIO0=LOW) - // This will cause the port to change from CDC (firmware) to JTAG (bootloader) - try { - await this.hardResetClassic(); - this.logger.debug("Reset to bootloader initiated"); - } - catch (err) { - this.logger.debug(`Reset error: ${err}`); - } - // Wait for reset to complete and port to change - await sleep(500); - this.logger.debug(`${this.chipName}: Port changed. Please select the bootloader port.`); - // Dispatch event to signal port change - this.dispatchEvent(new CustomEvent("usb-otg-port-change", { - detail: { - chipName: this.chipName, - message: `${this.chipName}: Port changed. Please select the bootloader port.`, - reason: "exit-console-to-bootloader", - }, - })); - // Port will change, so return true to indicate manual reconnection needed - return true; - } - // For other devices, use standard reconnectToBootloader - await this.reconnectToBootloader(); - return false; // No manual reconnection needed - } - /** - * @name isConsoleResetSupported - * Check if console reset is supported for this device - * ESP32-S2 USB-JTAG/CDC does not support reset in console mode - * because any reset causes USB port to be lost (hardware limitation) - */ - isConsoleResetSupported() { - if (this._parent) { - return this._parent.isConsoleResetSupported(); - } - // For ESP32-S2: if _isUsbJtagOrOtg is undefined, assume USB-JTAG/OTG (conservative) - // This means console reset is NOT supported (safer default) - const isS2UsbJtag = this.chipFamily === CHIP_FAMILY_ESP32S2 && - (this._isUsbJtagOrOtg === true || this._isUsbJtagOrOtg === undefined); - return !isS2UsbJtag; // Not supported for ESP32-S2 USB-JTAG/CDC - } - /** - * @name resetInConsoleMode - * Reset device while in console mode (firmware mode) - * - * NOTE: For ESP32-S2 USB-JTAG/CDC, ANY reset (hardware or software) causes - * the USB port to be lost because the device switches USB modes during reset. - * This is a hardware limitation - use isConsoleResetSupported() to check first. - */ - async resetInConsoleMode() { - if (this._parent) { - return await this._parent.resetInConsoleMode(); - } - if (!this.isConsoleResetSupported()) { - this.logger.debug("Simple Console reset not supported for ESP32-S2 USB-JTAG/CDC - using exitConsoleMode to enter bootloader"); - await this.exitConsoleMode(); - this.logger.debug("S2 now in bootloader mode - caller must do syncAndWdtReset on new port, then reconnect console"); - return; - } - // For other devices: Use standard firmware reset - try { - this.logger.debug("Resetting device in console mode"); - await this.hardResetToFirmware(); - this.logger.debug("Device reset complete"); - } - catch (err) { - this.logger.error(`Reset failed: ${err}`); - throw err; - } - } - /** - * @name syncAndWdtReset - * Open a new bootloader port, sync with ROM (no stub, no reset strategies), and fire WDT reset. - * This is used for ESP32-S2 USB-OTG devices which require WDT reset to switch modes. - * After WDT reset the port will re-enumerate again. - * The user must select the new port after this method is called. - * @param newPort - The bootloader port selected by the user - */ - async syncAndWdtReset(newPort) { - if (this._parent) { - await this._parent.syncAndWdtReset(newPort); - return; - } - this.port = newPort; - this.connected = false; - this.IS_STUB = false; - this.__inputBuffer = []; - this.__inputBufferReadIndex = 0; - this.__totalBytesRead = 0; - this.logger.debug("Opening bootloader port at 115200..."); - await this.port.open({ baudRate: ESP_ROM_BAUD }); - this.connected = true; - this.currentBaudRate = ESP_ROM_BAUD; - // Start read loop - this.readLoop(); - await sleep(100); - // Sync with ROM only - no reset strategies, device is already in bootloader - this.logger.debug("Syncing with bootloader ROM..."); - await this.sync(); - this.logger.debug("Bootloader sync OK, no stub"); - // Fire WDT reset → device boots into firmware - this.logger.debug("Firing WDT reset..."); - await this.rtcWdtResetChipSpecific(); - this.logger.debug("WDT reset fired - device will boot to firmware"); - } - /** - * @name drainInputBuffer - * Actively drain the input buffer by reading data for a specified time. - * Simple approach for some drivers (especially CP210x on Windows) that have - * issues with buffer flushing. - * - * Based on esptool.py fix: https://github.com/espressif/esptool/commit/5338ea054e5099ac7be235c54034802ac8a43162 - * - * @param bufferingTime - Time in milliseconds to wait for the buffer to fill - */ - async drainInputBuffer(bufferingTime = 200) { - // Wait for the buffer to fill - await sleep(bufferingTime); - // Unsupported command response is sent 8 times and has - // 14 bytes length including delimiter SLIP_END (0xC0) bytes. - // At least part of it is read as a command response, - // but to be safe, read it all. - const bytesToDrain = 14 * 8; - let drained = 0; - // Drain the buffer by reading available data - const drainStart = Date.now(); - const drainTimeout = 100; // Short timeout for draining - while (drained < bytesToDrain && Date.now() - drainStart < drainTimeout) { - if (this._inputBufferAvailable > 0) { - const byte = this._readByte(); - if (byte !== undefined) { - drained++; - } - } - else { - // Small sleep to avoid busy waiting - await sleep(1); - } - } - if (drained > 0) { - this.logger.debug(`Drained ${drained} bytes from input buffer`); - } - // Final clear of application buffer - if (!this._parent) { - this.__inputBuffer = []; - this.__inputBufferReadIndex = 0; - } - } - /** - * @name flushSerialBuffers - * Flush any pending data in the TX and RX serial port buffers - * This clears both the application RX buffer and waits for hardware buffers to drain - */ - async flushSerialBuffers() { - // Clear application buffer - if (!this._parent) { - this.__inputBuffer = []; - this.__inputBufferReadIndex = 0; - } - // Wait for any pending data - await sleep(SYNC_TIMEOUT); - // Final clear - if (!this._parent) { - this.__inputBuffer = []; - this.__inputBufferReadIndex = 0; - } - this.logger.debug("Serial buffers flushed"); - } - /** - * @name readFlash - * Read flash memory from the chip (only works with stub loader) - * @param addr - Address to read from - * @param size - Number of bytes to read - * @param onPacketReceived - Optional callback function called when packet is received - * @param options - Optional parameters for advanced control - * - chunkSize: Amount of data to request from ESP in one command (bytes) - * - blockSize: Size of each data block sent by ESP (bytes) - * - maxInFlight: Maximum unacknowledged bytes (bytes) - * @returns Uint8Array containing the flash data - */ - async readFlash(addr, size, onPacketReceived, options) { - if (!this.IS_STUB) { - throw new Error("Reading flash is only supported in stub mode. Please run runStub() first."); - } - // Flush serial buffers before flash read operation - await this.flushSerialBuffers(); - const readStartTime = Date.now(); - this.logger.log(`Reading ${size} bytes from flash at address 0x${addr.toString(16)}...`); - // Initialize adaptive speed multipliers for WebUSB devices - if (this.isWebUSB()) { - if (this._isCDCDevice) { - // CDC devices (CH343): Start with maximum, adaptive adjustment enabled - this._adaptiveBlockMultiplier = 8; // blockSize = 248 bytes - this._adaptiveMaxInFlightMultiplier = 8; // maxInFlight = 248 bytes - this._consecutiveSuccessfulChunks = 0; - this.logger.debug(`CDC device - Initialized: blockMultiplier=${this._adaptiveBlockMultiplier}, maxInFlightMultiplier=${this._adaptiveMaxInFlightMultiplier}`); - } - else { - // Non-CDC devices (CH340, CP2102): Fixed values, no adaptive adjustment - this._adaptiveBlockMultiplier = 1; // blockSize = 31 bytes (fixed) - this._adaptiveMaxInFlightMultiplier = 1; // maxInFlight = 31 bytes (fixed) - this._consecutiveSuccessfulChunks = 0; - this.logger.debug(`Non-CDC device - Fixed values: blockSize=31, maxInFlight=31`); - } - } - // Chunk size: Amount of data to request from ESP in one command - // For WebUSB (Android), use smaller chunks to avoid timeouts and buffer issues - // For Web Serial (Desktop), use larger chunks for better performance - let CHUNK_SIZE; - if ((options === null || options === void 0 ? void 0 : options.chunkSize) !== undefined) { - // Use user-provided chunkSize if in advanced mode - CHUNK_SIZE = options.chunkSize; - this.logger.log(`Using custom chunk size: 0x${CHUNK_SIZE.toString(16)} bytes`); - } - else if (this.isWebUSB()) { - // WebUSB: Use smaller chunks to avoid SLIP timeout issues - CHUNK_SIZE = 0x4 * 0x1000; // 4KB = 16384 bytes - } - else { - // Web Serial: Use larger chunks for better performance - CHUNK_SIZE = 0x40 * 0x1000; - } - let allData = new Uint8Array(0); - let currentAddr = addr; - let remainingSize = size; - while (remainingSize > 0) { - const chunkSize = Math.min(CHUNK_SIZE, remainingSize); - let chunkSuccess = false; - let retryCount = 0; - const MAX_RETRIES = 5; - let deepRecoveryAttempted = false; - // Retry loop for this chunk - while (!chunkSuccess && retryCount <= MAX_RETRIES) { - let resp = new Uint8Array(0); - let lastAckedLength = 0; // Track last acknowledged length - try { - // Only log on first attempt or retries - if (retryCount === 0) { - this.logger.debug(`Reading chunk at 0x${currentAddr.toString(16)}, size: 0x${chunkSize.toString(16)}`); - } - let blockSize; - let maxInFlight; - if ((options === null || options === void 0 ? void 0 : options.blockSize) !== undefined && - (options === null || options === void 0 ? void 0 : options.maxInFlight) !== undefined) { - // Use user-provided values if in advanced mode - blockSize = options.blockSize; - maxInFlight = options.maxInFlight; - if (retryCount === 0) { - this.logger.debug(`Using custom parameters: blockSize=${blockSize}, maxInFlight=${maxInFlight}`); - } - } - else if (this.isWebUSB()) { - // WebUSB (Android): All devices use adaptive speed - // All have maxTransferSize=64, baseBlockSize=31 - const maxTransferSize = this.port.maxTransferSize || 64; - const baseBlockSize = Math.floor((maxTransferSize - 2) / 2); // 31 bytes - // Use current adaptive multipliers (initialized at start of readFlash) - blockSize = baseBlockSize * this._adaptiveBlockMultiplier; - maxInFlight = baseBlockSize * this._adaptiveMaxInFlightMultiplier; - } - else { - // Web Serial (Desktop): Use multiples of 63 for consistency - const base = 63; - blockSize = base * 65; // 63 * 65 = 4095 (close to 0x1000) - maxInFlight = base * 130; // 63 * 130 = 8190 (close to blockSize * 2) - } - const pkt = pack("= chunkSize) { - break; - } - } - throw err; - } - if (packet && packet.length > 0) { - const packetData = new Uint8Array(packet); - // Append to response - const newResp = new Uint8Array(resp.length + packetData.length); - newResp.set(resp); - newResp.set(packetData, resp.length); - resp = newResp; - // Send acknowledgment when we've received maxInFlight bytes - // The stub sends packets until (num_sent - num_acked) >= max_in_flight - // We MUST wait for all packets before sending ACK - const shouldAck = resp.length >= chunkSize || // End of chunk - resp.length >= lastAckedLength + maxInFlight; // Received all packets - if (shouldAck) { - const ackData = pack("= 2) { - const maxTransferSize = this.port.maxTransferSize || 64; - const baseBlockSize = Math.floor((maxTransferSize - 2) / 2); // 31 bytes - // Maximum: blockSize=248 (8 * 31), maxInFlight=248 (8 * 31) - const MAX_BLOCK_MULTIPLIER = 8; // 248 bytes - tested stable - const MAX_INFLIGHT_MULTIPLIER = 8; // 248 bytes - tested stable - let adjusted = false; - // Increase blockSize first (up to 248), then maxInFlight - if (this._adaptiveBlockMultiplier < MAX_BLOCK_MULTIPLIER) { - this._adaptiveBlockMultiplier = Math.min(this._adaptiveBlockMultiplier * 2, MAX_BLOCK_MULTIPLIER); - adjusted = true; - } - // Once blockSize is at maximum, increase maxInFlight - else if (this._adaptiveMaxInFlightMultiplier < MAX_INFLIGHT_MULTIPLIER) { - this._adaptiveMaxInFlightMultiplier = Math.min(this._adaptiveMaxInFlightMultiplier * 2, MAX_INFLIGHT_MULTIPLIER); - adjusted = true; - } - if (adjusted) { - const newBlockSize = baseBlockSize * this._adaptiveBlockMultiplier; - const newMaxInFlight = baseBlockSize * this._adaptiveMaxInFlightMultiplier; - this.logger.debug(`Speed increased: blockSize=${newBlockSize}, maxInFlight=${newMaxInFlight}`); - this._lastAdaptiveAdjustment = Date.now(); - } - // Reset counter - this._consecutiveSuccessfulChunks = 0; - } - } - } - catch (err) { - retryCount++; - // ADAPTIVE SPEED ADJUSTMENT: Only for CDC devices - // Non-CDC devices stay at fixed values - if (this.isWebUSB() && this._isCDCDevice && retryCount === 1) { - // Only reduce if we're above minimum - if (this._adaptiveBlockMultiplier > 1 || - this._adaptiveMaxInFlightMultiplier > 1) { - // Reduce to minimum on error - this._adaptiveBlockMultiplier = 1; // 31 bytes (for CH343) - this._adaptiveMaxInFlightMultiplier = 1; // 31 bytes - this._consecutiveSuccessfulChunks = 0; // Reset success counter - const maxTransferSize = this.port.maxTransferSize || 64; - const baseBlockSize = Math.floor((maxTransferSize - 2) / 2); - const newBlockSize = baseBlockSize * this._adaptiveBlockMultiplier; - const newMaxInFlight = baseBlockSize * this._adaptiveMaxInFlightMultiplier; - this.logger.debug(`Error at higher speed - reduced to minimum: blockSize=${newBlockSize}, maxInFlight=${newMaxInFlight}`); - } - else { - // Already at minimum and still failing - this is a real error - this.logger.debug(`Error at minimum speed (blockSize=31, maxInFlight=31) - not a speed issue`); - } - } - // Check if it's a timeout error or SLIP error - if (err instanceof SlipReadError) { - if (retryCount <= MAX_RETRIES) { - this.logger.debug(`Cleared buffer and retrying (attempt ${retryCount}/${MAX_RETRIES})...`); - // Continue to retry the same chunk (will send NEW read command) - } - else { - // All retries exhausted - attempt recovery by reloading stub - // IMPORTANT: Do NOT close port to keep ESP32 in bootloader mode - if (!deepRecoveryAttempted) { - deepRecoveryAttempted = true; - this.logger.log(`All retries exhausted at 0x${currentAddr.toString(16)}. Attempting recovery (close and reopen port)...`); - try { - // Reconnect will close port, reopen, and reload stub - await this.reconnect(); - this.logger.log("Deep recovery successful. Resuming read from current position..."); - // Reset retry counter to give it another chance after recovery - retryCount = 0; - continue; - } - catch (recoveryErr) { - throw new Error(`Failed to read chunk at 0x${currentAddr.toString(16)} after ${MAX_RETRIES} retries and recovery failed: ${recoveryErr}`); - } - } - else { - // Recovery already attempted, give up - throw new Error(`Failed to read chunk at 0x${currentAddr.toString(16)} after ${MAX_RETRIES} retries and recovery attempt`); - } - } - } - else { - // Non-SLIP error, don't retry - throw err; - } - } - } - // Update progress (use empty array since we already appended to allData) - if (onPacketReceived) { - onPacketReceived(new Uint8Array(chunkSize), allData.length, size); - } - currentAddr += chunkSize; - remainingSize -= chunkSize; - this.logger.debug(`Total progress: 0x${allData.length.toString(16)} from 0x${size.toString(16)} bytes`); - } - const totalDuration = Date.now() - readStartTime; - const totalSpeedKBs = (allData.length / - 1024 / - (totalDuration / 1000)).toFixed(1); - this.logger.log(`Read complete: ${allData.length} bytes in ${(totalDuration / 1000).toFixed(1)} s (${totalSpeedKBs} KB/s)`); - return allData; - } -} -class EspStubLoader extends ESPLoader { - constructor() { - super(...arguments); - /* - The Stubloader has commands that run on the uploaded Stub Code in RAM - rather than built in commands. - */ - this.IS_STUB = true; - } - /** - * @name memBegin (592) - * Start downloading an application image to RAM - */ - async memBegin(size, _blocks, _blocksize, offset) { - const stub = await getStubCode(this.chipFamily, this.chipRevision); - // Stub may be null for chips without stub support - if (stub === null) { - return [0, []]; - } - const load_start = offset; - const load_end = offset + size; - this.logger.debug(`Load range: ${toHex(load_start, 8)}-${toHex(load_end, 8)}`); - this.logger.debug(`Stub data: ${toHex(stub.data_start, 8)}, len: ${stub.data.length}, text: ${toHex(stub.text_start, 8)}, len: ${stub.text.length}`); - for (const [start, end] of [ - [stub.data_start, stub.data_start + stub.data.length], - [stub.text_start, stub.text_start + stub.text.length], - ]) { - if (load_start < end && load_end > start) { - throw new Error("Software loader is resident at " + - toHex(start, 8) + - "-" + - toHex(end, 8) + - ". " + - "Can't load binary at overlapping address range " + - toHex(load_start, 8) + - "-" + - toHex(load_end, 8) + - ". " + - "Try changing the binary loading address."); - } - } - return [0, []]; - } - /** - * @name eraseFlash - * Erase entire flash chip - */ - async eraseFlash() { - await this.checkCommand(ESP_ERASE_FLASH, [], 0, CHIP_ERASE_TIMEOUT); - } - /** - * @name eraseRegion - * Erase a specific region of flash - */ - async eraseRegion(offset, size) { - // Validate inputs - if (offset < 0) { - throw new Error(`Invalid offset: ${offset} (must be non-negative)`); - } - if (size < 0) { - throw new Error(`Invalid size: ${size} (must be non-negative)`); - } - // No-op for zero size - if (size === 0) { - this.logger.log("eraseRegion: size is 0, skipping erase"); - return; - } - // Check for sector alignment - if (offset % FLASH_SECTOR_SIZE !== 0) { - throw new Error(`Offset ${offset} (0x${offset.toString(16)}) is not aligned to flash sector size ${FLASH_SECTOR_SIZE} (0x${FLASH_SECTOR_SIZE.toString(16)})`); - } - if (size % FLASH_SECTOR_SIZE !== 0) { - throw new Error(`Size ${size} (0x${size.toString(16)}) is not aligned to flash sector size ${FLASH_SECTOR_SIZE} (0x${FLASH_SECTOR_SIZE.toString(16)})`); - } - // Check for reasonable bounds (prevent wrapping in pack) - const maxValue = 0xffffffff; // 32-bit unsigned max - if (offset > maxValue) { - throw new Error(`Offset ${offset} exceeds maximum value ${maxValue}`); - } - if (size > maxValue) { - throw new Error(`Size ${size} exceeds maximum value ${maxValue}`); - } - // Check for wrap-around - if (offset + size > maxValue) { - throw new Error(`Region end (offset + size = ${offset + size}) exceeds maximum addressable range ${maxValue}`); - } - const timeout = timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, size); - const buffer = pack(" data.length) - break; - const page = data.slice(pageOffset, pageOffset + pageSize); - const objId = page[0] | (page[1] << 8); - // Look for SPIFFS filename pattern: 0x01 followed by '/' and printable chars - for (let i = 0; i < page.length - 10; i++) { - if (page[i] === 0x01 && page[i + 1] === 0x2f) { // 0x01 followed by '/' - let validChars = 0; - for (let j = i + 1; j < Math.min(i + 20, page.length); j++) { - if (page[j] >= 0x20 && page[j] < 0x7f) { - validChars++; - } - else if (page[j] === 0x00) { - break; - } - } - if (validChars >= 4) { // At least "/xxx" - spiffsScore += 5; - break; - } - } - } - // Check for typical SPIFFS object ID patterns - if ((objId & 0x8000) !== 0) { - const idLow = objId & 0x7fff; - if (idLow > 0 && idLow < 0x1000) { - spiffsScore += 2; - } - } - } - return spiffsScore >= 10; -} -/** - * Scan ESP8266 flash for filesystem by detecting filesystem signatures - * Reads actual block_count from LittleFS superblock for accurate size detection - * - * @param flashData - Flash data starting at scanOffset - * @param scanOffset - The offset in flash where this data starts - * @param flashSize - Total flash size in bytes - * @returns Detected filesystem layout or null - */ -function scanESP8266Filesystem(flashData, scanOffset, flashSize) { - // Check for LittleFS signature - // LittleFS superblock has "littlefs" magic at offset 8 within block 0 - const blockSizes = ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES; // ESP8266 typically uses 8192 - for (const blockSize of blockSizes) { - // Check block 0 and block 1 (mirrored superblock) - for (let blockIndex = 0; blockIndex < 2; blockIndex++) { - const superblockOffset = blockIndex * blockSize; - const magicOffset = superblockOffset + 8; - if (magicOffset + 8 > flashData.length) { - continue; - } - const magicStr = String.fromCharCode(flashData[magicOffset], flashData[magicOffset + 1], flashData[magicOffset + 2], flashData[magicOffset + 3], flashData[magicOffset + 4], flashData[magicOffset + 5], flashData[magicOffset + 6], flashData[magicOffset + 7]); - if (magicStr === "littlefs") { - // Validate version (at offset 16 in superblock) - const versionOffset = superblockOffset + 16; - const version = flashData[versionOffset] | - (flashData[versionOffset + 1] << 8) | - (flashData[versionOffset + 2] << 16) | - (flashData[versionOffset + 3] << 24); - if (version !== 0 && (version >>> 0) !== 0xffffffff) { - // Found valid LittleFS! - // Try to read block_count from superblock (offset 24, 4 bytes little-endian) - const blockCountOffset = superblockOffset + 24; - if (blockCountOffset + 4 <= flashData.length) { - const blockCount = flashData[blockCountOffset] | - (flashData[blockCountOffset + 1] << 8) | - (flashData[blockCountOffset + 2] << 16) | - (flashData[blockCountOffset + 3] << 24); - // Validate block_count (should be reasonable: > 0 and < 100000) - if (blockCount > 0 && blockCount < 100000) { - const detectedSize = blockCount * blockSize; - // Verify size is reasonable (not larger than remaining flash) - if (detectedSize > 0 && scanOffset + detectedSize <= flashSize) { - return { - start: scanOffset, - end: scanOffset + detectedSize, - size: detectedSize, - page: ESP8266_LITTLEFS_PAGE_SIZE, - block: blockSize, - }; - } - } - } - // Fallback to known layout patterns if block_count read failed - return getLayoutForDetectedFilesystem(scanOffset, flashSize, blockSize); - } - } - } - } - // Check for SPIFFS filesystem using pattern detection - if (detectSPIFFSPatterns(flashData)) { - // SPIFFS does not store size in the image itself - // Size must come from linker script or partition table - return getLayoutForDetectedFilesystem(scanOffset, flashSize, ESP8266_SPIFFS_BLOCK_SIZE); - } - // Also check for SPIFFS magic 0x20140529 (some implementations have it) - if (flashData.length >= 4) { - const spiffsMagic = flashData[0] | - (flashData[1] << 8) | - (flashData[2] << 16) | - (flashData[3] << 24); - if (spiffsMagic === 0x20140529) { - // Found SPIFFS magic! - // Additional validation: Check if header looks valid - let validHeader = true; - // Check if next bytes are not all 0xFF - if (flashData.length >= 16) { - let allFF = true; - for (let i = 4; i < 16; i++) { - if (flashData[i] !== 0xff) { - allFF = false; - break; - } - } - if (allFF) { - validHeader = false; - } - } - if (validHeader) { - return getLayoutForDetectedFilesystem(scanOffset, flashSize, ESP8266_SPIFFS_BLOCK_SIZE); - } - } - } - // Check for FAT filesystem - // FAT can start at offset 0 or 0x1000 (4096 bytes) in ESP8266 - const fatOffsets = [0, 0x1000]; - for (const fatOffset of fatOffsets) { - if (flashData.length < fatOffset + 512) { - continue; - } - const bootSig = flashData[fatOffset + 510] | (flashData[fatOffset + 511] << 8); - if (bootSig === 0xaa55) { - // Read bytes per sector - const bytesPerSector = flashData[fatOffset + 0x0b] | (flashData[fatOffset + 0x0c] << 8); - // Validate bytes per sector (must be 512, 1024, 2048, or 4096) - if (![512, 1024, 2048, 4096].includes(bytesPerSector)) { - continue; - } - // Read total sectors (try 16-bit first, then 32-bit) - let totalSectors = flashData[fatOffset + 0x13] | (flashData[fatOffset + 0x14] << 8); - if (totalSectors === 0) { - // Use 32-bit total sectors - totalSectors = - flashData[fatOffset + 0x20] | - (flashData[fatOffset + 0x21] << 8) | - (flashData[fatOffset + 0x22] << 16) | - (flashData[fatOffset + 0x23] << 24); - } - // Validate values - if (bytesPerSector > 0 && totalSectors > 0 && totalSectors < 100000000) { - const detectedSize = totalSectors * bytesPerSector; - // Verify size is reasonable (not larger than remaining flash) - // Account for the FAT offset in the actual flash position - const actualStart = scanOffset + fatOffset; - if (detectedSize > 0 && actualStart + detectedSize <= flashSize) { - return { - start: actualStart, - end: actualStart + detectedSize, - size: detectedSize, - page: bytesPerSector, - block: bytesPerSector, // FAT uses sector size as block size - }; - } - } - } - } - return null; -} -/** - * Get filesystem layout based on detected offset and flash size - * Uses known ESP8266 linker script patterns from Arduino/PlatformIO - */ -function getLayoutForDetectedFilesystem(offset, flashSize, blockSize) { - const flashSizeMB = flashSize / (1024 * 1024); - // 16MB Flash layouts - if (flashSizeMB >= 16) { - if (offset === 0x100000) { - return { start: 0x100000, end: 0xffa000, size: 0xefa000, page: 256, block: blockSize }; // 15MB - } - else if (offset === 0x200000) { - return { start: 0x200000, end: 0xffa000, size: 0xdfa000, page: 256, block: blockSize }; // 14MB - } - } - // 8MB Flash layouts - if (flashSizeMB >= 8) { - if (offset === 0x100000) { - return { start: 0x100000, end: 0x7fa000, size: 0x6fa000, page: 256, block: blockSize }; // 7MB - } - else if (offset === 0x200000) { - return { start: 0x200000, end: 0x7fa000, size: 0x5fa000, page: 256, block: blockSize }; // 6MB - } - } - // 4MB Flash layouts - if (flashSizeMB >= 4) { - if (offset === 0x100000) { - return { start: 0x100000, end: 0x3fa000, size: 0x2fa000, page: 256, block: blockSize }; // 3MB - } - else if (offset === 0x200000) { - return { start: 0x200000, end: 0x3fa000, size: 0x1fa000, page: 256, block: blockSize }; // 2MB - } - else if (offset === 0x300000) { - return { start: 0x300000, end: 0x3fa000, size: 0x0fa000, page: 256, block: blockSize }; // 1MB - } - } - // 2MB Flash layouts - if (flashSizeMB >= 2) { - if (offset === 0x100000) { - return { start: 0x100000, end: 0x1fa000, size: 0x0fa000, page: 256, block: blockSize }; // 1MB - } - else if (offset === 0x180000) { - return { start: 0x180000, end: 0x1fa000, size: 0x07a000, page: 256, block: blockSize }; // 512KB - } - else if (offset === 0x1c0000) { - return { start: 0x1c0000, end: 0x1fb000, size: 0x03b000, page: 256, block: blockSize }; // 256KB - } - else if (offset === 0x1e0000) { - return { start: 0x1e0000, end: 0x1fb000, size: 0x01b000, page: 256, block: blockSize }; // 128KB - } - else if (offset === 0x1f0000) { - return { start: 0x1f0000, end: 0x1fb000, size: 0x00b000, page: 256, block: blockSize }; // 64KB - } - } - // 1MB Flash layouts - if (flashSizeMB >= 1) { - if (offset === 0x07b000) { - return { start: 0x07b000, end: 0x0fb000, size: 0x080000, page: 256, block: blockSize }; // 512KB - } - else if (offset === 0x0bb000) { - return { start: 0x0bb000, end: 0x0fb000, size: 0x040000, page: 256, block: blockSize }; // 256KB - } - else if (offset === 0x0cb000) { - return { start: 0x0cb000, end: 0x0fb000, size: 0x030000, page: 256, block: blockSize }; // 192KB - } - else if (offset === 0x0d3000) { - return { start: 0x0d3000, end: 0x0fb000, size: 0x028000, page: 256, block: blockSize }; // 160KB - } - else if (offset === 0x0d7000) { - return { start: 0x0d7000, end: 0x0fb000, size: 0x024000, page: 256, block: blockSize }; // 144KB - } - else if (offset === 0x0db000) { - return { start: 0x0db000, end: 0x0fb000, size: 0x020000, page: 256, block: blockSize }; // 128KB - } - else if (offset === 0x0eb000) { - return { start: 0x0eb000, end: 0x0fb000, size: 0x010000, page: 256, block: blockSize }; // 64KB - } - } - // 512KB Flash layouts - if (flashSizeMB >= 0.5) { - if (offset === 0x05b000) { - return { start: 0x05b000, end: 0x07b000, size: 0x020000, page: 256, block: blockSize }; // 128KB - } - else if (offset === 0x06b000) { - return { start: 0x06b000, end: 0x07b000, size: 0x010000, page: 256, block: blockSize }; // 64KB - } - else if (offset === 0x073000) { - return { start: 0x073000, end: 0x07b000, size: 0x008000, page: 256, block: blockSize }; // 32KB - } - } - // Fallback: use remaining flash space - const size = flashSize - offset; - return { - start: offset, - end: flashSize, - size: size, - page: 256, - block: blockSize, - }; -} -/** - * Get common ESP8266 filesystem layouts as fallback - * Used when we can't scan the actual flash - * - * @param flashSizeMB - Flash size in megabytes - * @returns Array of possible filesystem layouts (most common first) - */ -function getESP8266FilesystemLayout(flashSizeMB) { - // Based on common ESP8266 linker script configurations - if (flashSizeMB >= 16) { - // 16MB flash - return [ - { start: 0x100000, end: 0xffa000, size: 0xefa000, page: 256, block: 8192 }, // 15MB - { start: 0x200000, end: 0xffa000, size: 0xdfa000, page: 256, block: 8192 }, // 14MB - ]; - } - else if (flashSizeMB >= 8) { - // 8MB flash - return [ - { start: 0x100000, end: 0x7fa000, size: 0x6fa000, page: 256, block: 8192 }, // 7MB - { start: 0x200000, end: 0x7fa000, size: 0x5fa000, page: 256, block: 8192 }, // 6MB - ]; - } - else if (flashSizeMB >= 4) { - // 4MB flash: Multiple possible configurations - return [ - { start: 0x200000, end: 0x3fa000, size: 0x1fa000, page: 256, block: 8192 }, // 2MB (most common) - { start: 0x100000, end: 0x3fa000, size: 0x2fa000, page: 256, block: 8192 }, // 3MB - { start: 0x300000, end: 0x3fa000, size: 0x0fa000, page: 256, block: 8192 }, // 1MB - ]; - } - else if (flashSizeMB >= 2) { - // 2MB flash - return [ - { start: 0x100000, end: 0x1fa000, size: 0x0fa000, page: 256, block: 8192 }, // 1MB - { start: 0x180000, end: 0x1fa000, size: 0x07a000, page: 256, block: 8192 }, // 512KB - { start: 0x1c0000, end: 0x1fb000, size: 0x03b000, page: 256, block: 8192 }, // 256KB - { start: 0x1e0000, end: 0x1fb000, size: 0x01b000, page: 256, block: 8192 }, // 128KB - { start: 0x1f0000, end: 0x1fb000, size: 0x00b000, page: 256, block: 8192 }, // 64KB - ]; - } - else if (flashSizeMB >= 1) { - // 1MB flash - return [ - { start: 0x0db000, end: 0x0fb000, size: 0x020000, page: 256, block: 8192 }, // 128KB (most common) - { start: 0x07b000, end: 0x0fb000, size: 0x080000, page: 256, block: 8192 }, // 512KB - { start: 0x0bb000, end: 0x0fb000, size: 0x040000, page: 256, block: 8192 }, // 256KB - { start: 0x0cb000, end: 0x0fb000, size: 0x030000, page: 256, block: 8192 }, // 192KB - { start: 0x0d3000, end: 0x0fb000, size: 0x028000, page: 256, block: 8192 }, // 160KB - { start: 0x0d7000, end: 0x0fb000, size: 0x024000, page: 256, block: 8192 }, // 144KB - { start: 0x0eb000, end: 0x0fb000, size: 0x010000, page: 256, block: 8192 }, // 64KB - ]; - } - else if (flashSizeMB >= 0.5) { - // 512KB flash - return [ - { start: 0x05b000, end: 0x07b000, size: 0x020000, page: 256, block: 8192 }, // 128KB - { start: 0x06b000, end: 0x07b000, size: 0x010000, page: 256, block: 8192 }, // 64KB - { start: 0x073000, end: 0x07b000, size: 0x008000, page: 256, block: 8192 }, // 32KB - ]; - } - return []; -} -/** - * Filesystem types based on partition subtype - */ -var FilesystemType; -(function (FilesystemType) { - FilesystemType["UNKNOWN"] = "unknown"; - FilesystemType["LITTLEFS"] = "littlefs"; - FilesystemType["FATFS"] = "fatfs"; - FilesystemType["SPIFFS"] = "spiffs"; -})(FilesystemType || (FilesystemType = {})); -/** - * Detect filesystem type from partition information - * Note: This only provides a hint. LittleFS is often stored in SPIFFS partitions (0x82). - * Use detectFilesystemFromImage() for accurate detection. - */ -function detectFilesystemType(partition) { - if (partition.type !== 0x01) { - return FilesystemType.UNKNOWN; - } - switch (partition.subtype) { - case 0x81: - return FilesystemType.FATFS; - case 0x82: - return FilesystemType.UNKNOWN; - default: - return FilesystemType.UNKNOWN; - } -} -/** - * Detect filesystem type from image data - * Properly validates LittleFS superblock structure at correct offsets - * - * @param imageData - Binary filesystem image data - * @param chipName - Optional chip name for ESP8266-specific detection (e.g. "ESP8266") - */ -function detectFilesystemFromImage(imageData, chipName) { - if (imageData.length < 512) { - return FilesystemType.UNKNOWN; - } - // Check for LittleFS superblock at proper offsets - // LittleFS superblock structure: - // - Offset 0-3: version (4 bytes, little-endian) - // - Offset 4-7: CRC/flags (4 bytes) - // - Offset 8-15: "littlefs" magic string (8 bytes ASCII) - // - Offset 16+: additional metadata - // The superblock is at block 0 and mirrored at block 1 - // Block size is determined by the distance between mirrored superblocks - // Use chip-specific block sizes - const isESP8266 = chipName === null || chipName === void 0 ? void 0 : chipName.toUpperCase().includes("ESP8266"); - const blockSizes = isESP8266 - ? ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES - : LITTLEFS_BLOCK_SIZE_CANDIDATES; - for (const blockSize of blockSizes) { - // Check first two blocks (superblock is mirrored) - for (let blockIndex = 0; blockIndex < 2; blockIndex++) { - const superblockOffset = blockIndex * blockSize; - if (superblockOffset + 20 > imageData.length) { - continue; - } - // Check for "littlefs" magic at offset 8 of superblock - const magicOffset = superblockOffset + 8; - if (magicOffset + 8 <= imageData.length) { - const magicStr = String.fromCharCode(imageData[magicOffset], imageData[magicOffset + 1], imageData[magicOffset + 2], imageData[magicOffset + 3], imageData[magicOffset + 4], imageData[magicOffset + 5], imageData[magicOffset + 6], imageData[magicOffset + 7]); - if (magicStr === "littlefs") { - // Found valid LittleFS superblock with magic string - // Validate version field to avoid false positives (at offset 16) - const versionOffset = superblockOffset + 16; - const version = imageData[versionOffset] | - (imageData[versionOffset + 1] << 8) | - (imageData[versionOffset + 2] << 16) | - (imageData[versionOffset + 3] << 24); - // Version must be non-zero and not erased flash (0xFFFFFFFF) - // Use unsigned comparison - if (version !== 0 && (version >>> 0) !== 0xFFFFFFFF) { - return FilesystemType.LITTLEFS; - } - } - } - } - } - // Check for FAT filesystem signatures - // FAT can start at offset 0 or 0x1000 (4096 bytes) in ESP8266 - const fatOffsets = [0, 0x1000]; - for (const fatOffset of fatOffsets) { - if (imageData.length < fatOffset + 512) { - continue; - } - const bootSig = imageData[fatOffset + 510] | (imageData[fatOffset + 511] << 8); - if (bootSig === 0xaa55) { - const fat16Sig = imageData.length >= fatOffset + 62 - ? String.fromCharCode(imageData[fatOffset + 54], imageData[fatOffset + 55], imageData[fatOffset + 56], imageData[fatOffset + 57], imageData[fatOffset + 58]) - : ""; - const fat32Sig = imageData.length >= fatOffset + 90 - ? String.fromCharCode(imageData[fatOffset + 82], imageData[fatOffset + 83], imageData[fatOffset + 84], imageData[fatOffset + 85], imageData[fatOffset + 86]) - : ""; - if (fat16Sig.startsWith("FAT") || fat32Sig.startsWith("FAT")) { - return FilesystemType.FATFS; - } - } - } - // Check for SPIFFS magic (0x20140529) - if (imageData.length >= 4) { - const spiffsMagic = imageData[0] | - (imageData[1] << 8) | - (imageData[2] << 16) | - (imageData[3] << 24); - if (spiffsMagic === 0x20140529) { - return FilesystemType.SPIFFS; - } - } - // Check for SPIFFS filesystem using pattern detection - if (detectSPIFFSPatterns(imageData)) { - return FilesystemType.SPIFFS; - } - return FilesystemType.UNKNOWN; -} -/** - * Get appropriate block size for filesystem type and chip - */ -function getDefaultBlockSize(fsType, chipName) { - const isESP8266 = chipName === null || chipName === void 0 ? void 0 : chipName.toUpperCase().includes("ESP8266"); - switch (fsType) { - case FilesystemType.FATFS: - return FATFS_DEFAULT_BLOCK_SIZE; - case FilesystemType.LITTLEFS: - return isESP8266 - ? ESP8266_LITTLEFS_BLOCK_SIZE - : LITTLEFS_DEFAULT_BLOCK_SIZE; - default: - return isESP8266 ? ESP8266_LITTLEFS_BLOCK_SIZE : 4096; - } -} -/** - * Get block size candidates for filesystem type and chip - */ -function getBlockSizeCandidates(fsType, chipName) { - const isESP8266 = chipName === null || chipName === void 0 ? void 0 : chipName.toUpperCase().includes("ESP8266"); - switch (fsType) { - case FilesystemType.FATFS: - return FATFS_BLOCK_SIZE_CANDIDATES; - case FilesystemType.LITTLEFS: - return isESP8266 - ? ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES - : LITTLEFS_BLOCK_SIZE_CANDIDATES; - default: - return isESP8266 - ? ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES - : [4096, 2048, 1024, 512]; - } -} - -/** - * ESP32 Partition Table Parser - * Based on ESP-IDF partition table format - */ -// Partition types -const PARTITION_TYPES = { - 0x00: "app", - 0x01: "data", -}; -// App subtypes -const APP_SUBTYPES = { - 0x00: "factory", - 0x10: "ota_0", - 0x11: "ota_1", - 0x12: "ota_2", - 0x13: "ota_3", - 0x14: "ota_4", - 0x15: "ota_5", - 0x16: "ota_6", - 0x17: "ota_7", - 0x18: "ota_8", - 0x19: "ota_9", - 0x1a: "ota_10", - 0x1b: "ota_11", - 0x1c: "ota_12", - 0x1d: "ota_13", - 0x1e: "ota_14", - 0x1f: "ota_15", - 0x20: "test", -}; -// Data subtypes -const DATA_SUBTYPES = { - 0x00: "ota", - 0x01: "phy", - 0x02: "nvs", - 0x03: "coredump", - 0x04: "nvs_keys", - 0x05: "efuse", - 0x80: "esphttpd", - 0x81: "fat", - 0x82: "spiffs", - 0x83: "littlefs", -}; -const PARTITION_ENTRY_SIZE = 32; -const PARTITION_MAGIC = 0x50aa; -/** - * Parse a single partition entry from binary data - */ -function parsePartitionEntry(data) { - if (data.length < PARTITION_ENTRY_SIZE) { - return null; - } - // Check magic bytes - const magic = (data[0] | (data[1] << 8)) & 0xffff; - if (magic !== PARTITION_MAGIC) { - return null; - } - const type = data[2]; - const subtype = data[3]; - const offset = data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24); - const size = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24); - // Name is at offset 12, max 16 bytes, null-terminated - let name = ""; - for (let i = 12; i < 28; i++) { - if (data[i] === 0) - break; - name += String.fromCharCode(data[i]); - } - const flags = data[28] | (data[29] << 8) | (data[30] << 16) | (data[31] << 24); - // Get type and subtype names - const typeName = PARTITION_TYPES[type] || `unknown(0x${type.toString(16)})`; - let subtypeName = ""; - if (type === 0x00) { - subtypeName = APP_SUBTYPES[subtype] || `unknown(0x${subtype.toString(16)})`; - } - else if (type === 0x01) { - subtypeName = - DATA_SUBTYPES[subtype] || `unknown(0x${subtype.toString(16)})`; - } - else { - subtypeName = `0x${subtype.toString(16)}`; - } - return { - name, - type, - subtype, - offset, - size, - flags, - typeName, - subtypeName, - }; -} -/** - * Parse the entire partition table - */ -function parsePartitionTable(data) { - const partitions = []; - for (let i = 0; i < data.length; i += PARTITION_ENTRY_SIZE) { - const entryData = data.slice(i, i + PARTITION_ENTRY_SIZE); - const partition = parsePartitionEntry(entryData); - if (partition === null) { - // End of partition table or invalid entry - break; - } - partitions.push(partition); - } - return partitions; -} -/** - * Format size in human-readable format - */ -function formatSize(bytes) { - if (bytes < 1024) { - return `${bytes} B`; - } - else if (bytes < 1024 * 1024) { - return `${(bytes / 1024).toFixed(2)} KB`; - } - else { - return `${(bytes / (1024 * 1024)).toFixed(2)} MB`; - } -} - -/** - * SPIFFS Build Configuration - * Based on ESP-IDF spiffsgen.py - */ -const SPIFFS_PH_FLAG_USED_FINAL_INDEX = 0xf8; -const SPIFFS_PH_FLAG_USED_FINAL = 0xfc; -const SPIFFS_PH_FLAG_LEN = 1; -const SPIFFS_PH_IX_SIZE_LEN = 4; -const SPIFFS_PH_IX_OBJ_TYPE_LEN = 1; -const SPIFFS_TYPE_FILE = 1; -// Based on typedefs under spiffs_config.h -const SPIFFS_OBJ_ID_LEN = 2; // spiffs_obj_id -const SPIFFS_SPAN_IX_LEN = 2; // spiffs_span_ix -const SPIFFS_PAGE_IX_LEN = 2; // spiffs_page_ix -const SPIFFS_BLOCK_IX_LEN = 2; // spiffs_block_ix -class SpiffsBuildConfig { - constructor(options) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m; - if (options.blockSize % options.pageSize !== 0) { - throw new Error("block size should be a multiple of page size"); - } - this.pageSize = options.pageSize; - this.blockSize = options.blockSize; - this.objIdLen = (_a = options.objIdLen) !== null && _a !== void 0 ? _a : SPIFFS_OBJ_ID_LEN; - this.spanIxLen = (_b = options.spanIxLen) !== null && _b !== void 0 ? _b : SPIFFS_SPAN_IX_LEN; - this.packed = (_c = options.packed) !== null && _c !== void 0 ? _c : true; - this.aligned = (_d = options.aligned) !== null && _d !== void 0 ? _d : true; - this.objNameLen = (_e = options.objNameLen) !== null && _e !== void 0 ? _e : 32; - this.metaLen = (_f = options.metaLen) !== null && _f !== void 0 ? _f : 4; - this.pageIxLen = (_g = options.pageIxLen) !== null && _g !== void 0 ? _g : SPIFFS_PAGE_IX_LEN; - this.blockIxLen = (_h = options.blockIxLen) !== null && _h !== void 0 ? _h : SPIFFS_BLOCK_IX_LEN; - this.endianness = (_j = options.endianness) !== null && _j !== void 0 ? _j : "little"; - this.useMagic = (_k = options.useMagic) !== null && _k !== void 0 ? _k : true; - this.useMagicLen = (_l = options.useMagicLen) !== null && _l !== void 0 ? _l : true; - this.alignedObjIxTables = (_m = options.alignedObjIxTables) !== null && _m !== void 0 ? _m : false; - this.PAGES_PER_BLOCK = Math.floor(this.blockSize / this.pageSize); - this.OBJ_LU_PAGES_PER_BLOCK = Math.ceil(((this.blockSize / this.pageSize) * this.objIdLen) / this.pageSize); - this.OBJ_USABLE_PAGES_PER_BLOCK = - this.PAGES_PER_BLOCK - this.OBJ_LU_PAGES_PER_BLOCK; - this.OBJ_LU_PAGES_OBJ_IDS_LIM = Math.floor(this.pageSize / this.objIdLen); - this.OBJ_DATA_PAGE_HEADER_LEN = - this.objIdLen + this.spanIxLen + SPIFFS_PH_FLAG_LEN; - const pad = 4 - - (this.OBJ_DATA_PAGE_HEADER_LEN % 4 === 0 - ? 4 - : this.OBJ_DATA_PAGE_HEADER_LEN % 4); - this.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED = this.OBJ_DATA_PAGE_HEADER_LEN + pad; - this.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD = pad; - this.OBJ_DATA_PAGE_CONTENT_LEN = - this.pageSize - this.OBJ_DATA_PAGE_HEADER_LEN; - this.OBJ_INDEX_PAGES_HEADER_LEN = - this.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED + - SPIFFS_PH_IX_SIZE_LEN + - SPIFFS_PH_IX_OBJ_TYPE_LEN + - this.objNameLen + - this.metaLen; - if (this.alignedObjIxTables) { - this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = - (this.OBJ_INDEX_PAGES_HEADER_LEN + SPIFFS_PAGE_IX_LEN - 1) & - -2; - this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = - this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED - - this.OBJ_INDEX_PAGES_HEADER_LEN; - } - else { - this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = this.OBJ_INDEX_PAGES_HEADER_LEN; - this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = 0; - } - this.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM = Math.floor((this.pageSize - this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED) / - this.blockIxLen); - this.OBJ_INDEX_PAGES_OBJ_IDS_LIM = Math.floor((this.pageSize - this.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED) / this.blockIxLen); - } -} -class SpiffsFullError extends Error { - constructor(message = "SPIFFS is full") { - super(message); - this.name = "SpiffsFullError"; - } -} - -/** - * SPIFFS Page Classes - * Based on ESP-IDF spiffsgen.py - */ -class SpiffsPage { - constructor(bix, buildConfig) { - this.buildConfig = buildConfig; - this.bix = bix; - } - pack(format, ...values) { - const buffer = new ArrayBuffer(this.calcSize(format)); - const view = new DataView(buffer); - let offset = 0; - for (let i = 0; i < format.length; i++) { - const type = format[i]; - const value = values[i]; - switch (type) { - case "B": // unsigned char (1 byte) - view.setUint8(offset, value); - offset += 1; - break; - case "H": // unsigned short (2 bytes) - if (this.buildConfig.endianness === "little") { - view.setUint16(offset, value, true); - } - else { - view.setUint16(offset, value, false); - } - offset += 2; - break; - case "I": // unsigned int (4 bytes) - if (this.buildConfig.endianness === "little") { - view.setUint32(offset, value, true); - } - else { - view.setUint32(offset, value, false); - } - offset += 4; - break; - } - } - return new Uint8Array(buffer); - } - unpack(format, data, offset = 0) { - const view = new DataView(data.buffer, data.byteOffset + offset); - const results = []; - let pos = 0; - for (const type of format) { - switch (type) { - case "B": - results.push(view.getUint8(pos)); - pos += 1; - break; - case "H": - results.push(this.buildConfig.endianness === "little" - ? view.getUint16(pos, true) - : view.getUint16(pos, false)); - pos += 2; - break; - case "I": - results.push(this.buildConfig.endianness === "little" - ? view.getUint32(pos, true) - : view.getUint32(pos, false)); - pos += 4; - break; - } - } - return results; - } - calcSize(format) { - let size = 0; - for (const type of format) { - switch (type) { - case "B": - size += 1; - break; - case "H": - size += 2; - break; - case "I": - size += 4; - break; - } - } - return size; - } -} -class SpiffsObjPageWithIdx extends SpiffsPage { - constructor(objId, buildConfig) { - super(0, buildConfig); - this.objId = objId; - } - getObjId() { - return this.objId; - } -} -class SpiffsObjLuPage extends SpiffsPage { - constructor(bix, buildConfig) { - super(bix, buildConfig); - this.objIdsLimit = this.buildConfig.OBJ_LU_PAGES_OBJ_IDS_LIM; - this.objIds = []; - } - calcMagic(blocksLim) { - let magic = 0x20140529 ^ this.buildConfig.pageSize; - if (this.buildConfig.useMagicLen) { - magic = magic ^ (blocksLim - this.bix); - } - const mask = (1 << (8 * this.buildConfig.objIdLen)) - 1; - return magic & mask; - } - registerPage(page) { - if (this.objIdsLimit <= 0) { - throw new SpiffsFullError(); - } - const pageType = page instanceof SpiffsObjIndexPage ? "index" : "data"; - this.objIds.push([page.getObjId(), pageType]); - this.objIdsLimit--; - } - toBinary() { - const img = new Uint8Array(this.buildConfig.pageSize); - img.fill(0xff); - let offset = 0; - for (const [objId, pageType] of this.objIds) { - let id = objId; - if (pageType === "index") { - id ^= 1 << (this.buildConfig.objIdLen * 8 - 1); - } - const packed = this.pack(this.buildConfig.objIdLen === 1 - ? "B" - : this.buildConfig.objIdLen === 2 - ? "H" - : "I", id); - img.set(packed, offset); - offset += packed.length; - } - return img; - } - magicfy(blocksLim) { - const remaining = this.objIdsLimit; - const emptyObjId = (1 << (this.buildConfig.objIdLen * 8)) - 1; - if (remaining >= 2) { - for (let i = 0; i < remaining; i++) { - if (i === remaining - 2) { - this.objIds.push([this.calcMagic(blocksLim), "data"]); - break; - } - else { - this.objIds.push([emptyObjId, "data"]); - } - this.objIdsLimit--; - } - } - } -} -class SpiffsObjIndexPage extends SpiffsObjPageWithIdx { - constructor(objId, spanIx, size, name, buildConfig) { - super(objId, buildConfig); - this.spanIx = spanIx; - this.name = name; - this.size = size; - if (this.spanIx === 0) { - this.pagesLim = this.buildConfig.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM; - } - else { - this.pagesLim = this.buildConfig.OBJ_INDEX_PAGES_OBJ_IDS_LIM; - } - this.pages = []; - } - registerPage(page) { - if (this.pagesLim <= 0) { - throw new SpiffsFullError(); - } - this.pages.push(page.offset); - this.pagesLim--; - } - toBinary() { - const img = new Uint8Array(this.buildConfig.pageSize); - img.fill(0xff); - const objId = this.objId ^ (1 << (this.buildConfig.objIdLen * 8 - 1)); - const format = (this.buildConfig.objIdLen === 1 - ? "B" - : this.buildConfig.objIdLen === 2 - ? "H" - : "I") + - (this.buildConfig.spanIxLen === 1 - ? "B" - : this.buildConfig.spanIxLen === 2 - ? "H" - : "I") + - "B"; - let offset = 0; - const header = this.pack(format, objId, this.spanIx, SPIFFS_PH_FLAG_USED_FINAL_INDEX); - img.set(header, offset); - offset += header.length; - // Add padding - offset += this.buildConfig.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD; - // If first index page, add filename, type and size - if (this.spanIx === 0) { - const sizeType = this.pack("IB", this.size, SPIFFS_TYPE_FILE); - img.set(sizeType, offset); - offset += sizeType.length; - // Write filename with proper null-termination - const nameBytes = new TextEncoder().encode(this.name); - // Ensure we don't exceed objNameLen - const bytesToWrite = Math.min(nameBytes.length, this.buildConfig.objNameLen); - img.set(nameBytes.slice(0, bytesToWrite), offset); - // The rest is already 0xFF from img.fill(0xff), but SPIFFS expects 0x00 for unused name bytes - // Fill remaining name bytes with 0x00 - for (let i = bytesToWrite; i < this.buildConfig.objNameLen; i++) { - img[offset + i] = 0x00; - } - offset += - this.buildConfig.objNameLen + - this.buildConfig.metaLen + - this.buildConfig.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD; - } - // Add page indices - for (const page of this.pages) { - // Calculate page index by dividing page offset by page size - // pageSize is always a power of 2, so integer division is safe - const pageIx = Math.floor(page / this.buildConfig.pageSize); - const pageIxPacked = this.pack(this.buildConfig.pageIxLen === 1 - ? "B" - : this.buildConfig.pageIxLen === 2 - ? "H" - : "I", pageIx); - img.set(pageIxPacked, offset); - offset += pageIxPacked.length; - } - return img; - } -} -class SpiffsObjDataPage extends SpiffsObjPageWithIdx { - constructor(offset, objId, spanIx, contents, buildConfig) { - super(objId, buildConfig); - this.offset = offset; - this.spanIx = spanIx; - this.contents = contents; - } - toBinary() { - const img = new Uint8Array(this.buildConfig.pageSize); - img.fill(0xff); - const format = (this.buildConfig.objIdLen === 1 - ? "B" - : this.buildConfig.objIdLen === 2 - ? "H" - : "I") + - (this.buildConfig.spanIxLen === 1 - ? "B" - : this.buildConfig.spanIxLen === 2 - ? "H" - : "I") + - "B"; - const header = this.pack(format, this.objId, this.spanIx, SPIFFS_PH_FLAG_USED_FINAL); - img.set(header, 0); - img.set(this.contents, header.length); - return img; - } -} - -/** - * SPIFFS Block Class - * Based on ESP-IDF spiffsgen.py - */ -class SpiffsBlock { - constructor(bix, buildConfig) { - this.buildConfig = buildConfig; - this.offset = bix * this.buildConfig.blockSize; - this.remainingPages = this.buildConfig.OBJ_USABLE_PAGES_PER_BLOCK; - this.pages = []; - this.bix = bix; - this.luPages = []; - for (let i = 0; i < this.buildConfig.OBJ_LU_PAGES_PER_BLOCK; i++) { - const page = new SpiffsObjLuPage(this.bix, this.buildConfig); - this.luPages.push(page); - } - this.pages.push(...this.luPages); - this.luPageIter = this.luPages[Symbol.iterator](); - this.luPage = this.luPageIter.next().value || null; - this.curObjIndexSpanIx = 0; - this.curObjDataSpanIx = 0; - this.curObjId = 0; - this.curObjIdxPage = null; - } - reset() { - this.curObjIndexSpanIx = 0; - this.curObjDataSpanIx = 0; - this.curObjId = 0; - this.curObjIdxPage = null; - } - registerPage(page) { - if (page instanceof SpiffsObjDataPage) { - if (!this.curObjIdxPage) { - throw new Error("No current object index page"); - } - this.curObjIdxPage.registerPage(page); - } - try { - if (!this.luPage) { - throw new SpiffsFullError(); - } - this.luPage.registerPage(page); - } - catch (e) { - if (e instanceof SpiffsFullError) { - const next = this.luPageIter.next(); - if (next.done) { - throw new Error("Invalid attempt to add page to a block when there is no more space in lookup"); - } - this.luPage = next.value; - this.luPage.registerPage(page); - } - else { - throw e; - } - } - this.pages.push(page); - } - beginObj(objId, size, name, objIndexSpanIx = 0, objDataSpanIx = 0) { - if (this.remainingPages <= 0) { - throw new SpiffsFullError(); - } - this.reset(); - this.curObjId = objId; - this.curObjIndexSpanIx = objIndexSpanIx; - this.curObjDataSpanIx = objDataSpanIx; - const page = new SpiffsObjIndexPage(objId, this.curObjIndexSpanIx, size, name, this.buildConfig); - this.registerPage(page); - this.curObjIdxPage = page; - this.remainingPages--; - this.curObjIndexSpanIx++; - } - updateObj(contents) { - if (this.remainingPages <= 0) { - throw new SpiffsFullError(); - } - const page = new SpiffsObjDataPage(this.offset + this.pages.length * this.buildConfig.pageSize, this.curObjId, this.curObjDataSpanIx, contents, this.buildConfig); - this.registerPage(page); - this.curObjDataSpanIx++; - this.remainingPages--; - } - endObj() { - this.reset(); - } - isFull() { - return this.remainingPages <= 0; - } - toBinary(blocksLim) { - const img = new Uint8Array(this.buildConfig.blockSize); - img.fill(0xff); - let offset = 0; - if (this.buildConfig.useMagic) { - for (let idx = 0; idx < this.pages.length; idx++) { - const page = this.pages[idx]; - if (idx === this.buildConfig.OBJ_LU_PAGES_PER_BLOCK - 1) { - if (page instanceof SpiffsObjLuPage) { - page.magicfy(blocksLim); - } - } - const pageBinary = page.toBinary(); - img.set(pageBinary, offset); - offset += pageBinary.length; - } - } - else { - for (const page of this.pages) { - const pageBinary = page.toBinary(); - img.set(pageBinary, offset); - offset += pageBinary.length; - } - } - return img; - } - get currentObjIndexSpanIx() { - return this.curObjIndexSpanIx; - } - get currentObjDataSpanIx() { - return this.curObjDataSpanIx; - } - get currentObjId() { - return this.curObjId; - } - get currentObjIdxPage() { - return this.curObjIdxPage; - } - set currentObjId(value) { - this.curObjId = value; - } - set currentObjIdxPage(value) { - this.curObjIdxPage = value; - } - set currentObjDataSpanIx(value) { - this.curObjDataSpanIx = value; - } - set currentObjIndexSpanIx(value) { - this.curObjIndexSpanIx = value; - } -} - -/** - * SPIFFS Filesystem Implementation - * Based on ESP-IDF spiffsgen.py - */ -class SpiffsFS { - constructor(imgSize, buildConfig) { - if (imgSize % buildConfig.blockSize !== 0) { - throw new Error("image size should be a multiple of block size"); - } - this.imgSize = imgSize; - this.buildConfig = buildConfig; - this.blocks = []; - this.blocksLim = Math.floor(this.imgSize / this.buildConfig.blockSize); - this.remainingBlocks = this.blocksLim; - this.curObjId = 1; // starting object id - } - createBlock() { - if (this.isFull()) { - throw new SpiffsFullError("the image size has been exceeded"); - } - const block = new SpiffsBlock(this.blocks.length, this.buildConfig); - this.blocks.push(block); - this.remainingBlocks--; - return block; - } - isFull() { - return this.remainingBlocks <= 0; - } - createFile(imgPath, contents) { - if (imgPath.length > this.buildConfig.objNameLen) { - throw new Error(`object name '${imgPath}' too long`); - } - const name = imgPath; - let offset = 0; - try { - const block = this.blocks[this.blocks.length - 1]; - block.beginObj(this.curObjId, contents.length, name); - } - catch { - const block = this.createBlock(); - block.beginObj(this.curObjId, contents.length, name); - } - while (offset < contents.length) { - const chunkSize = Math.min(this.buildConfig.OBJ_DATA_PAGE_CONTENT_LEN, contents.length - offset); - const contentsChunk = contents.slice(offset, offset + chunkSize); - try { - const block = this.blocks[this.blocks.length - 1]; - try { - block.updateObj(contentsChunk); - } - catch (e) { - if (e instanceof SpiffsFullError) { - if (block.isFull()) { - throw e; - } - // Object index exhausted, write another object index page - block.beginObj(this.curObjId, contents.length, name, block.currentObjIndexSpanIx, block.currentObjDataSpanIx); - continue; - } - throw e; - } - } - catch (e) { - if (e instanceof SpiffsFullError) { - // All pages in block exhausted, create new block - const prevBlock = this.blocks[this.blocks.length - 1]; - const block = this.createBlock(); - block.currentObjId = prevBlock.currentObjId; - block.currentObjIdxPage = prevBlock.currentObjIdxPage; - block.currentObjDataSpanIx = prevBlock.currentObjDataSpanIx; - block.currentObjIndexSpanIx = prevBlock.currentObjIndexSpanIx; - continue; - } - throw e; - } - offset += chunkSize; - } - const block = this.blocks[this.blocks.length - 1]; - block.endObj(); - this.curObjId++; - } - toBinary() { - const allBlocks = []; - for (const block of this.blocks) { - allBlocks.push(block.toBinary(this.blocksLim)); - } - let bix = this.blocks.length; - let remaining = this.remainingBlocks; - if (this.buildConfig.useMagic) { - // Create empty blocks with magic numbers - while (remaining > 0) { - const block = new SpiffsBlock(bix, this.buildConfig); - allBlocks.push(block.toBinary(this.blocksLim)); - remaining--; - bix++; - } - } - else { - // Fill remaining space with 0xFF - const remainingSize = this.imgSize - allBlocks.length * this.buildConfig.blockSize; - if (remainingSize > 0) { - const padding = new Uint8Array(remainingSize); - padding.fill(0xff); - allBlocks.push(padding); - } - } - // Concatenate all blocks - const totalSize = allBlocks.reduce((sum, block) => sum + block.length, 0); - const img = new Uint8Array(totalSize); - let offset = 0; - for (const block of allBlocks) { - img.set(block, offset); - offset += block.length; - } - return img; - } - listFiles() { - // This would require parsing the blocks - implement in fromBinary - throw new Error("listFiles requires fromBinary to be called first"); - } - readFile() { - // This would require parsing the blocks - implement in fromBinary - throw new Error("readFile requires fromBinary to be called first"); - } - deleteFile() { - // SPIFFS doesn't support in-place deletion - // Need to recreate filesystem without the file - throw new Error("deleteFile not yet implemented - requires filesystem recreation"); - } -} - -/** - * SPIFFS Reader - Parse and extract files from SPIFFS images - * Based on ESP-IDF spiffsgen.py extract_files() method - */ -class SpiffsReader { - constructor(imageData, buildConfig) { - this.imageData = imageData; - this.buildConfig = buildConfig; - this.filesMap = new Map(); - } - unpack(format, data, offset = 0) { - const view = new DataView(data.buffer, data.byteOffset + offset); - const results = []; - let pos = 0; - for (const type of format) { - switch (type) { - case "B": - results.push(view.getUint8(pos)); - pos += 1; - break; - case "H": - results.push(this.buildConfig.endianness === "little" - ? view.getUint16(pos, true) - : view.getUint16(pos, false)); - pos += 2; - break; - case "I": - results.push(this.buildConfig.endianness === "little" - ? view.getUint32(pos, true) - : view.getUint32(pos, false)); - pos += 4; - break; - } - } - return results; - } - parse() { - const blocksCount = Math.floor(this.imageData.length / this.buildConfig.blockSize); - for (let bix = 0; bix < blocksCount; bix++) { - const blockOffset = bix * this.buildConfig.blockSize; - const blockData = this.imageData.slice(blockOffset, blockOffset + this.buildConfig.blockSize); - this.parseBlock(blockData); - } - } - parseBlock(blockData) { - // Parse lookup pages to find valid objects - for (let pageIdx = 0; pageIdx < this.buildConfig.OBJ_LU_PAGES_PER_BLOCK; pageIdx++) { - const luPageOffset = pageIdx * this.buildConfig.pageSize; - const luPageData = blockData.slice(luPageOffset, luPageOffset + this.buildConfig.pageSize); - // Parse object IDs from lookup page - for (let i = 0; i < luPageData.length; i += this.buildConfig.objIdLen) { - if (i + this.buildConfig.objIdLen > luPageData.length) - break; - const objIdBytes = luPageData.slice(i, i + this.buildConfig.objIdLen); - const [objId] = this.unpack(this.buildConfig.objIdLen === 1 - ? "B" - : this.buildConfig.objIdLen === 2 - ? "H" - : "I", objIdBytes); - // Check if it's a valid object (not erased/empty) - const emptyValue = (1 << (this.buildConfig.objIdLen * 8)) - 1; - if (objId === emptyValue) - continue; - // Check if it's an index page (MSB set) - const isIndex = (objId & (1 << (this.buildConfig.objIdLen * 8 - 1))) !== 0; - const realObjId = objId & ~(1 << (this.buildConfig.objIdLen * 8 - 1)); - if (isIndex && !this.filesMap.has(realObjId)) { - this.filesMap.set(realObjId, { - name: null, - size: 0, - dataPages: [], - }); - } - } - } - // Parse actual pages to get file metadata and content - for (let pageIdx = this.buildConfig.OBJ_LU_PAGES_PER_BLOCK; pageIdx < this.buildConfig.PAGES_PER_BLOCK; pageIdx++) { - const pageOffset = pageIdx * this.buildConfig.pageSize; - const pageData = blockData.slice(pageOffset, pageOffset + this.buildConfig.pageSize); - this.parsePage(pageData); - } - } - parsePage(pageData) { - // Parse page header - const headerFormat = (this.buildConfig.objIdLen === 1 - ? "B" - : this.buildConfig.objIdLen === 2 - ? "H" - : "I") + - (this.buildConfig.spanIxLen === 1 - ? "B" - : this.buildConfig.spanIxLen === 2 - ? "H" - : "I") + - "B"; - const headerSize = this.buildConfig.objIdLen + - this.buildConfig.spanIxLen + - SPIFFS_PH_FLAG_LEN; - if (pageData.length < headerSize) - return; - const [objId, spanIx, flags] = this.unpack(headerFormat, pageData); - // Check for valid page - const emptyId = (1 << (this.buildConfig.objIdLen * 8)) - 1; - if (objId === emptyId) - return; - const isIndex = (objId & (1 << (this.buildConfig.objIdLen * 8 - 1))) !== 0; - const realObjId = objId & ~(1 << (this.buildConfig.objIdLen * 8 - 1)); - if (isIndex && flags === SPIFFS_PH_FLAG_USED_FINAL_INDEX) { - // Index page - contains file metadata - if (!this.filesMap.has(realObjId)) { - this.filesMap.set(realObjId, { - name: null, - size: 0, - dataPages: [], - }); - } - // Only first index page (span_ix == 0) has filename and size - if (spanIx === 0) { - this.parseIndexPage(pageData, headerSize, realObjId); - } - } - else if (!isIndex && flags === SPIFFS_PH_FLAG_USED_FINAL) { - // Data page - contains file content - if (this.filesMap.has(realObjId)) { - const contentStart = headerSize; - const content = pageData.slice(contentStart, contentStart + this.buildConfig.OBJ_DATA_PAGE_CONTENT_LEN); - this.filesMap.get(realObjId).dataPages.push([spanIx, content]); - } - } - } - parseIndexPage(pageData, headerSize, objId) { - // Skip to size and type fields - let offset = headerSize + this.buildConfig.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD; - const sizeTypeFormat = "IB"; - const sizeTypeSize = SPIFFS_PH_IX_SIZE_LEN + SPIFFS_PH_IX_OBJ_TYPE_LEN; - if (offset + sizeTypeSize <= pageData.length) { - const [fileSize] = this.unpack(sizeTypeFormat, pageData, offset); - offset += sizeTypeSize; - // Read filename - const nameEnd = offset + this.buildConfig.objNameLen; - if (nameEnd <= pageData.length) { - const nameBytes = pageData.slice(offset, nameEnd); - // Find null terminator - const nullPos = nameBytes.indexOf(0); - const actualNameBytes = nullPos !== -1 ? nameBytes.slice(0, nullPos) : nameBytes; - const filename = new TextDecoder().decode(actualNameBytes); - const fileInfo = this.filesMap.get(objId); - fileInfo.name = filename; - fileInfo.size = fileSize; - } - } - } - listFiles() { - const files = []; - for (const [, fileInfo] of this.filesMap) { - if (fileInfo.name === null) - continue; - // Sort data pages by span index - fileInfo.dataPages.sort((a, b) => a[0] - b[0]); - // Reconstruct file content - const chunks = []; - let totalWritten = 0; - for (const [, content] of fileInfo.dataPages) { - const remaining = fileInfo.size - totalWritten; - if (remaining <= 0) - break; - const toWrite = Math.min(content.length, remaining); - chunks.push(content.slice(0, toWrite)); - totalWritten += toWrite; - } - // Concatenate chunks - const data = new Uint8Array(totalWritten); - let offset = 0; - for (const chunk of chunks) { - data.set(chunk, offset); - offset += chunk.length; - } - files.push({ - name: fileInfo.name, - size: fileInfo.size, - data, - }); - } - return files; - } - readFile(path) { - const files = this.listFiles(); - const file = files.find((f) => f.name === path || f.name === "/" + path); - return file ? file.data : null; - } -} - -/** - * SPIFFS Module Entry Point - */ -// Default ESP32 SPIFFS configuration -const DEFAULT_SPIFFS_CONFIG = { - pageSize: 256, - blockSize: 4096, - objNameLen: 32, - metaLen: 4, - useMagic: true, - useMagicLen: true, - alignedObjIxTables: false, -}; - -/// -const connect = async (logger) => { - // - Request a port and open a connection. - // Try to use requestSerialPort if available (supports WebUSB for Android) - let port; - const customRequestPort = globalThis.requestSerialPort; - if (typeof customRequestPort === "function") { - port = await customRequestPort(); - } - else { - // Check if Web Serial API is available - if (!navigator.serial) { - throw new Error("Web Serial API is not supported in this browser. " + - "Please use Chrome, Edge, or Opera on desktop, or Chrome on Android. " + - "Note: The page must be served over HTTPS or localhost."); - } - port = await navigator.serial.requestPort(); - } - // Only open if not already open (requestSerialPort may return an opened port) - if (!port.readable || !port.writable) { - await port.open({ baudRate: ESP_ROM_BAUD }); - } - return new ESPLoader(port, logger); -}; -const connectWithPort = async (port, logger) => { - // Connect using an already opened port (useful for WebUSB wrapper) - if (!port) { - throw new Error("Port is required"); - } - // Check if port is already open, if not open it - if (!port.readable || !port.writable) { - await port.open({ baudRate: ESP_ROM_BAUD }); - } - return new ESPLoader(port, logger); -}; - -export { CHIP_ERASE_TIMEOUT, CHIP_FAMILY_ESP32, CHIP_FAMILY_ESP32C2, CHIP_FAMILY_ESP32C3, CHIP_FAMILY_ESP32C5, CHIP_FAMILY_ESP32C6, CHIP_FAMILY_ESP32C61, CHIP_FAMILY_ESP32H2, CHIP_FAMILY_ESP32H21, CHIP_FAMILY_ESP32H4, CHIP_FAMILY_ESP32P4, CHIP_FAMILY_ESP32S2, CHIP_FAMILY_ESP32S3, CHIP_FAMILY_ESP32S31, CHIP_FAMILY_ESP8266, DEFAULT_SPIFFS_CONFIG, DEFAULT_TIMEOUT, ERASE_REGION_TIMEOUT_PER_MB, ESP8266_LITTLEFS_BLOCK_SIZE, ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES, ESP8266_LITTLEFS_PAGE_SIZE, ESP8266_SPIFFS_BLOCK_SIZE, ESP8266_SPIFFS_PAGE_SIZE, ESPLoader, ESP_CHANGE_BAUDRATE, ESP_CHECKSUM_MAGIC, ESP_ERASE_FLASH, ESP_ERASE_REGION, ESP_FLASH_BEGIN, ESP_FLASH_DATA, ESP_FLASH_DEFL_BEGIN, ESP_FLASH_DEFL_DATA, ESP_FLASH_DEFL_END, ESP_FLASH_END, ESP_GET_SECURITY_INFO, ESP_MEM_BEGIN, ESP_MEM_DATA, ESP_MEM_END, ESP_RAM_BLOCK, ESP_READ_FLASH, ESP_READ_REG, ESP_SPI_ATTACH, ESP_SPI_FLASH_MD5, ESP_SPI_SET_PARAMS, ESP_SYNC, ESP_WRITE_REG, FATFS_BLOCK_SIZE_CANDIDATES, FATFS_DEFAULT_BLOCK_SIZE, FLASH_READ_TIMEOUT, FilesystemType, LITTLEFS_BLOCK_SIZE_CANDIDATES, LITTLEFS_DEFAULT_BLOCK_SIZE, MAX_TIMEOUT, MEM_END_ROM_TIMEOUT, ROM_INVALID_RECV_MSG, SYNC_TIMEOUT, SpiffsBuildConfig, SpiffsFS, SpiffsReader, USB_RAM_BLOCK, connect, connectWithPort, detectFilesystemFromImage, detectFilesystemType, formatMacAddr, formatSize, getBlockSizeCandidates, getDefaultBlockSize, getESP8266FilesystemLayout, hexFormatter, parsePartitionTable, scanESP8266Filesystem, sleep, toHex }; +const t=t=>{let e=[192];for(const i of t)219==i?e=e.concat([219,221]):192==i?e=e.concat([219,220]):e.push(i);return e.push(192),e},e=t=>{const e=[];for(let i=0;i"["+t.map(t=>s(t)).join(", ")+"]",s=(t,e=2)=>{const i=t.toString(16).toUpperCase();return i.startsWith("-")?"-0x"+i.substring(1).padStart(e,"0"):"0x"+i.padStart(e,"0")},a=t=>t.map(t=>t.toString(16).toUpperCase().padStart(2,"0")).join(":");const r=t=>new Promise(e=>setTimeout(e,t)),n={18:"256KB",19:"512KB",20:"1MB",21:"2MB",22:"4MB",23:"8MB",24:"16MB",25:"32MB",26:"64MB",27:"128MB",28:"256MB",32:"64MB",33:"128MB",34:"256MB",50:"256KB",51:"512KB",52:"1MB",53:"2MB",54:"4MB",55:"8MB",56:"16MB",57:"32MB",58:"64MB"},o=4096,h=115200,l=1073061888,d=1061265408,c=1610641408,u=1610647552,g=1611352064,f=1611335680,_=1611352064,p=1611335680,b=1343410176,w=1343312316,m=1<<27,y=1343312312,S=1343312892,B=544296960,I=e(" UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"),R=33382,v=50,C=12882,E=12883,k=12994,x=12995,U=12997,M=12998,D=207969,O=12914,A=12916,F=12917,T=12928,L=12849,z={5:{name:"ESP32-C3",family:x},9:{name:"ESP32-S3",family:E},12:{name:"ESP32-C2",family:k},13:{name:"ESP32-C6",family:M},16:{name:"ESP32-H2",family:O},18:{name:"ESP32-P4",family:T},20:{name:"ESP32-C61",family:D},23:{name:"ESP32-C5",family:U},25:{name:"ESP32-H21",family:F},28:{name:"ESP32-H4",family:A},32:{name:"ESP32-S31",family:L}},P={4293968129:{name:"ESP8266",family:R},15736195:{name:"ESP32",family:v},1990:{name:"ESP32-S2",family:C}},N=2,$=3,W=4,j=5,G=6,H=7,J=8,Q=9,V=10,Z=208,X=209,K=210,q=11,Y=13,tt=15,et=19,it=20,st=239,at=16,rt=17,nt=18,ot=5,ht=2048,lt=6144,dt=3e3,ct=15e4,ut=3e5,gt=100,ft=3e4,_t=500,pt=100,bt=(t,e)=>{const i=Math.floor(t*(e/486));return i{switch(t){case v:return{regBase:1072963584,baseFuse:l,macFuse:1073061888,usrOffs:28,usr1Offs:32,usr2Offs:36,mosiDlenOffs:40,misoDlenOffs:44,w0Offs:128,uartDateReg:1610612856,flashOffs:4096};case C:return{regBase:1061167104,baseFuse:d,macFuse:1061265476,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612856,flashOffs:4096};case E:return{regBase:1610620928,usrOffs:24,baseFuse:c,macFuse:1610641476,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612864,flashOffs:0};case R:return{regBase:1610613248,usrOffs:28,baseFuse:1072693328,macFuse:1072693328,usr1Offs:32,usr2Offs:36,mosiDlenOffs:-1,misoDlenOffs:-1,w0Offs:64,uartDateReg:1610612856,flashOffs:0};case k:return{regBase:1610620928,baseFuse:u,macFuse:1610647616,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case x:return{regBase:1610620928,baseFuse:1610647552,macFuse:1610647620,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case U:return{regBase:1610625024,baseFuse:g,macFuse:1611352132,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:8192};case M:return{regBase:1610625024,baseFuse:f,macFuse:1611335748,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case D:return{regBase:1610625024,baseFuse:_,macFuse:1611352132,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case O:return{regBase:1610625024,baseFuse:p,macFuse:1611335748,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case A:return{regBase:1611239424,baseFuse:1611339776,macFuse:1611339844,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610686588,flashOffs:8192};case F:return{regBase:1610625024,baseFuse:1611350016,macFuse:1611350084,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case T:return{regBase:1342754816,baseFuse:b,macFuse:1343410244,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1343004812,flashOffs:8192};case L:return{regBase:542113792,baseFuse:B,macFuse:544297028,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:540582028,flashOffs:8192};default:return{regBase:-1,baseFuse:-1,macFuse:-1,usrOffs:-1,usr1Offs:-1,usr2Offs:-1,mosiDlenOffs:-1,misoDlenOffs:-1,w0Offs:-1,uartDateReg:-1,flashOffs:-1}}};class mt extends Error{constructor(t){super(t),this.name="SlipReadError"}}const yt=async(t,i)=>{let s;if(t==A||t==F||t==L)return null;if(t==v)s=await import("./esp32-BRKoi17y.js");else if(t==C)s=await import("./esp32s2-iX3WoDbg.js");else if(t==E)s=await import("./esp32s3-DGwDVIgz.js");else if(t==R)s=await import("./esp8266-CUwxJpGa.js");else if(t==k)s=await import("./esp32c2-Btgr_lwh.js");else if(t==x)s=await import("./esp32c3-CHKfoI8W.js");else if(t==U)s=await import("./esp32c5-BDW4KtLo.js");else if(t==M)s=await import("./esp32c6-il8tTxAG.js");else if(t==D)s=await import("./esp32c61-thKzxBGf.js");else if(t==O)s=await import("./esp32h2-CxoUHv_P.js");else{if(t!=T)return null;s=null!=i&&i>=300?await import("./esp32p4r3-CqI71ojR.js"):await import("./esp32p4-D3jLP-jY.js")}return{...s,text:e(atob(s.text)),data:e(atob(s.data))}},St={239:"Winbond",200:"GigaDevice",157:"ISSI",194:"Macronix/MXIC",32:"XMC / Micron",28:"EON",133:"Puya",104:"BOYA",161:"Fudan Microelectronics (FM)",1:"Spansion/Cypress",94:"Zbit",55:"AMIC",224:"Berg Micro"},Bt={66073:"S25FL256S (256Mbit)",81941:"S25FL016K (16Mbit)",81942:"S25FL032K (32Mbit)",90135:"S25FL064L (64Mbit)",90136:"S25FL128L (128Mbit)",1847315:"EN25Q40 (4Mbit)",1847316:"EN25Q80A (8Mbit)",1847317:"EN25Q16 (16Mbit)",1847318:"EN25Q32B (32Mbit)",1847319:"EN25Q64 (64Mbit)",1847320:"EN25Q128 (128Mbit)",1863701:"EN25QH16 (16Mbit)",1863702:"EN25QH32 (32Mbit)",1863703:"EN25QH64 (64Mbit)",1863704:"EN25QH128 (128Mbit)",2113557:"XM25QH16C (16Mbit)",2113558:"XM25QH32B (32Mbit)",2113559:"XM25QH64C (64Mbit)",2113560:"XM25QH128C (128Mbit)",2113561:"XM25QH256C (256Mbit)",2113817:"XM25QU256C (256Mbit)",2125847:"XM25QH64A (64Mbit)",2125848:"XM25QH128A (128Mbit)",2144790:"N25Q032A (32Mbit)",2144791:"N25Q064A (64Mbit)",2144792:"N25Q128A (128Mbit)",2145045:"N25Q016A (16Mbit)",3612693:"A25L016 (16Mbit)",3612694:"A25L032 (32Mbit)",3620886:"A25LQ032 (32Mbit)",6176789:"ZB25VQ16 (16Mbit)",6176790:"ZB25VQ32 (32Mbit)",6176791:"ZB25VQ64 (64Mbit)",6176792:"ZB25VQ128 (128Mbit)",6832149:"BY25Q16 (16Mbit)",6832150:"BY25Q32 (32Mbit)",6832151:"BY25Q64 (64Mbit)",6832152:"BY25Q128 (128Mbit)",8740885:"P25Q16H (16Mbit)",8740886:"P25Q32H (32Mbit)",8740887:"P25Q64H (64Mbit)",8740888:"P25Q128H (128Mbit)",10313749:"IS25LP016 (16Mbit)",10313750:"IS25LP032 (32Mbit)",10313751:"IS25LP064 (64Mbit)",10313752:"IS25LP128 (128Mbit)",10313753:"IS25LP256 (256Mbit)",10317845:"IS25WP016 (16Mbit)",10317846:"IS25WP032 (32Mbit)",10317847:"IS25WP064 (64Mbit)",10317848:"IS25WP128 (128Mbit)",10317849:"IS25WP256 (256Mbit)",10567700:"FM25Q08 (8Mbit)",10567701:"FM25Q16 (16Mbit)",10567702:"FM25Q32 (32Mbit)",10567703:"FM25Q64 (64Mbit)",10567704:"FM25Q128 (128Mbit)",12722192:"MX25L512E (512Kbit)",12722193:"MX25L1005C (1Mbit)",12722194:"MX25L2005C (2Mbit)",12722195:"MX25L4005 (4Mbit)",12722196:"MX25L8005 (8Mbit)",12722197:"MX25L1605D (16Mbit)",12722198:"MX25L3205D (32Mbit)",12722199:"MX25L6405D (64Mbit)",12722200:"MX25L12805D (128Mbit)",12722201:"MX25L25635E (256Mbit)",12722202:"MX25L51245G (512Mbit)",12738070:"MX25L3233F (32Mbit)",13123601:"GD25Q10 (1Mbit)",13123602:"GD25Q20 (2Mbit)",13123603:"GD25Q40 (4Mbit)",13123604:"GD25Q80 (8Mbit)",13123605:"GD25Q16 (16Mbit)",13123606:"GD25Q32 (32Mbit)",13123607:"GD25Q64 (64Mbit)",13123608:"GD25Q127C (128Mbit)",13123609:"GD25Q256 (256Mbit)",13123616:"GD25Q512 (512Mbit)",13131801:"GD25LQ256D (256Mbit)",14696469:"BG25Q16A (16Mbit)",14696470:"BG25Q32 (32Mbit)",14696471:"BG25Q64 (64Mbit)",14696472:"BG25Q128 (128Mbit)",15679508:"W25Q80 (8Mbit)",15679509:"W25Q16 (16Mbit)",15679510:"W25Q32 (32Mbit)",15679511:"W25Q64 (64Mbit)",15679512:"W25Q128 (128Mbit)",15679513:"W25Q256 (256Mbit)",15679520:"W25Q512JV (512Mbit)",15683602:"W25Q20BW (2Mbit)",15683603:"W25Q40BW (4Mbit)",15687697:"W25Q10EW (1Mbit)",15687698:"W25Q20EW (2Mbit)",15687699:"W25Q40EW (4Mbit)"};function It(t){let e=t.length;for(;--e>=0;)t[e]=0}const Rt=256,vt=286,Ct=30,Et=15,kt=new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]),xt=new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]),Ut=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]),Mt=new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),Dt=new Array(576);It(Dt);const Ot=new Array(60);It(Ot);const At=new Array(512);It(At);const Ft=new Array(256);It(Ft);const Tt=new Array(29);It(Tt);const Lt=new Array(Ct);function zt(t,e,i,s,a){this.static_tree=t,this.extra_bits=e,this.extra_base=i,this.elems=s,this.max_length=a,this.has_stree=t&&t.length}let Pt,Nt,$t;function Wt(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}It(Lt);const jt=t=>t<256?At[t]:At[256+(t>>>7)],Gt=(t,e)=>{t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255},Ht=(t,e,i)=>{t.bi_valid>16-i?(t.bi_buf|=e<>16-t.bi_valid,t.bi_valid+=i-16):(t.bi_buf|=e<{Ht(t,i[2*e],i[2*e+1])},Qt=(t,e)=>{let i=0;do{i|=1&t,t>>>=1,i<<=1}while(--e>0);return i>>>1},Vt=(t,e,i)=>{const s=new Array(16);let a,r,n=0;for(a=1;a<=Et;a++)n=n+i[a-1]<<1,s[a]=n;for(r=0;r<=e;r++){let e=t[2*r+1];0!==e&&(t[2*r]=Qt(s[e]++,e))}},Zt=t=>{let e;for(e=0;e{t.bi_valid>8?Gt(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0},Kt=(t,e,i,s)=>{const a=2*e,r=2*i;return t[a]{const s=t.heap[i];let a=i<<1;for(;a<=t.heap_len&&(a{let s,a,r,n,o=0;if(0!==t.sym_next)do{s=255&t.pending_buf[t.sym_buf+o++],s+=(255&t.pending_buf[t.sym_buf+o++])<<8,a=t.pending_buf[t.sym_buf+o++],0===s?Jt(t,a,e):(r=Ft[a],Jt(t,r+Rt+1,e),n=kt[r],0!==n&&(a-=Tt[r],Ht(t,a,n)),s--,r=jt(s),Jt(t,r,i),n=xt[r],0!==n&&(s-=Lt[r],Ht(t,s,n)))}while(o{const i=e.dyn_tree,s=e.stat_desc.static_tree,a=e.stat_desc.has_stree,r=e.stat_desc.elems;let n,o,h,l=-1;for(t.heap_len=0,t.heap_max=573,n=0;n>1;n>=1;n--)qt(t,i,n);h=r;do{n=t.heap[1],t.heap[1]=t.heap[t.heap_len--],qt(t,i,1),o=t.heap[1],t.heap[--t.heap_max]=n,t.heap[--t.heap_max]=o,i[2*h]=i[2*n]+i[2*o],t.depth[h]=(t.depth[n]>=t.depth[o]?t.depth[n]:t.depth[o])+1,i[2*n+1]=i[2*o+1]=h,t.heap[1]=h++,qt(t,i,1)}while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],((t,e)=>{const i=e.dyn_tree,s=e.max_code,a=e.stat_desc.static_tree,r=e.stat_desc.has_stree,n=e.stat_desc.extra_bits,o=e.stat_desc.extra_base,h=e.stat_desc.max_length;let l,d,c,u,g,f,_=0;for(u=0;u<=Et;u++)t.bl_count[u]=0;for(i[2*t.heap[t.heap_max]+1]=0,l=t.heap_max+1;l<573;l++)d=t.heap[l],u=i[2*i[2*d+1]+1]+1,u>h&&(u=h,_++),i[2*d+1]=u,d>s||(t.bl_count[u]++,g=0,d>=o&&(g=n[d-o]),f=i[2*d],t.opt_len+=f*(u+g),r&&(t.static_len+=f*(a[2*d+1]+g)));if(0!==_){do{for(u=h-1;0===t.bl_count[u];)u--;t.bl_count[u]--,t.bl_count[u+1]+=2,t.bl_count[h]--,_-=2}while(_>0);for(u=h;0!==u;u--)for(d=t.bl_count[u];0!==d;)c=t.heap[--l],c>s||(i[2*c+1]!==u&&(t.opt_len+=(u-i[2*c+1])*i[2*c],i[2*c+1]=u),d--)}})(t,e),Vt(i,l,t.bl_count)},ee=(t,e,i)=>{let s,a,r=-1,n=e[1],o=0,h=7,l=4;for(0===n&&(h=138,l=3),e[2*(i+1)+1]=65535,s=0;s<=i;s++)a=n,n=e[2*(s+1)+1],++o{let s,a,r=-1,n=e[1],o=0,h=7,l=4;for(0===n&&(h=138,l=3),s=0;s<=i;s++)if(a=n,n=e[2*(s+1)+1],!(++o{Ht(t,0+(s?1:0),3),Xt(t),Gt(t,i),Gt(t,~i),i&&t.pending_buf.set(t.window.subarray(e,e+i),t.pending),t.pending+=i};var re=(t,e,i,s)=>{let a,r,n=0;t.level>0?(2===t.strm.data_type&&(t.strm.data_type=(t=>{let e,i=4093624447;for(e=0;e<=31;e++,i>>>=1)if(1&i&&0!==t.dyn_ltree[2*e])return 0;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return 1;for(e=32;e{let e;for(ee(t,t.dyn_ltree,t.l_desc.max_code),ee(t,t.dyn_dtree,t.d_desc.max_code),te(t,t.bl_desc),e=18;e>=3&&0===t.bl_tree[2*Mt[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e})(t),a=t.opt_len+3+7>>>3,r=t.static_len+3+7>>>3,r<=a&&(a=r)):a=r=i+5,i+4<=a&&-1!==e?ae(t,e,i,s):4===t.strategy||r===a?(Ht(t,2+(s?1:0),3),Yt(t,Dt,Ot)):(Ht(t,4+(s?1:0),3),((t,e,i,s)=>{let a;for(Ht(t,e-257,5),Ht(t,i-1,5),Ht(t,s-4,4),a=0;a{se||((()=>{let t,e,i,s,a;const r=new Array(16);for(i=0,s=0;s<28;s++)for(Tt[s]=i,t=0;t<1<>=7;s(t.pending_buf[t.sym_buf+t.sym_next++]=e,t.pending_buf[t.sym_buf+t.sym_next++]=e>>8,t.pending_buf[t.sym_buf+t.sym_next++]=i,0===e?t.dyn_ltree[2*i]++:(t.matches++,e--,t.dyn_ltree[2*(Ft[i]+Rt+1)]++,t.dyn_dtree[2*jt(e)]++),t.sym_next===t.sym_end),_tr_align:t=>{Ht(t,2,3),Jt(t,256,Dt),(t=>{16===t.bi_valid?(Gt(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)})(t)}};var oe=(t,e,i,s)=>{let a=65535&t,r=t>>>16&65535,n=0;for(;0!==i;){n=i>2e3?2e3:i,i-=n;do{a=a+e[s++]|0,r=r+a|0}while(--n);a%=65521,r%=65521}return a|r<<16};const he=new Uint32Array((()=>{let t,e=[];for(var i=0;i<256;i++){t=i;for(var s=0;s<8;s++)t=1&t?3988292384^t>>>1:t>>>1;e[i]=t}return e})());var le=(t,e,i,s)=>{const a=he,r=s+i;t^=-1;for(let i=s;i>>8^a[255&(t^e[i])];return-1^t},de={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"},ce={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_OK:0,Z_STREAM_END:1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_UNKNOWN:2,Z_DEFLATED:8};const{_tr_init:ue,_tr_stored_block:ge,_tr_flush_block:fe,_tr_tally:_e,_tr_align:pe}=ne,{Z_NO_FLUSH:be,Z_PARTIAL_FLUSH:we,Z_FULL_FLUSH:me,Z_FINISH:ye,Z_BLOCK:Se,Z_OK:Be,Z_STREAM_END:Ie,Z_STREAM_ERROR:Re,Z_DATA_ERROR:ve,Z_BUF_ERROR:Ce,Z_DEFAULT_COMPRESSION:Ee,Z_FILTERED:ke,Z_HUFFMAN_ONLY:xe,Z_RLE:Ue,Z_FIXED:Me,Z_DEFAULT_STRATEGY:De,Z_UNKNOWN:Oe,Z_DEFLATED:Ae}=ce,Fe=258,Te=262,Le=42,ze=113,Pe=666,Ne=(t,e)=>(t.msg=de[e],e),$e=t=>2*t-(t>4?9:0),We=t=>{let e=t.length;for(;--e>=0;)t[e]=0},je=t=>{let e,i,s,a=t.w_size;e=t.hash_size,s=e;do{i=t.head[--s],t.head[s]=i>=a?i-a:0}while(--e);e=a,s=e;do{i=t.prev[--s],t.prev[s]=i>=a?i-a:0}while(--e)};let Ge=(t,e,i)=>(e<{const e=t.state;let i=e.pending;i>t.avail_out&&(i=t.avail_out),0!==i&&(t.output.set(e.pending_buf.subarray(e.pending_out,e.pending_out+i),t.next_out),t.next_out+=i,e.pending_out+=i,t.total_out+=i,t.avail_out-=i,e.pending-=i,0===e.pending&&(e.pending_out=0))},Je=(t,e)=>{fe(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,He(t.strm)},Qe=(t,e)=>{t.pending_buf[t.pending++]=e},Ve=(t,e)=>{t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e},Ze=(t,e,i,s)=>{let a=t.avail_in;return a>s&&(a=s),0===a?0:(t.avail_in-=a,e.set(t.input.subarray(t.next_in,t.next_in+a),i),1===t.state.wrap?t.adler=oe(t.adler,e,a,i):2===t.state.wrap&&(t.adler=le(t.adler,e,a,i)),t.next_in+=a,t.total_in+=a,a)},Xe=(t,e)=>{let i,s,a=t.max_chain_length,r=t.strstart,n=t.prev_length,o=t.nice_match;const h=t.strstart>t.w_size-Te?t.strstart-(t.w_size-Te):0,l=t.window,d=t.w_mask,c=t.prev,u=t.strstart+Fe;let g=l[r+n-1],f=l[r+n];t.prev_length>=t.good_match&&(a>>=2),o>t.lookahead&&(o=t.lookahead);do{if(i=e,l[i+n]===f&&l[i+n-1]===g&&l[i]===l[r]&&l[++i]===l[r+1]){r+=2,i++;do{}while(l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&rn){if(t.match_start=e,n=s,s>=o)break;g=l[r+n-1],f=l[r+n]}}}while((e=c[e&d])>h&&0!==--a);return n<=t.lookahead?n:t.lookahead},Ke=t=>{const e=t.w_size;let i,s,a;do{if(s=t.window_size-t.lookahead-t.strstart,t.strstart>=e+(e-Te)&&(t.window.set(t.window.subarray(e,e+e-s),0),t.match_start-=e,t.strstart-=e,t.block_start-=e,t.insert>t.strstart&&(t.insert=t.strstart),je(t),s+=e),0===t.strm.avail_in)break;if(i=Ze(t.strm,t.window,t.strstart+t.lookahead,s),t.lookahead+=i,t.lookahead+t.insert>=3)for(a=t.strstart-t.insert,t.ins_h=t.window[a],t.ins_h=Ge(t,t.ins_h,t.window[a+1]);t.insert&&(t.ins_h=Ge(t,t.ins_h,t.window[a+3-1]),t.prev[a&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=a,a++,t.insert--,!(t.lookahead+t.insert<3)););}while(t.lookahead{let i,s,a,r=t.pending_buf_size-5>t.w_size?t.w_size:t.pending_buf_size-5,n=0,o=t.strm.avail_in;do{if(i=65535,a=t.bi_valid+42>>3,t.strm.avail_outs+t.strm.avail_in&&(i=s+t.strm.avail_in),i>a&&(i=a),i>8,t.pending_buf[t.pending-2]=~i,t.pending_buf[t.pending-1]=~i>>8,He(t.strm),s&&(s>i&&(s=i),t.strm.output.set(t.window.subarray(t.block_start,t.block_start+s),t.strm.next_out),t.strm.next_out+=s,t.strm.avail_out-=s,t.strm.total_out+=s,t.block_start+=s,i-=s),i&&(Ze(t.strm,t.strm.output,t.strm.next_out,i),t.strm.next_out+=i,t.strm.avail_out-=i,t.strm.total_out+=i)}while(0===n);return o-=t.strm.avail_in,o&&(o>=t.w_size?(t.matches=2,t.window.set(t.strm.input.subarray(t.strm.next_in-t.w_size,t.strm.next_in),0),t.strstart=t.w_size,t.insert=t.strstart):(t.window_size-t.strstart<=o&&(t.strstart-=t.w_size,t.window.set(t.window.subarray(t.w_size,t.w_size+t.strstart),0),t.matches<2&&t.matches++,t.insert>t.strstart&&(t.insert=t.strstart)),t.window.set(t.strm.input.subarray(t.strm.next_in-o,t.strm.next_in),t.strstart),t.strstart+=o,t.insert+=o>t.w_size-t.insert?t.w_size-t.insert:o),t.block_start=t.strstart),t.high_watera&&t.block_start>=t.w_size&&(t.block_start-=t.w_size,t.strstart-=t.w_size,t.window.set(t.window.subarray(t.w_size,t.w_size+t.strstart),0),t.matches<2&&t.matches++,a+=t.w_size,t.insert>t.strstart&&(t.insert=t.strstart)),a>t.strm.avail_in&&(a=t.strm.avail_in),a&&(Ze(t.strm,t.window,t.strstart,a),t.strstart+=a,t.insert+=a>t.w_size-t.insert?t.w_size-t.insert:a),t.high_water>3,a=t.pending_buf_size-a>65535?65535:t.pending_buf_size-a,r=a>t.w_size?t.w_size:a,s=t.strstart-t.block_start,(s>=r||(s||e===ye)&&e!==be&&0===t.strm.avail_in&&s<=a)&&(i=s>a?a:s,n=e===ye&&0===t.strm.avail_in&&i===s?1:0,ge(t,t.block_start,i,n),t.block_start+=i,He(t.strm)),n?3:1)},Ye=(t,e)=>{let i,s;for(;;){if(t.lookahead=3&&(t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+3-1]),i=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!==i&&t.strstart-i<=t.w_size-Te&&(t.match_length=Xe(t,i)),t.match_length>=3)if(s=_e(t,t.strstart-t.match_start,t.match_length-3),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=3){t.match_length--;do{t.strstart++,t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+3-1]),i=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart}while(0!==--t.match_length);t.strstart++}else t.strstart+=t.match_length,t.match_length=0,t.ins_h=t.window[t.strstart],t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+1]);else s=_e(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++;if(s&&(Je(t,!1),0===t.strm.avail_out))return 1}return t.insert=t.strstart<2?t.strstart:2,e===ye?(Je(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(Je(t,!1),0===t.strm.avail_out)?1:2},ti=(t,e)=>{let i,s,a;for(;;){if(t.lookahead=3&&(t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+3-1]),i=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),t.prev_length=t.match_length,t.prev_match=t.match_start,t.match_length=2,0!==i&&t.prev_length4096)&&(t.match_length=2)),t.prev_length>=3&&t.match_length<=t.prev_length){a=t.strstart+t.lookahead-3,s=_e(t,t.strstart-1-t.prev_match,t.prev_length-3),t.lookahead-=t.prev_length-1,t.prev_length-=2;do{++t.strstart<=a&&(t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+3-1]),i=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart)}while(0!==--t.prev_length);if(t.match_available=0,t.match_length=2,t.strstart++,s&&(Je(t,!1),0===t.strm.avail_out))return 1}else if(t.match_available){if(s=_e(t,0,t.window[t.strstart-1]),s&&Je(t,!1),t.strstart++,t.lookahead--,0===t.strm.avail_out)return 1}else t.match_available=1,t.strstart++,t.lookahead--}return t.match_available&&(s=_e(t,0,t.window[t.strstart-1]),t.match_available=0),t.insert=t.strstart<2?t.strstart:2,e===ye?(Je(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(Je(t,!1),0===t.strm.avail_out)?1:2};function ei(t,e,i,s,a){this.good_length=t,this.max_lazy=e,this.nice_length=i,this.max_chain=s,this.func=a}const ii=[new ei(0,0,0,0,qe),new ei(4,4,8,4,Ye),new ei(4,5,16,8,Ye),new ei(4,6,32,32,Ye),new ei(4,4,16,16,ti),new ei(8,16,32,32,ti),new ei(8,16,128,128,ti),new ei(8,32,128,256,ti),new ei(32,128,258,1024,ti),new ei(32,258,258,4096,ti)];function si(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=Ae,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new Uint16Array(1146),this.dyn_dtree=new Uint16Array(122),this.bl_tree=new Uint16Array(78),We(this.dyn_ltree),We(this.dyn_dtree),We(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new Uint16Array(16),this.heap=new Uint16Array(573),We(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new Uint16Array(573),We(this.depth),this.sym_buf=0,this.lit_bufsize=0,this.sym_next=0,this.sym_end=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}const ai=t=>{if(!t)return 1;const e=t.state;return!e||e.strm!==t||e.status!==Le&&57!==e.status&&69!==e.status&&73!==e.status&&91!==e.status&&103!==e.status&&e.status!==ze&&e.status!==Pe?1:0},ri=t=>{if(ai(t))return Ne(t,Re);t.total_in=t.total_out=0,t.data_type=Oe;const e=t.state;return e.pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=2===e.wrap?57:e.wrap?Le:ze,t.adler=2===e.wrap?0:1,e.last_flush=-2,ue(e),Be},ni=t=>{const e=ri(t);var i;return e===Be&&((i=t.state).window_size=2*i.w_size,We(i.head),i.max_lazy_match=ii[i.level].max_lazy,i.good_match=ii[i.level].good_length,i.nice_match=ii[i.level].nice_length,i.max_chain_length=ii[i.level].max_chain,i.strstart=0,i.block_start=0,i.lookahead=0,i.insert=0,i.match_length=i.prev_length=2,i.match_available=0,i.ins_h=0),e},oi=(t,e,i,s,a,r)=>{if(!t)return Re;let n=1;if(e===Ee&&(e=6),s<0?(n=0,s=-s):s>15&&(n=2,s-=16),a<1||a>9||i!==Ae||s<8||s>15||e<0||e>9||r<0||r>Me||8===s&&1!==n)return Ne(t,Re);8===s&&(s=9);const o=new si;return t.state=o,o.strm=t,o.status=Le,o.wrap=n,o.gzhead=null,o.w_bits=s,o.w_size=1<oi(t,e,Ae,15,8,De),deflateInit2:oi,deflateReset:ni,deflateResetKeep:ri,deflateSetHeader:(t,e)=>ai(t)||2!==t.state.wrap?Re:(t.state.gzhead=e,Be),deflate:(t,e)=>{if(ai(t)||e>Se||e<0)return t?Ne(t,Re):Re;const i=t.state;if(!t.output||0!==t.avail_in&&!t.input||i.status===Pe&&e!==ye)return Ne(t,0===t.avail_out?Ce:Re);const s=i.last_flush;if(i.last_flush=e,0!==i.pending){if(He(t),0===t.avail_out)return i.last_flush=-1,Be}else if(0===t.avail_in&&$e(e)<=$e(s)&&e!==ye)return Ne(t,Ce);if(i.status===Pe&&0!==t.avail_in)return Ne(t,Ce);if(i.status===Le&&0===i.wrap&&(i.status=ze),i.status===Le){let e=Ae+(i.w_bits-8<<4)<<8,s=-1;if(s=i.strategy>=xe||i.level<2?0:i.level<6?1:6===i.level?2:3,e|=s<<6,0!==i.strstart&&(e|=32),e+=31-e%31,Ve(i,e),0!==i.strstart&&(Ve(i,t.adler>>>16),Ve(i,65535&t.adler)),t.adler=1,i.status=ze,He(t),0!==i.pending)return i.last_flush=-1,Be}if(57===i.status)if(t.adler=0,Qe(i,31),Qe(i,139),Qe(i,8),i.gzhead)Qe(i,(i.gzhead.text?1:0)+(i.gzhead.hcrc?2:0)+(i.gzhead.extra?4:0)+(i.gzhead.name?8:0)+(i.gzhead.comment?16:0)),Qe(i,255&i.gzhead.time),Qe(i,i.gzhead.time>>8&255),Qe(i,i.gzhead.time>>16&255),Qe(i,i.gzhead.time>>24&255),Qe(i,9===i.level?2:i.strategy>=xe||i.level<2?4:0),Qe(i,255&i.gzhead.os),i.gzhead.extra&&i.gzhead.extra.length&&(Qe(i,255&i.gzhead.extra.length),Qe(i,i.gzhead.extra.length>>8&255)),i.gzhead.hcrc&&(t.adler=le(t.adler,i.pending_buf,i.pending,0)),i.gzindex=0,i.status=69;else if(Qe(i,0),Qe(i,0),Qe(i,0),Qe(i,0),Qe(i,0),Qe(i,9===i.level?2:i.strategy>=xe||i.level<2?4:0),Qe(i,3),i.status=ze,He(t),0!==i.pending)return i.last_flush=-1,Be;if(69===i.status){if(i.gzhead.extra){let e=i.pending,s=(65535&i.gzhead.extra.length)-i.gzindex;for(;i.pending+s>i.pending_buf_size;){let a=i.pending_buf_size-i.pending;if(i.pending_buf.set(i.gzhead.extra.subarray(i.gzindex,i.gzindex+a),i.pending),i.pending=i.pending_buf_size,i.gzhead.hcrc&&i.pending>e&&(t.adler=le(t.adler,i.pending_buf,i.pending-e,e)),i.gzindex+=a,He(t),0!==i.pending)return i.last_flush=-1,Be;e=0,s-=a}let a=new Uint8Array(i.gzhead.extra);i.pending_buf.set(a.subarray(i.gzindex,i.gzindex+s),i.pending),i.pending+=s,i.gzhead.hcrc&&i.pending>e&&(t.adler=le(t.adler,i.pending_buf,i.pending-e,e)),i.gzindex=0}i.status=73}if(73===i.status){if(i.gzhead.name){let e,s=i.pending;do{if(i.pending===i.pending_buf_size){if(i.gzhead.hcrc&&i.pending>s&&(t.adler=le(t.adler,i.pending_buf,i.pending-s,s)),He(t),0!==i.pending)return i.last_flush=-1,Be;s=0}e=i.gzindexs&&(t.adler=le(t.adler,i.pending_buf,i.pending-s,s)),i.gzindex=0}i.status=91}if(91===i.status){if(i.gzhead.comment){let e,s=i.pending;do{if(i.pending===i.pending_buf_size){if(i.gzhead.hcrc&&i.pending>s&&(t.adler=le(t.adler,i.pending_buf,i.pending-s,s)),He(t),0!==i.pending)return i.last_flush=-1,Be;s=0}e=i.gzindexs&&(t.adler=le(t.adler,i.pending_buf,i.pending-s,s))}i.status=103}if(103===i.status){if(i.gzhead.hcrc){if(i.pending+2>i.pending_buf_size&&(He(t),0!==i.pending))return i.last_flush=-1,Be;Qe(i,255&t.adler),Qe(i,t.adler>>8&255),t.adler=0}if(i.status=ze,He(t),0!==i.pending)return i.last_flush=-1,Be}if(0!==t.avail_in||0!==i.lookahead||e!==be&&i.status!==Pe){let s=0===i.level?qe(i,e):i.strategy===xe?((t,e)=>{let i;for(;;){if(0===t.lookahead&&(Ke(t),0===t.lookahead)){if(e===be)return 1;break}if(t.match_length=0,i=_e(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,i&&(Je(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,e===ye?(Je(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(Je(t,!1),0===t.strm.avail_out)?1:2})(i,e):i.strategy===Ue?((t,e)=>{let i,s,a,r;const n=t.window;for(;;){if(t.lookahead<=Fe){if(Ke(t),t.lookahead<=Fe&&e===be)return 1;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=3&&t.strstart>0&&(a=t.strstart-1,s=n[a],s===n[++a]&&s===n[++a]&&s===n[++a])){r=t.strstart+Fe;do{}while(s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&at.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=3?(i=_e(t,1,t.match_length-3),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(i=_e(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),i&&(Je(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,e===ye?(Je(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(Je(t,!1),0===t.strm.avail_out)?1:2})(i,e):ii[i.level].func(i,e);if(3!==s&&4!==s||(i.status=Pe),1===s||3===s)return 0===t.avail_out&&(i.last_flush=-1),Be;if(2===s&&(e===we?pe(i):e!==Se&&(ge(i,0,0,!1),e===me&&(We(i.head),0===i.lookahead&&(i.strstart=0,i.block_start=0,i.insert=0))),He(t),0===t.avail_out))return i.last_flush=-1,Be}return e!==ye?Be:i.wrap<=0?Ie:(2===i.wrap?(Qe(i,255&t.adler),Qe(i,t.adler>>8&255),Qe(i,t.adler>>16&255),Qe(i,t.adler>>24&255),Qe(i,255&t.total_in),Qe(i,t.total_in>>8&255),Qe(i,t.total_in>>16&255),Qe(i,t.total_in>>24&255)):(Ve(i,t.adler>>>16),Ve(i,65535&t.adler)),He(t),i.wrap>0&&(i.wrap=-i.wrap),0!==i.pending?Be:Ie)},deflateEnd:t=>{if(ai(t))return Re;const e=t.state.status;return t.state=null,e===ze?Ne(t,ve):Be},deflateSetDictionary:(t,e)=>{let i=e.length;if(ai(t))return Re;const s=t.state,a=s.wrap;if(2===a||1===a&&s.status!==Le||s.lookahead)return Re;if(1===a&&(t.adler=oe(t.adler,e,i,0)),s.wrap=0,i>=s.w_size){0===a&&(We(s.head),s.strstart=0,s.block_start=0,s.insert=0);let t=new Uint8Array(s.w_size);t.set(e.subarray(i-s.w_size,i),0),e=t,i=s.w_size}const r=t.avail_in,n=t.next_in,o=t.input;for(t.avail_in=i,t.next_in=0,t.input=e,Ke(s);s.lookahead>=3;){let t=s.strstart,e=s.lookahead-2;do{s.ins_h=Ge(s,s.ins_h,s.window[t+3-1]),s.prev[t&s.w_mask]=s.head[s.ins_h],s.head[s.ins_h]=t,t++}while(--e);s.strstart=t,s.lookahead=2,Ke(s)}return s.strstart+=s.lookahead,s.block_start=s.strstart,s.insert=s.lookahead,s.lookahead=0,s.match_length=s.prev_length=2,s.match_available=0,t.next_in=n,t.input=o,t.avail_in=r,s.wrap=a,Be},deflateInfo:"pako deflate (from Nodeca project)"};const li=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var di=function(t){const e=Array.prototype.slice.call(arguments,1);for(;e.length;){const i=e.shift();if(i){if("object"!=typeof i)throw new TypeError(i+"must be non-object");for(const e in i)li(i,e)&&(t[e]=i[e])}}return t},ci=t=>{let e=0;for(let i=0,s=t.length;i=252?6:t>=248?5:t>=240?4:t>=224?3:t>=192?2:1;gi[254]=gi[254]=1;var fi=t=>{if("function"==typeof TextEncoder&&TextEncoder.prototype.encode)return(new TextEncoder).encode(t);let e,i,s,a,r,n=t.length,o=0;for(a=0;a>>6,e[r++]=128|63&i):i<65536?(e[r++]=224|i>>>12,e[r++]=128|i>>>6&63,e[r++]=128|63&i):(e[r++]=240|i>>>18,e[r++]=128|i>>>12&63,e[r++]=128|i>>>6&63,e[r++]=128|63&i);return e};var _i=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0};const pi=Object.prototype.toString,{Z_NO_FLUSH:bi,Z_SYNC_FLUSH:wi,Z_FULL_FLUSH:mi,Z_FINISH:yi,Z_OK:Si,Z_STREAM_END:Bi,Z_DEFAULT_COMPRESSION:Ii,Z_DEFAULT_STRATEGY:Ri,Z_DEFLATED:vi}=ce;function Ci(t){this.options=di({level:Ii,method:vi,chunkSize:16384,windowBits:15,memLevel:8,strategy:Ri},t||{});let e=this.options;e.raw&&e.windowBits>0?e.windowBits=-e.windowBits:e.gzip&&e.windowBits>0&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new _i,this.strm.avail_out=0;let i=hi.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(i!==Si)throw new Error(de[i]);if(e.header&&hi.deflateSetHeader(this.strm,e.header),e.dictionary){let t;if(t="string"==typeof e.dictionary?fi(e.dictionary):"[object ArrayBuffer]"===pi.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,i=hi.deflateSetDictionary(this.strm,t),i!==Si)throw new Error(de[i]);this._dict_set=!0}}Ci.prototype.push=function(t,e){const i=this.strm,s=this.options.chunkSize;let a,r;if(this.ended)return!1;for(r=e===~~e?e:!0===e?yi:bi,"string"==typeof t?i.input=fi(t):"[object ArrayBuffer]"===pi.call(t)?i.input=new Uint8Array(t):i.input=t,i.next_in=0,i.avail_in=i.input.length;;)if(0===i.avail_out&&(i.output=new Uint8Array(s),i.next_out=0,i.avail_out=s),(r===wi||r===mi)&&i.avail_out<=6)this.onData(i.output.subarray(0,i.next_out)),i.avail_out=0;else{if(a=hi.deflate(i,r),a===Bi)return i.next_out>0&&this.onData(i.output.subarray(0,i.next_out)),a=hi.deflateEnd(this.strm),this.onEnd(a),this.ended=!0,a===Si;if(0!==i.avail_out){if(r>0&&i.next_out>0)this.onData(i.output.subarray(0,i.next_out)),i.avail_out=0;else if(0===i.avail_in)break}else this.onData(i.output)}return!0},Ci.prototype.onData=function(t){this.chunks.push(t)},Ci.prototype.onEnd=function(t){t===Si&&(this.result=ci(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg};var Ei={deflate:function(t,e){const i=new Ci(e);if(i.push(t,!0),i.err)throw i.msg||de[i.err];return i.result}};const{deflate:ki}=Ei;var xi=ki;const Ui={b:{u:DataView.prototype.getInt8,p:DataView.prototype.setInt8,bytes:1},B:{u:DataView.prototype.getUint8,p:DataView.prototype.setUint8,bytes:1},h:{u:DataView.prototype.getInt16,p:DataView.prototype.setInt16,bytes:2},H:{u:DataView.prototype.getUint16,p:DataView.prototype.setUint16,bytes:2},i:{u:DataView.prototype.getInt32,p:DataView.prototype.setInt32,bytes:4},I:{u:DataView.prototype.getUint32,p:DataView.prototype.setUint32,bytes:4}},Mi=(t,...e)=>{let i=0;if(t.replace(/[<>]/,"").length!=e.length)throw"Pack format to Argument count mismatch";const s=[];let a=!0;for(let s=0;s"==t[s]?a=!1:(r(t[s],e[i]),i++);function r(t,e){if(!(t in Ui))throw"Unhandled character '"+t+"' in pack format";const i=Ui[t].bytes,r=new DataView(new ArrayBuffer(i));Ui[t].p.bind(r)(0,e,a);for(let t=0;t{let i=0;const s=[];let a=!0;for(const e of t)"<"==e?a=!0:">"==e?a=!1:r(e);function r(t){if(!(t in Ui))throw"Unhandled character '"+t+"' in unpack format";const r=Ui[t].bytes,n=new DataView(new ArrayBuffer(r));for(let t=0;t=this._inputBuffer.length))return this._inputBuffer[this._inputBufferReadIndex++]}_clearInputBuffer(){this._inputBuffer.length=0,this._inputBufferReadIndex=0}_compactInputBuffer(){this._inputBufferReadIndex>1e3&&this._inputBufferReadIndex>this._inputBuffer.length/2&&(this._inputBuffer.splice(0,this._inputBufferReadIndex),this._inputBufferReadIndex=0)}get _totalBytesRead(){return this._parent?this._parent._totalBytesRead:this.__totalBytesRead||0}set _totalBytesRead(t){this._parent?this._parent._totalBytesRead=t:this.__totalBytesRead=t}get _commandLock(){return this._parent?this._parent._commandLock:this.__commandLock}set _commandLock(t){this._parent?this._parent._commandLock=t:this.__commandLock=t}get _isReconfiguring(){return this._parent?this._parent._isReconfiguring:this.__isReconfiguring}set _isReconfiguring(t){this._parent?this._parent._isReconfiguring=t:this.__isReconfiguring=t}get _abandonCurrentOperation(){return this._parent?this._parent._abandonCurrentOperation:this.__abandonCurrentOperation}set _abandonCurrentOperation(t){this._parent?this._parent._abandonCurrentOperation=t:this.__abandonCurrentOperation=t}get _adaptiveBlockMultiplier(){return this._parent?this._parent._adaptiveBlockMultiplier:this.__adaptiveBlockMultiplier}set _adaptiveBlockMultiplier(t){this._parent?this._parent._adaptiveBlockMultiplier=t:this.__adaptiveBlockMultiplier=t}get _adaptiveMaxInFlightMultiplier(){return this._parent?this._parent._adaptiveMaxInFlightMultiplier:this.__adaptiveMaxInFlightMultiplier}set _adaptiveMaxInFlightMultiplier(t){this._parent?this._parent._adaptiveMaxInFlightMultiplier=t:this.__adaptiveMaxInFlightMultiplier=t}get _consecutiveSuccessfulChunks(){return this._parent?this._parent._consecutiveSuccessfulChunks:this.__consecutiveSuccessfulChunks}set _consecutiveSuccessfulChunks(t){this._parent?this._parent._consecutiveSuccessfulChunks=t:this.__consecutiveSuccessfulChunks=t}get _lastAdaptiveAdjustment(){return this._parent?this._parent._lastAdaptiveAdjustment:this.__lastAdaptiveAdjustment}set _lastAdaptiveAdjustment(t){this._parent?this._parent._lastAdaptiveAdjustment=t:this.__lastAdaptiveAdjustment=t}get _isCDCDevice(){return this._parent?this._parent._isCDCDevice:this.__isCDCDevice}set _isCDCDevice(t){this._parent?this._parent._isCDCDevice=t:this.__isCDCDevice=t}detectUSBSerialChip(t,e){const i={6790:{29986:{name:"CH340",maxBaudrate:460800},29987:{name:"CH340",maxBaudrate:460800},30084:{name:"CH340",maxBaudrate:460800},21795:{name:"CH341",maxBaudrate:2e6},21971:{name:"CH343",maxBaudrate:6e6},21972:{name:"CH9102",maxBaudrate:6e6},21976:{name:"CH9101",maxBaudrate:3e6}},4292:{6e4:{name:"CP2102(n)",maxBaudrate:3e6},60016:{name:"CP2105",maxBaudrate:2e6},60017:{name:"CP2108",maxBaudrate:2e6}},1027:{24577:{name:"FT232R",maxBaudrate:3e6},24592:{name:"FT2232",maxBaudrate:3e6},24593:{name:"FT4232",maxBaudrate:3e6},24596:{name:"FT232H",maxBaudrate:12e6},24597:{name:"FT230X",maxBaudrate:3e6}},12346:{2:{name:"ESP32-S2 Native USB",maxBaudrate:2e6},18:{name:"ESP32-P4 Native USB",maxBaudrate:2e6},4097:{name:"ESP32 Native USB",maxBaudrate:2e6}}}[t];return i&&i[e]?i[e]:{name:`Unknown (VID: 0x${t.toString(16)}, PID: 0x${e.toString(16)})`}}async initialize(){if(!this._parent){this.__inputBuffer=[],this.__inputBufferReadIndex=0,this.__totalBytesRead=0;const t=this.port.getInfo();if(t.usbVendorId&&t.usbProductId){const e=this.detectUSBSerialChip(t.usbVendorId,t.usbProductId);this.logger.log(`USB-Serial: ${e.name} (VID: 0x${t.usbVendorId.toString(16)}, PID: 0x${t.usbProductId.toString(16)})`),e.maxBaudrate&&(this._maxUSBSerialBaudrate=e.maxBaudrate,this.logger.log(`Max baudrate: ${e.maxBaudrate}`)),12346===t.usbVendorId&&2===t.usbProductId&&(this._isESP32S2NativeUSB=!0),(12346===t.usbVendorId||6790===t.usbVendorId&&21971===t.usbProductId)&&(this._isCDCDevice=!0)}this.readLoop()}await this.connectWithResetStrategies(),await this.detectChip(),this.chipFamily===T&&301===this.chipRevision&&await this.powerOnFlash();try{this._isUsbJtagOrOtg=await this.detectUsbConnectionType(),this.logger.debug("USB connection type: "+(this._isUsbJtagOrOtg?"USB-JTAG/OTG":"External Serial Chip"))}catch(t){this.logger.debug(`Could not detect USB connection type: ${t}`)}try{const t=await this.getUsbMode();this.logger.debug(`USB mode (register): ${t.mode} (uartNo=${t.uartNo})`)}catch(t){this.logger.debug(`Could not detect USB mode: ${t}`)}const t=wt(this.getChipFamily()),e=t.macFuse;for(let t=0;t<4;t++)this._efuses[t]=await this.readRegister(e+4*t);const i=null!==this.chipRevision&&void 0!==this.chipRevision?` (revision ${this.chipRevision})`:"";this.logger.log(`Connected to ${this.chipName}${i}`),this.logger.debug(`Bootloader flash offset: 0x${t.flashOffs.toString(16)}`),this._initializationSucceeded=!0}async detectChip(){try{const t=(await this.getSecurityInfo()).chipId,e=z[t];if(e)return this.chipName=e.name,this.chipFamily=e.family,this.chipRevision=await this.getChipRevision(),this.logger.debug(`${this.chipName} revision: ${this.chipRevision}`),this.chipFamily===T&&this.chipRevision>=300?this.chipVariant="rev300":this.chipFamily===T&&(this.chipVariant="rev0"),void this.logger.debug(`Detected chip via IMAGE_CHIP_ID: ${t} (${this.chipName})`);this.logger.debug(`Unknown IMAGE_CHIP_ID: ${t}, falling back to magic value detection`)}catch(t){this.logger.debug(`GET_SECURITY_INFO failed, using magic value detection: ${t}`),await this.drainInputBuffer(200),this._clearInputBuffer(),await r(gt);try{await this.sync()}catch(t){this.logger.debug(`Re-sync after GET_SECURITY_INFO failure: ${t}`)}}const t=await this.readRegister(1073745920),e=P[t>>>0];if(void 0===e)throw new Error(`Unknown Chip: Hex: ${s(t>>>0,8).toLowerCase()} Number: ${t}`);this.chipName=e.name,this.chipFamily=e.family,this.chipRevision=await this.getChipRevision(),this.logger.debug(`${this.chipName} revision: ${this.chipRevision}`),this.chipFamily===T&&(this.chipVariant=this.chipRevision>=300?"rev300":"rev0",this.logger.debug(`ESP32-P4 variant: ${this.chipVariant}`)),this.logger.debug(`Detected chip via magic value: ${s(t>>>0,8)} (${this.chipName})`)}async getChipRevision(){var t;let e=0,i=0;switch(this.chipFamily){case v:{const s=await this.readRegister(1073061900),a=await this.readRegister(1073061908);e=a>>24&3;const r=s>>15&1,n=a>>20&1;i=null!==(t={0:0,1:1,3:2,7:3}[(await this.readRegister(1073111164)>>31&1)<<2|n<<1|r])&&void 0!==t?t:0;break}case C:{const t=await this.readRegister(1061265488);e=((t>>20&1)<<3)+(await this.readRegister(1061265492)>>4&7),i=t>>18&3;break}case E:{const t=await this.readRegister(1610641488),s=await this.readRegister(1610641496);e=((s>>23&1)<<3)+(t>>18&7),i=s>>24&3;break}case k:{const t=await this.readRegister(1610647620);e=t>>16&15,i=t>>20&3;break}case x:{const t=await this.readRegister(1610647632),s=await this.readRegister(1610647640);e=((s>>23&1)<<3)+(t>>18&7),i=s>>24&3;break}case U:{const t=await this.readRegister(1611352140);e=15&t,i=t>>4&3;break}case M:{const t=await this.readRegister(1611335760);e=t>>18&15,i=t>>22&3;break}case D:{const t=await this.readRegister(1611352140);e=15&t,i=t>>4&3;break}case O:{const t=await this.readRegister(1611335760);e=t>>18&7,i=t>>21&3;break}case A:case F:break;case T:{const t=await this.readRegister(1343410252);e=15&t,i=(t>>23&1)<<2|t>>4&3;break}case L:{const t=await this.readRegister(544297036);e=15&t,i=t>>4&3;break}}return 100*i+e}async powerOnFlash(){if(this.chipFamily!==T)return;if(301!==this.chipRevision)return;this.logger.debug("Powering on flash for ESP32-P4 Rev 301 (ECO6)"),await this.writeRegister(1343291660,1),await r(10);const t=await this.readRegister(w);await this.writeRegister(w,t|m);const e=await this.readRegister(y);await this.writeRegister(y,128|e);const i=await this.readRegister(S);await this.writeRegister(S,3|i),await r(.05);const s=await this.readRegister(w);await this.writeRegister(w,-134217729&s);const a=await this.readRegister(y);await this.writeRegister(y,-2139095041&a);const n=await this.readRegister(y);await this.writeRegister(y,128|n);const o=await this.readRegister(y);await this.writeRegister(y,-129&o),await r(2),this.logger.debug("Flash powered on successfully")}async getSecurityInfo(){const[,t]=await this.checkCommand(20,[],0);if(0===t.length)throw new Error("GET_SECURITY_INFO not supported or returned empty response");if(t.length<12)throw new Error(`Invalid security info response length: ${t.length} (expected at least 12 bytes)`);return{flags:Di("=16?Di("=20?Di("t.toString(16).padStart(2,"0").toUpperCase()).join(":")}async readLoop(){this.debug&&this.logger.debug("Starting read loop"),this._reader=this.port.readable.getReader();try{let t=!0;for(;t;){const{value:e,done:i}=await this._reader.read();if(i){this._reader.releaseLock(),t=!1;break}if(!e||0===e.length)continue;const s=Array.from(e);Array.prototype.push.apply(this._inputBuffer,s),this._totalBytesRead+=e.length}}catch{}finally{if(this._isReconfiguring=!1,this._reader){try{this._reader.releaseLock(),this.logger.debug("Reader released in readLoop cleanup")}catch(t){this.logger.debug(`Reader release error in readLoop: ${t}`)}this._reader=void 0}}this.connected=!1,this._isESP32S2NativeUSB&&!this._initializationSucceeded&&(this.logger.log("ESP32-S2 Native USB detected - requesting port reselection"),this.dispatchEvent(new CustomEvent("esp32s2-usb-reconnect",{detail:{message:"ESP32-S2 Native USB requires port reselection"}}))),this._suppressDisconnect||this.dispatchEvent(new Event("disconnect")),this._suppressDisconnect=!1,this.logger.debug("Finished read loop")}async setRTS(t){await this.port.setSignals({requestToSend:t}),await this.setDTR(this.state_DTR)}async setDTR(t){this.state_DTR=t,await this.port.setSignals({dataTerminalReady:t})}async setDTRandRTS(t,e){this.state_DTR=t,this.state_RTS=e,await this.port.setSignals({dataTerminalReady:t,requestToSend:e})}async runSignalSequence(t){const e=!0===this.port.isWebUSB;for(const i of t)void 0!==i.dtr&&void 0!==i.rts?e?await this.setDTRandRTSWebUSB(i.dtr,i.rts):await this.setDTRandRTS(i.dtr,i.rts):(void 0!==i.dtr&&(e?await this.setDTRWebUSB(i.dtr):await this.setDTR(i.dtr)),void 0!==i.rts&&(e?await this.setRTSWebUSB(i.rts):await this.setRTS(i.rts))),i.delayMs&&await r(i.delayMs)}async hardResetUSBJTAGSerial(){await this.runSignalSequence([{rts:!1},{dtr:!1,delayMs:100},{dtr:!0,rts:!1,delayMs:100},{rts:!0},{dtr:!1,rts:!0,delayMs:100},{dtr:!1,rts:!1,delayMs:200}])}async hardResetClassic(){await this.runSignalSequence([{dtr:!1,rts:!0,delayMs:100},{dtr:!0,rts:!1,delayMs:50},{dtr:!1,delayMs:200}])}async hardResetToFirmware(){await this.runSignalSequence([{dtr:!1,rts:!0,delayMs:100},{rts:!1,delayMs:50},{delayMs:200}])}async hardResetUnixTight(){await this.runSignalSequence([{dtr:!0,rts:!0},{dtr:!1,rts:!1},{dtr:!1,rts:!0,delayMs:100},{dtr:!0,rts:!1,delayMs:50},{dtr:!1,rts:!1},{dtr:!1,delayMs:200}])}async setRTSWebUSB(t){this.state_RTS=t,await this.port.setSignals({requestToSend:t,dataTerminalReady:this.state_DTR})}async setDTRWebUSB(t){this.state_DTR=t,await this.port.setSignals({dataTerminalReady:t,requestToSend:this.state_RTS})}async setDTRandRTSWebUSB(t,e){this.state_DTR=t,this.state_RTS=e,await this.port.setSignals({dataTerminalReady:t,requestToSend:e})}async hardResetUSBJTAGSerialInvertedDTRWebUSB(){await this.runSignalSequence([{rts:!1,dtr:!0,delayMs:100},{dtr:!1,rts:!1,delayMs:100},{rts:!0,dtr:!0,delayMs:100},{dtr:!0,rts:!1,delayMs:200}])}async hardResetClassicLongDelayWebUSB(){await this.runSignalSequence([{dtr:!1,rts:!0,delayMs:500},{dtr:!0,rts:!1,delayMs:200},{dtr:!1,delayMs:500}])}async hardResetClassicShortDelayWebUSB(){await this.runSignalSequence([{dtr:!1,rts:!0,delayMs:50},{dtr:!0,rts:!1,delayMs:25},{dtr:!1,delayMs:100}])}async hardResetInvertedWebUSB(){await this.runSignalSequence([{dtr:!0,rts:!1,delayMs:100},{dtr:!1,rts:!0,delayMs:50},{dtr:!0,delayMs:200}])}async hardResetInvertedDTRWebUSB(){await this.runSignalSequence([{dtr:!0,rts:!0,delayMs:100},{dtr:!1,rts:!1,delayMs:50},{dtr:!0,delayMs:200}])}async hardResetInvertedRTSWebUSB(){await this.runSignalSequence([{dtr:!1,rts:!1,delayMs:100},{dtr:!0,rts:!0,delayMs:50},{dtr:!1,delayMs:200}])}isWebUSB(){return!0===this.port.isWebUSB}async connectWithResetStrategies(){const t=this.port.getInfo(),e=4097===t.usbProductId,i=12346===t.usbVendorId,s=[],a=this,n=!e&&!i;if(this.isWebUSB()){const r=4292===t.usbVendorId,o=6790===t.usbVendorId,h=12346===t.usbVendorId&&2===t.usbProductId;(e||i)&&(h?(s.push({name:"USB-JTAG/Serial (WebUSB) - ESP32-S2",fn:async()=>await a.hardResetUSBJTAGSerial()}),s.push({name:"USB-JTAG/Serial Inverted DTR (WebUSB) - ESP32-S2",fn:async()=>await a.hardResetUSBJTAGSerialInvertedDTRWebUSB()}),s.push({name:"UnixTight (WebUSB) - ESP32-S2 CDC",fn:async()=>await a.hardResetUnixTight()}),s.push({name:"Classic (WebUSB) - ESP32-S2 CDC",fn:async()=>await a.hardResetClassic()})):(s.push({name:"USB-JTAG/Serial Inverted DTR (WebUSB)",fn:async()=>await a.hardResetUSBJTAGSerialInvertedDTRWebUSB()}),s.push({name:"USB-JTAG/Serial (WebUSB)",fn:async()=>await a.hardResetUSBJTAGSerial()}),s.push({name:"Inverted DTR Classic (WebUSB)",fn:async()=>await a.hardResetInvertedDTRWebUSB()}))),n&&(o?(s.push({name:"UnixTight (WebUSB) - CH34x",fn:async()=>await a.hardResetUnixTight()}),s.push({name:"Classic (WebUSB) - CH34x",fn:async()=>await a.hardResetClassic()}),s.push({name:"Inverted Both (WebUSB) - CH34x",fn:async()=>await a.hardResetInvertedWebUSB()}),s.push({name:"Inverted RTS (WebUSB) - CH34x",fn:async()=>await a.hardResetInvertedRTSWebUSB()}),s.push({name:"Inverted DTR (WebUSB) - CH34x",fn:async()=>await a.hardResetInvertedDTRWebUSB()})):r?(s.push({name:"UnixTight (WebUSB) - CP2102",fn:async()=>await a.hardResetUnixTight()}),s.push({name:"Classic (WebUSB) - CP2102",fn:async()=>await a.hardResetClassic()}),s.push({name:"Inverted Both (WebUSB) - CP2102",fn:async()=>await a.hardResetInvertedWebUSB()}),s.push({name:"Inverted RTS (WebUSB) - CP2102",fn:async()=>await a.hardResetInvertedRTSWebUSB()}),s.push({name:"Inverted DTR (WebUSB) - CP2102",fn:async()=>await a.hardResetInvertedDTRWebUSB()})):(s.push({name:"UnixTight (WebUSB)",fn:async()=>await a.hardResetUnixTight()}),s.push({name:"Classic (WebUSB)",fn:async function(){return await a.hardResetClassic()}}),s.push({name:"Inverted Both (WebUSB)",fn:async function(){return await a.hardResetInvertedWebUSB()}}),s.push({name:"Inverted RTS (WebUSB)",fn:async function(){return await a.hardResetInvertedRTSWebUSB()}}),s.push({name:"Inverted DTR (WebUSB)",fn:async function(){return await a.hardResetInvertedDTRWebUSB()}}))),n||r||h||e||(6790!==t.usbVendorId&&s.push({name:"Classic (WebUSB)",fn:async function(){return await a.hardResetClassic()}}),s.push({name:"UnixTight (WebUSB)",fn:async function(){return await a.hardResetUnixTight()}}),s.push({name:"Classic Long Delay (WebUSB)",fn:async function(){return await a.hardResetClassicLongDelayWebUSB()}}),s.push({name:"Classic Short Delay (WebUSB)",fn:async function(){return await a.hardResetClassicShortDelayWebUSB()}}),i||s.push({name:"USB-JTAG/Serial fallback (WebUSB)",fn:async function(){return await a.hardResetUSBJTAGSerial()}}))}else(e||i)&&s.push({name:"USB-JTAG/Serial",fn:async function(){return await a.hardResetUSBJTAGSerial()}}),s.push({name:"UnixTight",fn:async function(){return await a.hardResetUnixTight()}}),e||i||s.push({name:"USB-JTAG/Serial (fallback)",fn:async function(){return await a.hardResetUSBJTAGSerial()}});let o=null;for(const t of s)try{if(!this.connected||!this.port.writable){this.logger.debug(`Port disconnected, skipping ${t.name} reset`);continue}if(this._abandonCurrentOperation=!1,await t.fn(),n){if(await this.syncWithTimeout(2e3))return void this.logger.log(`Connected USB Serial successfully with ${t.name} reset.`);throw new Error("Sync timeout or abandoned")}{const e=this.sync(),i=new Promise((t,e)=>setTimeout(()=>e(new Error("Sync timeout")),1e3));try{return await Promise.race([e,i]),void this.logger.debug(`Connected CDC/JTAG successfully with ${t.name} reset.`)}catch(t){throw new Error("Sync timeout or abandoned")}}}catch(t){if(o=t,this._abandonCurrentOperation=!0,await r(100),!this.connected||!this.port.writable){this.logger.log("Port disconnected during reset attempt");break}this._clearInputBuffer(),await this.drainInputBuffer(200),await this.flushSerialBuffers()}throw this._abandonCurrentOperation=!1,new Error(`Couldn't sync to ESP. Try resetting manually. Last error: ${null==o?void 0:o.message}`)}async watchdogReset(){await this.rtcWdtResetChipSpecific()}async rtcWdtResetChipSpecific(){let t,e,i,s;if(this.logger.debug("Hard resetting with watchdog timer..."),this.chipFamily===C)t=1061191852,e=1061191828,i=1061191832,s=1356348065;else if(this.chipFamily===E)t=1610645680,e=1610645656,i=1610645660,s=1356348065;else if(this.chipFamily===x)t=1610645672,e=1610645648,i=1610645652,s=1356348065;else if(this.chipFamily===U||this.chipFamily===M)t=1611340824,e=1611340800,i=1611340804,s=1356348065;else{if(this.chipFamily!==T)throw new Error(`rtcWdtResetChipSpecific() is not supported for ${this.chipFamily}`);t=1343315992,e=1343315968,i=1343315972,s=1356348065}await this.writeRegister(t,s,void 0,0),await this.writeRegister(i,2e3,void 0,0);await this.writeRegister(e,-805306110,void 0,0),await this.writeRegister(t,0,void 0,0),await r(500)}async resetToFirmwareMode(t=!0){this.logger.debug("Resetting from bootloader to firmware mode...");try{if(await this.detectUsbConnectionType()){let e;this.logger.debug("USB-JTAG/OTG detected - checking WDT reset support");try{e=await this.getUsbMode(),this.logger.debug(`USB mode: ${e.mode} (uartNo=${e.uartNo})`)}catch(t){this.logger.debug(`Could not get USB mode: ${t}`),e={mode:"usb-jtag-serial",uartNo:0}}if(!(this.chipFamily===C||this.chipFamily===E||this.chipFamily===T))return this.logger.debug(`${this.chipName} does not support WDT reset - using classic reset instead`),await this.hardResetToFirmware(),this.logger.debug("Classic reset to firmware complete"),!1;if(this.logger.debug(`${this.chipName} supports WDT reset - using WDT reset strategy`),this.IS_STUB){this.logger.debug("On stub - returning to ROM before WDT reset"),this.currentBaudRate!==h&&(this.logger.debug(`Changing baudrate from ${this.currentBaudRate} to 115200`),await this.reconfigurePort(h),this.currentBaudRate=h,this.logger.debug("Baudrate changed to 115200"));const t=this._consoleMode;this._consoleMode=!1,await this.hardReset(!0),await r(200),this._consoleMode=t,await this.sync(),this.IS_STUB=!1,this.logger.debug("Now on ROM")}else this.currentBaudRate!==h&&(this.logger.debug(`Not on stub, but baudrate is ${this.currentBaudRate} - changing to 115200 for WDT reset`),await this.reconfigurePort(h),this.currentBaudRate=h,this.logger.debug("Baudrate changed to 115200"));if(t&&"usb-otg"===e.mode){await this._clearForceDownloadBootIfNeeded()&&this.logger.debug("Force download boot flag cleared")}await this.rtcWdtResetChipSpecific(),this.logger.debug("WDT reset performed - device will boot to firmware");return!!("usb-otg"===e.mode||"usb-jtag-serial"===e.mode)&&(this.logger.debug(`Port will change after WDT reset (${e.mode}) - port reselection needed`),!0)}return this.logger.debug("External serial chip detected - using classic reset"),await this.hardResetToFirmware(),this.logger.debug("Classic reset to firmware complete"),!1}catch(t){throw this.logger.error(`Failed to reset to firmware mode: ${t}`),t}}async hardReset(t=!1){if(this._consoleMode)return t?void this.logger.debug("Skipping bootloader reset - device is in console mode"):(this.logger.debug("Performing hardware reset (console mode)..."),await this.resetInConsoleMode(),void this.logger.debug("Hardware reset complete"));if(t)4097===this.port.getInfo().usbProductId?(await this.hardResetUSBJTAGSerial(),this.logger.debug("USB-JTAG/Serial reset to bootloader.")):(await this.hardResetClassic(),this.logger.debug("Classic reset to bootloader."));else{this.logger.debug("Resetting to firmware mode...");if(await this.detectUsbConnectionType()){let t;this.logger.debug("USB-JTAG/OTG detected - using WDT reset");try{t=await this.getUsbMode(),this.logger.debug(`USB mode: ${t.mode} (uartNo=${t.uartNo})`)}catch(e){this.logger.debug(`Could not get USB mode: ${e}`),t={mode:"usb-jtag-serial",uartNo:0}}if("usb-otg"===t.mode)try{await this._clearForceDownloadBootIfNeeded()&&this.logger.debug("Force download boot flag cleared")}catch(t){this.logger.debug(`Could not clear force download flag: ${t}`)}return await this.rtcWdtResetChipSpecific(),void this.logger.debug(`${this.chipName}: WDT reset to firmware complete`)}this.logger.debug("External serial chip detected - using classic reset"),this.isWebUSB()?(await this.setRTSWebUSB(!0),await r(200),await this.setRTSWebUSB(!1),await r(200),this.logger.debug("Hard reset to firmware (WebUSB).")):(await this.setRTS(!0),await r(100),await this.setRTS(!1),this.logger.debug("Hard reset to firmware."))}await new Promise(t=>setTimeout(t,1e3))}macAddr(){const t=new Array(6).fill(0),e=this._efuses[0],i=this._efuses[1],s=this._efuses[2],a=this._efuses[3];let r;if(this.chipFamily==R){if(0!=a)r=[a>>16&255,a>>8&255,255&a];else if(i>>16&255){if(1!=(i>>16&255))throw new Error("Couldnt determine OUI");r=[172,208,116]}else r=[24,254,52];t[0]=r[0],t[1]=r[1],t[2]=r[2],t[3]=i>>8&255,t[4]=255&i,t[5]=e>>24&255}else if(this.chipFamily==v)t[0]=s>>8&255,t[1]=255&s,t[2]=i>>24&255,t[3]=i>>16&255,t[4]=i>>8&255,t[5]=255&i;else{if(this.chipFamily!=C&&this.chipFamily!=E&&this.chipFamily!=k&&this.chipFamily!=x&&this.chipFamily!=U&&this.chipFamily!=M&&this.chipFamily!=D&&this.chipFamily!=O&&this.chipFamily!=A&&this.chipFamily!=F&&this.chipFamily!=T&&this.chipFamily!=L)throw new Error("Unknown chip family");t[0]=i>>8&255,t[1]=255&i,t[2]=e>>24&255,t[3]=e>>16&255,t[4]=e>>8&255,t[5]=255&e}return t}async readRegister(t){this.debug&&this.logger.debug("Reading from Register "+s(t,8));const e=Mi("{a=Math.min(a,ut),await this.sendCommand(t,e,i);const[r,n]=await this.getResponse(t,a);if(null===n)throw new Error("Didn't get enough status bytes");let o=n,h=0;if(this.IS_STUB||this.chipFamily==R?h=2:[v,C,E,k,x,U,M,D,O,A,F,T,L].includes(this.chipFamily)||20===t?h=4:[2,4].includes(o.length)?h=o.length:(h=2,this.logger.debug(`Unknown chip family, defaulting to 2-byte status (opcode: ${s(t)}, data.length: ${o.length})`)),o.lengtht){throw new mt("Timed out waiting for packet "+(null===e?"header":"content"))}if(0!==this._inputBufferAvailable)for(;this._inputBufferAvailable>0;){if(Date.now()-n>t){throw new mt("Timed out waiting for packet "+(null===e?"header":"content"))}const r=this._readByte();if(null===e){if(r!=this.SLIP_END)throw this.debug&&(this.logger.debug("Read invalid data: "+s(r)),this.logger.debug("Remaining data in serial buffer: "+i(this._inputBuffer))),new mt("Invalid head of packet ("+s(r)+")");e=[]}else if(a)if(a=!1,r==this.SLIP_ESC_END)e.push(this.SLIP_END);else{if(r!=this.SLIP_ESC_ESC)throw this.debug&&(this.logger.debug("Read invalid data: "+s(r)),this.logger.debug("Remaining data in serial buffer: "+i(this._inputBuffer))),new mt("Invalid SLIP escape (0xdb, "+s(r)+")");e.push(this.SLIP_ESC)}else if(r==this.SLIP_ESC)a=!0;else{if(r==this.SLIP_END)return this.debug&&this.logger.debug("Received full packet: "+i(e)),this._compactInputBuffer(),e;e.push(r)}}else await r(1)}}else{let n=[];for(;;){if(this._abandonCurrentOperation)throw new mt("Operation abandoned (reset strategy timeout)");const o=Date.now();for(n=[];Date.now()-o0){n.push(this._readByte());break}await r(1)}if(0==n.length){throw new mt("Timed out waiting for packet "+(null===e?"header":"content"))}this.debug&&this.logger.debug("Read "+n.length+" bytes: "+i(n));for(const t of n)if(null===e){if(t!=this.SLIP_END)throw this.debug&&(this.logger.debug("Read invalid data: "+s(t)),this.logger.debug("Remaining data in serial buffer: "+i(this._inputBuffer))),new mt("Invalid head of packet ("+s(t)+")");e=[]}else if(a)if(a=!1,t==this.SLIP_ESC_END)e.push(this.SLIP_END);else{if(t!=this.SLIP_ESC_ESC)throw this.debug&&(this.logger.debug("Read invalid data: "+s(t)),this.logger.debug("Remaining data in serial buffer: "+i(this._inputBuffer))),new mt("Invalid SLIP escape (0xdb, "+s(t)+")");e.push(this.SLIP_ESC)}else if(t==this.SLIP_ESC)a=!0;else{if(t==this.SLIP_END)return this.debug&&this.logger.debug("Received full packet: "+i(e)),this._compactInputBuffer(),e;e.push(t)}}}}async getResponse(t,e=3e3){for(let i=0;i<100;i++){const i=await this.readPacket(e);if(i.length<8)continue;const[a,r,,n]=Di(">>24}async getC5CrystalFreqDetected(){const t=1048575&await this.readRegister(1610612756),e=h*t/1e6;return e>45?48:e>33?40:26}async setBaudrate(t){const e=this._parent?this._parent.chipFamily:this.chipFamily;if(this.IS_STUB||e!==U)try{const e=Mi("i&&(this.logger.log(`⚠️ WARNING: Baudrate ${t} exceeds USB-Serial chip limit (${i})!`),this.logger.log("⚠️ This may cause data corruption or connection failures!")),this.logger.debug(`Changed baud rate to ${t}`)}async setBaudrateC5Rom(t){const e=await this.getC5CrystalFreqRomExpect(),i=await this.getC5CrystalFreqDetected();this.logger.log(`ROM expects crystal freq: ${e} MHz, detected ${i} MHz.`);let s=t;48===i&&40===e?s=Math.trunc(40*t/48):40===i&&48===e&&(s=Math.trunc(48*t/40)),this.logger.log(`Changing baud rate to ${s}...`);try{const t=Mi("t)return!1;if(this._abandonCurrentOperation)return!1;this._clearInputBuffer();try{if(await this._sync())return await r(gt),!0}catch(t){if(this._abandonCurrentOperation)return!1}await r(gt)}return!1}async sync(){for(let t=0;t<5;t++){this._clearInputBuffer();if(await this._sync())return await r(gt),!0;await r(gt)}throw new Error("Couldn't sync to ESP. Try resetting.")}async _sync(){await this.sendCommand(8,I);for(let t=0;t<8;t++)try{const[,t]=await this.getResponse(8,gt);if(t.length>1&&0==t[0]&&0==t[1])return!0}catch(e){this.debug&&this.logger.debug(`Sync attempt ${t+1} failed: ${e}`)}return!1}getFlashWriteSize(){return this.IS_STUB?16384:1024}async flashData(t,e,i=0,a=!1){if(t.byteLength>=8){const e=Array.from(new Uint8Array(t,0,4)),i=e[0],a=e[2],r=e[3];this.logger.log(`Image header, Magic=${s(i)}, FlashMode=${s(a)}, FlashSizeFreq=${s(r)}`)}const r=(t=function(t,e,i=255){const s=t.length%e;if(0!==s){const a=new Uint8Array(e-s).fill(i),r=new Uint8Array(t.length+a.length);return r.set(t),r.set(a,t.length),r}return t}(new Uint8Array(t),4).buffer).byteLength;let n,o=0,h=dt;a?(n=xi(new Uint8Array(t),{level:9}).buffer,o=n.byteLength,this.logger.log(`Writing data with filesize: ${r}. Compressed Size: ${o}`),h=await this.flashDeflBegin(r,o,i)):(this.logger.log(`Writing data with filesize: ${r}`),n=t,await this.flashBegin(r,i));let l=[],d=0,c=0,u=0;const g=Date.now(),f=this.getFlashWriteSize(),_=a?o:r;for(;_-u>0;)this.debug&&this.logger.log(`Writing at ${s(i+d*f,8)} `),_-u>=f?l=Array.from(new Uint8Array(n,u,f)):(l=Array.from(new Uint8Array(n,u,_-u)),a||(l=l.concat(new Array(f-l.length).fill(255)))),a?await this.flashDeflBlock(l,d,h):await this.flashBlock(l,d),d+=1,c+=a?Math.round(l.length*r/o):l.length,u+=f,e(Math.min(c,r),r);this.logger.log("Took "+(Date.now()-g)+"ms to write "+_+" bytes"),this.IS_STUB&&(await this.flashBegin(0,0),a?await this.flashDeflFinish():await this.flashFinish())}async flashBlock(t,e,i=3e3){await this.checkCommand(3,Mi("0&&(r=r.concat(Mi("0&&await this.writeRegister(s,e-1),i>0&&await this.writeRegister(a,i-1)}else{const s=t.regBase+t.usr1Offs,a=(0==i?0:i-1)<<8|(0==e?0:e-1)<<17;await this.writeRegister(s,a)}}async waitDone(t,e){for(let i=0;i<10;i++){if(0==(await this.readRegister(t)&e))return}throw Error("SPI command did not complete in time")}async runSpiFlashCommand(t,e,i=0){const a=wt(this.getChipFamily()),r=a.regBase,n=r,o=r+a.usrOffs,h=r+a.usr2Offs,l=r+a.w0Offs,d=1<<18;if(i>32)throw new Error("Reading more than 32 bits back from a SPI flash operation is unsupported");if(e.length>64)throw new Error("Writing more than 64 bytes of data with one SPI command is unsupported");const c=8*e.length,u=await this.readRegister(o),g=await this.readRegister(h);let f=1<<31;if(i>0&&(f|=268435456),c>0&&(f|=134217728),await this.setDataLengths(a,c,i),await this.writeRegister(o,f),await this.writeRegister(h,7<<28|t),0==c)await this.writeRegister(l,0);else{const t=(4-e.length%4)%4;e=e.concat(new Array(t).fill(0));const i=Di("I".repeat(Math.floor(e.length/4)),e);let a=l;this.logger.debug(`Words Length: ${i.length}`);for(const t of i)this.logger.debug(`Writing word ${s(t)} to register offset ${s(a)}`),await this.writeRegister(a,t),a+=4}await this.writeRegister(n,d),await this.waitDone(n,d);const _=await this.readRegister(l);return await this.writeRegister(o,u),await this.writeRegister(h,g),_}async detectFlashSize(){this.logger.debug("Detecting Flash Size");const t=await this.flashId(),e=255&t,i=t>>16&255,s=(t>>8&255)<<8|i,a=St[e],r=Bt[e<<16|s];this.logger.log(`Flash Manufacturer: ${a||"Unknown"} (0x${e.toString(16)})`),this.logger.log(`Flash Device: ${r||`Unknown (0x${s.toString(16)})`}`),this.flashSize=n[i],this.logger.log(`Auto-detected Flash size: ${this.flashSize}`)}getEraseSize(t,e){const i=o,s=Math.floor((e+i-1)/i);let a=16-Math.floor(t/i)%16;return sr&&(a=r),await this.memBlock(s.slice(e,a),t)}}await this.memFinish(e.entry);const s=await this.readPacket(500),a=String.fromCharCode(...s);if("OHAI"!=a)throw new Error("Failed to start stub. Unexpected response: "+a);this.logger.debug("Stub is now running...");const r=new Ai(this.port,this.logger,this);return t||await r.detectFlashSize(),r}get _writer(){return this._parent?this._parent._writer:this.__writer}set _writer(t){this._parent?this._parent._writer=t:this.__writer=t}get _writeChain(){return this._parent?this._parent._writeChain:this.__writeChain}set _writeChain(t){this._parent?this._parent._writeChain=t:this.__writeChain=t}async writeToStream(t){if(this.port.writable){if(this._isReconfiguring)throw new Error("Cannot write during port reconfiguration");this._writeChain=this._writeChain.then(async()=>{if(!this.port.writable)throw new Error("Port became unavailable during write");if(!this._writer)try{this._writer=this.port.writable.getWriter()}catch(t){throw this.logger.error(`Failed to get writer: ${t}`),t}await this._writer.write(new Uint8Array(t))},async()=>{if(this.logger.debug("Previous write failed, attempting recovery for current write"),!this.port.writable)throw new Error("Port became unavailable during write");if(!this._writer)try{this._writer=this.port.writable.getWriter()}catch(t){throw this.logger.debug(`Failed to get writer in recovery: ${t}`),new Error("Cannot acquire writer lock")}await this._writer.write(new Uint8Array(t))}).catch(t=>{if(this.logger.error(`Write error: ${t}`),this._writer){try{this._writer.releaseLock()}catch{}this._writer=void 0}throw t}),await this._writeChain}else this.logger.debug("Port writable stream not available, skipping write")}async disconnect(){if(this._parent)await this._parent.disconnect();else if(this.port.writable){try{await this._writeChain}catch(t){}if(this._writer){try{await this._writer.close(),this._writer.releaseLock()}catch(t){}this._writer=void 0}else try{const t=this.port.writable.getWriter();await t.close(),t.releaseLock()}catch(t){}await new Promise(t=>{if(!this._reader)return void t(void 0);const e=setTimeout(()=>{this.logger.debug("Disconnect timeout - forcing resolution"),t(void 0)},1e3);this.addEventListener("disconnect",()=>{clearTimeout(e),t(void 0)},{once:!0});try{this._reader.cancel()}catch(i){clearTimeout(e),t(void 0)}}),this.connected=!1;try{await this.port.close(),this.logger.debug("Port closed successfully")}catch(t){this.logger.debug(`Port close error: ${t}`)}}}async releaseReaderWriter(){if(this._parent)await this._parent.releaseReaderWriter();else{try{await this._writeChain}catch(t){}if(this._writer){try{this._writer.releaseLock(),this.logger.debug("Writer released")}catch(t){this.logger.debug(`Writer release error: ${t}`)}this._writer=void 0}if(this._reader)try{this._suppressDisconnect=!0,await this._reader.cancel(),this.logger.debug("Reader cancelled - waiting for readLoop to finish"),await r(50),this.logger.debug("ReadLoop cleanup should be complete")}catch(t){this.logger.debug(`Reader cancel error: ${t}`)}}}async resetToFirmware(){return await this._resetToFirmwareIfNeeded()}async detectUsbConnectionType(){const t=this.port.getInfo(),e=t.usbProductId;if(!(12346===t.usbVendorId))return this.logger.debug("Not Espressif VID - external serial chip"),!1;const i=[2,18,4097].includes(e||0);return this.logger.debug(`USB-JTAG/OTG detection: ${i?"YES":"NO"} (PID=0x${null==e?void 0:e.toString(16)})`),i}async getUsbMode(){var t,e;const i=this._parent?this._parent.chipFamily:this.chipFamily,s=this._parent?null!==(t=this._parent.chipRevision)&&void 0!==t?t:0:null!==(e=this.chipRevision)&&void 0!==e?e:0;let a=null,r=null,n=null;switch(i){case C:a=1073741076,n=2;break;case E:a=1070526796,r=4,n=3;break;case x:a=(s<101?1070461028:1070461024)+24,r=3;break;case U:a=1082520852,r=3;break;case M:a=1082652032,r=3;break;case D:a=s<=200?1082455532:1082455524,r=s<=200?3:4;break;case O:a=1082457852,r=3;break;case A:a=1082652032,r=3;break;case T:a=s<300?1341390536:1341914824,r=6,n=5}if(null===a)return{mode:"uart",uartNo:0};const o=255&await this.readRegister(a);return null!==n&&o===n?(this.logger.debug(`USB mode: USB-OTG (uartNo=${o})`),{mode:"usb-otg",uartNo:o}):null!==r&&o===r?(this.logger.debug(`USB mode: USB-JTAG/Serial (uartNo=${o})`),{mode:"usb-jtag-serial",uartNo:o}):(this.logger.debug(`USB mode: UART (uartNo=${o})`),{mode:"uart",uartNo:o})}supportsNativeUsb(){const t=this._parent?this._parent.chipFamily:this.chipFamily;return[C,E,x,U,M,D,O,A,T].includes(t)}async _ensureStreamsReady(){if(this.isWebUSB())try{await this.port.recreateStreams(),this.logger.debug("WebUSB streams recreated");let t=30;for(;t>0&&!this.port.readable;)await r(100),t--;if(!this.port.readable)throw new Error("Readable stream not available after recreating streams");this.logger.debug("WebUSB streams are ready")}catch(t){throw this.logger.error(`Failed to recreate WebUSB streams: ${t}`),this._consoleMode=!1,t}else{let t=20;for(;t>0&&!this.port.readable;)await r(100),t--;if(!this.port.readable)throw this._consoleMode=!1,new Error("Readable stream not available after reset");this.logger.debug("Port streams are ready")}}async enterConsoleMode(){if(!this.port.writable||!this.port.readable)return this.logger.debug("Port is not open - port selection needed"),!0;let t;try{t=await this.detectUsbConnectionType(),this.logger.debug("USB connection type detected: "+(t?"USB-JTAG/OTG":"External Serial Chip")),this._isUsbJtagOrOtg=t}catch(e){if(void 0===this.isUsbJtagOrOtg)throw new Error(`Cannot enter console mode: USB connection type unknown and detection failed: ${e}`);this.logger.debug(`USB detection failed, using cached value: ${this.isUsbJtagOrOtg}`),t=this.isUsbJtagOrOtg}if(this._consoleMode=!0,t){return!!await this._resetToFirmwareIfNeeded()||(await this._ensureStreamsReady(),!1)}try{await this.releaseReaderWriter(),await r(100)}catch(t){this.logger.debug(`Failed to release locks: ${t}`)}try{await this.hardResetToFirmware(),this.logger.debug("Device reset to firmware mode")}catch(t){this.logger.debug(`Could not reset device: ${t}`)}return await this._ensureStreamsReady(),!1}async _clearForceDownloadBootIfNeeded(){try{let t,e,i;if(this.chipFamily===C)t=1061191976,e=1,i="ESP32-S2";else if(this.chipFamily===E)t=1610645804,e=1,i="ESP32-S3";else{if(this.chipFamily!==T)return!1;t=1343291400,e=4,i="ESP32-P4"}const s=await this.readRegister(t);this.logger.debug(`${i} force download boot register: 0x${s.toString(16)} (mask: 0x${e.toString(16)})`);return 0!==(s&e)?(this.logger.debug(`${i} force download boot flag is SET - clearing it`),await this.writeRegister(t,0,e,0),this.logger.debug(`${i} force download boot flag cleared`),!0):(this.logger.debug(`${i} force download boot flag is already CLEAR - no action needed`),!1)}catch(t){return this.logger.debug(`Error checking/clearing force download flag: ${t}`),!1}}async _resetToFirmwareIfNeeded(){const t=await this.detectUsbConnectionType();try{if(!this.port.writable||!this.port.readable)return this.logger.debug("Port is not open - assuming device is already in firmware mode"),!1;t?this.logger.debug("USB-JTAG/OTG: Keeping reader/writer active for WDT reset"):(await this.releaseReaderWriter(),this.logger.debug("External serial: Reader/writer released before reset"));return await this.resetToFirmwareMode(!0)?(this.logger.debug(`${this.chipName}: Port will change after WDT reset - user must reselect port`),this.dispatchEvent(new CustomEvent("usb-otg-port-change",{detail:{chipName:this.chipName,message:`${this.chipName} USB port changed after reset. Please select the new port.`,reason:"wdt-reset-to-firmware"}})),!0):(t&&(await this.releaseReaderWriter(),this.logger.debug("Reader/writer released after reset")),!1)}catch(e){return this.logger.error(`Reset to firmware mode failed: ${e}`),t?(this.logger.debug("Forcing port reselection due to USB-JTAG/OTG reset failure"),!0):(this.logger.debug("External serial reset failed, but port should still be usable"),!1)}}async reconnect(){if(this._parent)await this._parent.reconnect();else try{this.logger.log("Reconnecting serial port...");const t=this.currentBaudRate;this.connected=!1,this.__inputBuffer=[],this.__inputBufferReadIndex=0;try{await this._writeChain}catch(t){this.logger.debug(`Pending write error during reconnect: ${t}`)}if(this._isReconfiguring=!0,this._writer){try{this._writer.releaseLock()}catch(t){this.logger.debug(`Writer release error during reconnect: ${t}`)}this._writer=void 0}if(this._reader){try{await this._reader.cancel()}catch(t){this.logger.debug(`Reader cancel error: ${t}`)}this._reader=void 0}try{await this.port.close(),this.logger.debug("Port closed")}catch(t){this.logger.debug(`Port close error: ${t}`)}this.logger.debug("Opening port...");try{await this.port.open({baudRate:h}),this.connected=!0,this.currentBaudRate=h}catch(t){throw new Error(`Failed to open port: ${t}`)}if(!this.port.readable||!this.port.writable)throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);this._isReconfiguring=!1;const e=this.chipFamily,i=this.chipName,s=this.chipRevision,a=this.chipVariant,r=this.flashSize;if(await this.hardReset(!0),this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0,this.__totalBytesRead=0,this.readLoop()),await this.flushSerialBuffers(),await this.sync(),this.chipFamily=e,this.chipName=i,this.chipRevision=s,this.chipVariant=a,this.flashSize=r,this.logger.debug(`Reconnect complete (chip: ${this.chipName})`),!this.port.writable||!this.port.readable)throw new Error("Port not ready after reconnect");this.chipFamily===T&&301===this.chipRevision&&await this.powerOnFlash();const n=await this.runStub(!0);if(this.logger.debug("Stub loaded"),t!==h&&(await n.setBaudrate(t),!this.port.writable||!this.port.readable))throw new Error(`Port not ready after baudrate change (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);this.IS_STUB=!0,this.logger.debug("Reconnection successful")}catch(t){throw this._isReconfiguring=!1,t}}async reconnectToBootloader(){if(this._parent)await this._parent.reconnectToBootloader();else try{this.logger.log("Reconnecting to bootloader mode..."),this._consoleMode=!1,this.connected=!1,this.__inputBuffer=[],this.__inputBufferReadIndex=0;try{await this._writeChain}catch(t){this.logger.debug(`Pending write error during reconnect: ${t}`)}if(this._isReconfiguring=!0,this._writer){try{this._writer.releaseLock()}catch(t){this.logger.debug(`Writer release error during reconnect: ${t}`)}this._writer=void 0}if(this._reader){try{await this._reader.cancel()}catch(t){this.logger.debug(`Reader cancel error: ${t}`)}this._reader=void 0}try{await this.port.close(),this.logger.debug("Port closed")}catch(t){this.logger.debug(`Port close error: ${t}`)}this.logger.debug("Opening port...");try{await this.port.open({baudRate:h}),this.connected=!0,this.currentBaudRate=h}catch(t){throw new Error(`Failed to open port: ${t}`)}if(!this.port.readable||!this.port.writable)throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);this._isReconfiguring=!1,this.__chipFamily=void 0,this.chipName="Unknown Chip",this.chipRevision=null,this.chipVariant=null,this.IS_STUB=!1,this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0,this.__totalBytesRead=0,this.readLoop()),await r(100),await this.connectWithResetStrategies(),await this.detectChip(),this.logger.debug(`Reconnected to bootloader: ${this.chipName}`)}catch(t){throw this._isReconfiguring=!1,t}}async exitConsoleMode(){if(this._parent)return await this._parent.exitConsoleMode();this._consoleMode=!1;const t=this.chipFamily===C||this.chipFamily===T;let e=this._isUsbJtagOrOtg;if(t&&void 0===e)try{e=await this.detectUsbConnectionType()}catch(t){this.logger.debug(`USB detection failed, assuming USB-JTAG/OTG for ${this.chipName}: ${t}`),e=!0}if(t&&e){this.logger.debug(`${this.chipName} USB: Resetting to bootloader mode`);try{await this.hardResetClassic(),this.logger.debug("Reset to bootloader initiated")}catch(t){this.logger.debug(`Reset error: ${t}`)}return await r(500),this.logger.debug(`${this.chipName}: Port changed. Please select the bootloader port.`),this.dispatchEvent(new CustomEvent("usb-otg-port-change",{detail:{chipName:this.chipName,message:`${this.chipName}: Port changed. Please select the bootloader port.`,reason:"exit-console-to-bootloader"}})),!0}return await this.reconnectToBootloader(),!1}isConsoleResetSupported(){if(this._parent)return this._parent.isConsoleResetSupported();return!(this.chipFamily===C&&(!0===this._isUsbJtagOrOtg||void 0===this._isUsbJtagOrOtg))}async resetInConsoleMode(){if(this._parent)return await this._parent.resetInConsoleMode();if(!this.isConsoleResetSupported())return this.logger.debug("Simple Console reset not supported for ESP32-S2 USB-JTAG/CDC - using exitConsoleMode to enter bootloader"),await this.exitConsoleMode(),void this.logger.debug("S2 now in bootloader mode - caller must do syncAndWdtReset on new port, then reconnect console");try{this.logger.debug("Resetting device in console mode"),await this.hardResetToFirmware(),this.logger.debug("Device reset complete")}catch(t){throw this.logger.error(`Reset failed: ${t}`),t}}async syncAndWdtReset(t){this._parent?await this._parent.syncAndWdtReset(t):(this.port=t,this.connected=!1,this.IS_STUB=!1,this.__inputBuffer=[],this.__inputBufferReadIndex=0,this.__totalBytesRead=0,this.logger.debug("Opening bootloader port at 115200..."),await this.port.open({baudRate:h}),this.connected=!0,this.currentBaudRate=h,this.readLoop(),await r(100),this.logger.debug("Syncing with bootloader ROM..."),await this.sync(),this.logger.debug("Bootloader sync OK, no stub"),this.logger.debug("Firing WDT reset..."),await this.rtcWdtResetChipSpecific(),this.logger.debug("WDT reset fired - device will boot to firmware"))}async drainInputBuffer(t=200){await r(t);let e=0;const i=Date.now();for(;e<112&&Date.now()-i<100;)if(this._inputBufferAvailable>0){void 0!==this._readByte()&&e++}else await r(1);e>0&&this.logger.debug(`Drained ${e} bytes from input buffer`),this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0)}async flushSerialBuffers(){this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0),await r(gt),this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0),this.logger.debug("Serial buffers flushed")}async readFlash(e,i,s,a){if(!this.IS_STUB)throw new Error("Reading flash is only supported in stub mode. Please run runStub() first.");await this.flushSerialBuffers();const n=Date.now();let o;this.logger.log(`Reading ${i} bytes from flash at address 0x${e.toString(16)}...`),this.isWebUSB()&&(this._isCDCDevice?(this._adaptiveBlockMultiplier=8,this._adaptiveMaxInFlightMultiplier=8,this._consecutiveSuccessfulChunks=0,this.logger.debug(`CDC device - Initialized: blockMultiplier=${this._adaptiveBlockMultiplier}, maxInFlightMultiplier=${this._adaptiveMaxInFlightMultiplier}`)):(this._adaptiveBlockMultiplier=1,this._adaptiveMaxInFlightMultiplier=1,this._consecutiveSuccessfulChunks=0,this.logger.debug("Non-CDC device - Fixed values: blockSize=31, maxInFlight=31"))),void 0!==(null==a?void 0:a.chunkSize)?(o=a.chunkSize,this.logger.log(`Using custom chunk size: 0x${o.toString(16)} bytes`)):o=this.isWebUSB()?16384:262144;let h=new Uint8Array(0),l=e,d=i;for(;d>0;){const e=Math.min(o,d);let n=!1,c=0;const u=5;let g=!1;for(;!n&&c<=u;){let i=new Uint8Array(0),s=0;try{let o,d;if(0===c&&this.logger.debug(`Reading chunk at 0x${l.toString(16)}, size: 0x${e.toString(16)}`),void 0!==(null==a?void 0:a.blockSize)&&void 0!==(null==a?void 0:a.maxInFlight))o=a.blockSize,d=a.maxInFlight,0===c&&this.logger.debug(`Using custom parameters: blockSize=${o}, maxInFlight=${d}`);else if(this.isWebUSB()){const t=this.port.maxTransferSize||64,e=Math.floor((t-2)/2);o=e*this._adaptiveBlockMultiplier,d=e*this._adaptiveMaxInFlightMultiplier}else{const t=63;o=65*t,d=130*t}const u=Mi("=e)break}throw t}if(a&&a.length>0){const r=new Uint8Array(a),n=new Uint8Array(i.length+r.length);n.set(i),n.set(r,i.length),i=n;if(i.length>=e||i.length>=s+d){const e=Mi("=2)){const t=this.port.maxTransferSize||64,e=Math.floor((t-2)/2),i=8,s=8;let a=!1;if(this._adaptiveBlockMultiplier1||this._adaptiveMaxInFlightMultiplier>1){this._adaptiveBlockMultiplier=1,this._adaptiveMaxInFlightMultiplier=1,this._consecutiveSuccessfulChunks=0;const t=this.port.maxTransferSize||64,e=Math.floor((t-2)/2),i=e*this._adaptiveBlockMultiplier,s=e*this._adaptiveMaxInFlightMultiplier;this.logger.debug(`Error at higher speed - reduced to minimum: blockSize=${i}, maxInFlight=${s}`)}else this.logger.debug("Error at minimum speed (blockSize=31, maxInFlight=31) - not a speed issue");if(!(t instanceof mt))throw t;if(c<=u)this.logger.debug(`Cleared buffer and retrying (attempt ${c}/${u})...`);else{if(g)throw new Error(`Failed to read chunk at 0x${l.toString(16)} after ${u} retries and recovery attempt`);g=!0,this.logger.log(`All retries exhausted at 0x${l.toString(16)}. Attempting recovery (close and reopen port)...`);try{await this.reconnect(),this.logger.log("Deep recovery successful. Resuming read from current position..."),c=0;continue}catch(t){throw new Error(`Failed to read chunk at 0x${l.toString(16)} after ${u} retries and recovery failed: ${t}`)}}}}s&&s(new Uint8Array(e),h.length,i),l+=e,d-=e,this.logger.debug(`Total progress: 0x${h.length.toString(16)} from 0x${i.toString(16)} bytes`)}const c=Date.now()-n,u=(h.length/1024/(c/1e3)).toFixed(1);return this.logger.log(`Read complete: ${h.length} bytes in ${(c/1e3).toFixed(1)} s (${u} KB/s)`),h}}class Ai extends Oi{constructor(){super(...arguments),this.IS_STUB=!0}async memBegin(t,e,i,a){const r=await yt(this.chipFamily,this.chipRevision);if(null===r)return[0,[]];const n=a,o=a+t;this.logger.debug(`Load range: ${s(n,8)}-${s(o,8)}`),this.logger.debug(`Stub data: ${s(r.data_start,8)}, len: ${r.data.length}, text: ${s(r.text_start,8)}, len: ${r.text.length}`);for(const[t,e]of[[r.data_start,r.data_start+r.data.length],[r.text_start,r.text_start+r.text.length]])if(nt)throw new Error("Software loader is resident at "+s(t,8)+"-"+s(e,8)+". Can't load binary at overlapping address range "+s(n,8)+"-"+s(o,8)+". Try changing the binary loading address.");return[0,[]]}async eraseFlash(){await this.checkCommand(208,[],0,ct)}async eraseRegion(t,e){if(t<0)throw new Error(`Invalid offset: ${t} (must be non-negative)`);if(e<0)throw new Error(`Invalid size: ${e} (must be non-negative)`);if(0===e)return void this.logger.log("eraseRegion: size is 0, skipping erase");if(t%o!==0)throw new Error(`Offset ${t} (0x${t.toString(16)}) is not aligned to flash sector size 4096 (0x${o.toString(16)})`);if(e%o!==0)throw new Error(`Size ${e} (0x${e.toString(16)}) is not aligned to flash sector size 4096 (0x${o.toString(16)})`);const i=4294967295;if(t>i)throw new Error(`Offset ${t} exceeds maximum value 4294967295`);if(e>i)throw new Error(`Size ${e} exceeds maximum value 4294967295`);if(t+e>i)throw new Error(`Region end (offset + size = ${t+e}) exceeds maximum addressable range 4294967295`);const s=bt(ft,e),a=Mi("t.length)break;const r=t.slice(s,s+i),n=r[0]|r[1]<<8;for(let t=0;t=32&&r[e]<127)i++;else if(0===r[e])break;if(i>=4){e+=5;break}}if(32768&n){const t=32767&n;t>0&&t<4096&&(e+=2)}}return e>=10}function Hi(t,e,i){const s=Ni;for(const a of s)for(let s=0;s<2;s++){const r=s*a,n=r+8;if(n+8>t.length)continue;if("littlefs"===String.fromCharCode(t[n],t[n+1],t[n+2],t[n+3],t[n+4],t[n+5],t[n+6],t[n+7])){const s=r+16,n=t[s]|t[s+1]<<8|t[s+2]<<16|t[s+3]<<24;if(0!==n&&n>>>0!=4294967295){const s=r+24;if(s+4<=t.length){const r=t[s]|t[s+1]<<8|t[s+2]<<16|t[s+3]<<24;if(r>0&&r<1e5){const t=r*a;if(t>0&&e+t<=i)return{start:e,end:e+t,size:t,page:256,block:a}}}return Ji(e,i,a)}}}if(Gi(t))return Ji(e,i,ji);if(t.length>=4){if(538182953===(t[0]|t[1]<<8|t[2]<<16|t[3]<<24)){let s=!0;if(t.length>=16){let e=!0;for(let i=4;i<16;i++)if(255!==t[i]){e=!1;break}e&&(s=!1)}if(s)return Ji(e,i,ji)}}const a=[0,4096];for(const s of a){if(t.length0&&r>0&&r<1e8){const t=r*a,n=e+s;if(t>0&&n+t<=i)return{start:n,end:n+t,size:t,page:a,block:a}}}}return null}function Ji(t,e,i){const s=e/1048576;if(s>=16){if(1048576===t)return{start:1048576,end:16752640,size:15704064,page:256,block:i};if(2097152===t)return{start:2097152,end:16752640,size:14655488,page:256,block:i}}if(s>=8){if(1048576===t)return{start:1048576,end:8364032,size:7315456,page:256,block:i};if(2097152===t)return{start:2097152,end:8364032,size:6266880,page:256,block:i}}if(s>=4){if(1048576===t)return{start:1048576,end:4169728,size:3121152,page:256,block:i};if(2097152===t)return{start:2097152,end:4169728,size:2072576,page:256,block:i};if(3145728===t)return{start:3145728,end:4169728,size:1024e3,page:256,block:i}}if(s>=2){if(1048576===t)return{start:1048576,end:2072576,size:1024e3,page:256,block:i};if(1572864===t)return{start:1572864,end:2072576,size:499712,page:256,block:i};if(1835008===t)return{start:1835008,end:2076672,size:241664,page:256,block:i};if(1966080===t)return{start:1966080,end:2076672,size:110592,page:256,block:i};if(2031616===t)return{start:2031616,end:2076672,size:45056,page:256,block:i}}if(s>=1){if(503808===t)return{start:503808,end:1028096,size:524288,page:256,block:i};if(765952===t)return{start:765952,end:1028096,size:262144,page:256,block:i};if(831488===t)return{start:831488,end:1028096,size:196608,page:256,block:i};if(864256===t)return{start:864256,end:1028096,size:163840,page:256,block:i};if(880640===t)return{start:880640,end:1028096,size:147456,page:256,block:i};if(897024===t)return{start:897024,end:1028096,size:131072,page:256,block:i};if(962560===t)return{start:962560,end:1028096,size:65536,page:256,block:i}}if(s>=.5){if(372736===t)return{start:372736,end:503808,size:131072,page:256,block:i};if(438272===t)return{start:438272,end:503808,size:65536,page:256,block:i};if(471040===t)return{start:471040,end:503808,size:32768,page:256,block:i}}return{start:t,end:e,size:e-t,page:256,block:i}}function Qi(t){return t>=16?[{start:1048576,end:16752640,size:15704064,page:256,block:8192},{start:2097152,end:16752640,size:14655488,page:256,block:8192}]:t>=8?[{start:1048576,end:8364032,size:7315456,page:256,block:8192},{start:2097152,end:8364032,size:6266880,page:256,block:8192}]:t>=4?[{start:2097152,end:4169728,size:2072576,page:256,block:8192},{start:1048576,end:4169728,size:3121152,page:256,block:8192},{start:3145728,end:4169728,size:1024e3,page:256,block:8192}]:t>=2?[{start:1048576,end:2072576,size:1024e3,page:256,block:8192},{start:1572864,end:2072576,size:499712,page:256,block:8192},{start:1835008,end:2076672,size:241664,page:256,block:8192},{start:1966080,end:2076672,size:110592,page:256,block:8192},{start:2031616,end:2076672,size:45056,page:256,block:8192}]:t>=1?[{start:897024,end:1028096,size:131072,page:256,block:8192},{start:503808,end:1028096,size:524288,page:256,block:8192},{start:765952,end:1028096,size:262144,page:256,block:8192},{start:831488,end:1028096,size:196608,page:256,block:8192},{start:864256,end:1028096,size:163840,page:256,block:8192},{start:880640,end:1028096,size:147456,page:256,block:8192},{start:962560,end:1028096,size:65536,page:256,block:8192}]:t>=.5?[{start:372736,end:503808,size:131072,page:256,block:8192},{start:438272,end:503808,size:65536,page:256,block:8192},{start:471040,end:503808,size:32768,page:256,block:8192}]:[]}var Vi;function Zi(t){return 1!==t.type?Vi.UNKNOWN:129===t.subtype?Vi.FATFS:Vi.UNKNOWN}function Xi(t,e){if(t.length<512)return Vi.UNKNOWN;const i=(null==e?void 0:e.toUpperCase().includes("ESP8266"))?Ni:Ti;for(const e of i)for(let i=0;i<2;i++){const s=i*e;if(s+20>t.length)continue;const a=s+8;if(a+8<=t.length){if("littlefs"===String.fromCharCode(t[a],t[a+1],t[a+2],t[a+3],t[a+4],t[a+5],t[a+6],t[a+7])){const e=s+16,i=t[e]|t[e+1]<<8|t[e+2]<<16|t[e+3]<<24;if(0!==i&&i>>>0!=4294967295)return Vi.LITTLEFS}}}const s=[0,4096];for(const e of s){if(t.length=e+62?String.fromCharCode(t[e+54],t[e+55],t[e+56],t[e+57],t[e+58]):"",s=t.length>=e+90?String.fromCharCode(t[e+82],t[e+83],t[e+84],t[e+85],t[e+86]):"";if(i.startsWith("FAT")||s.startsWith("FAT"))return Vi.FATFS}}if(t.length>=4){if(538182953===(t[0]|t[1]<<8|t[2]<<16|t[3]<<24))return Vi.SPIFFS}return Gi(t)?Vi.SPIFFS:Vi.UNKNOWN}function Ki(t,e){const i=null==e?void 0:e.toUpperCase().includes("ESP8266");switch(t){case Vi.FATFS:return 4096;case Vi.LITTLEFS:default:return i?Pi:4096}}function qi(t,e){const i=null==e?void 0:e.toUpperCase().includes("ESP8266");switch(t){case Vi.FATFS:return zi;case Vi.LITTLEFS:return i?Ni:Ti;default:return i?Ni:[4096,2048,1024,512]}}!function(t){t.UNKNOWN="unknown",t.LITTLEFS="littlefs",t.FATFS="fatfs",t.SPIFFS="spiffs"}(Vi||(Vi={}));const Yi={0:"app",1:"data"},ts={0:"factory",16:"ota_0",17:"ota_1",18:"ota_2",19:"ota_3",20:"ota_4",21:"ota_5",22:"ota_6",23:"ota_7",24:"ota_8",25:"ota_9",26:"ota_10",27:"ota_11",28:"ota_12",29:"ota_13",30:"ota_14",31:"ota_15",32:"test"},es={0:"ota",1:"phy",2:"nvs",3:"coredump",4:"nvs_keys",5:"efuse",128:"esphttpd",129:"fat",130:"spiffs",131:"littlefs"};function is(t){if(t.length<32)return null;if(20650!==(65535&(t[0]|t[1]<<8)))return null;const e=t[2],i=t[3],s=t[4]|t[5]<<8|t[6]<<16|t[7]<<24,a=t[8]|t[9]<<8|t[10]<<16|t[11]<<24;let r="";for(let e=12;e<28&&0!==t[e];e++)r+=String.fromCharCode(t[e]);const n=t[28]|t[29]<<8|t[30]<<16|t[31]<<24,o=Yi[e]||`unknown(0x${e.toString(16)})`;let h="";return h=0===e?ts[i]||`unknown(0x${i.toString(16)})`:1===e?es[i]||`unknown(0x${i.toString(16)})`:`0x${i.toString(16)}`,{name:r,type:e,subtype:i,offset:s,size:a,flags:n,typeName:o,subtypeName:h}}function ss(t){const e=[];for(let i=0;i=2)for(let s=0;sthis.buildConfig.objNameLen)throw new Error(`object name '${t}' too long`);const i=t;let s=0;try{this.blocks[this.blocks.length-1].beginObj(this.curObjId,e.length,i)}catch{this.createBlock().beginObj(this.curObjId,e.length,i)}for(;s0;){const s=new us(e,this.buildConfig);t.push(s.toBinary(this.blocksLim)),i--,e++}else{const e=this.imgSize-t.length*this.buildConfig.blockSize;if(e>0){const i=new Uint8Array(e);i.fill(255),t.push(i)}}const s=t.reduce((t,e)=>t+e.length,0),a=new Uint8Array(s);let r=0;for(const e of t)a.set(e,r),r+=e.length;return a}listFiles(){throw new Error("listFiles requires fromBinary to be called first")}readFile(){throw new Error("readFile requires fromBinary to be called first")}deleteFile(){throw new Error("deleteFile not yet implemented - requires filesystem recreation")}}class fs{constructor(t,e){this.imageData=t,this.buildConfig=e,this.filesMap=new Map}unpack(t,e,i=0){const s=new DataView(e.buffer,e.byteOffset+i),a=[];let r=0;for(const e of t)switch(e){case"B":a.push(s.getUint8(r)),r+=1;break;case"H":a.push("little"===this.buildConfig.endianness?s.getUint16(r,!0):s.getUint16(r,!1)),r+=2;break;case"I":a.push("little"===this.buildConfig.endianness?s.getUint32(r,!0):s.getUint32(r,!1)),r+=4}return a}parse(){const t=Math.floor(this.imageData.length/this.buildConfig.blockSize);for(let e=0;es.length);t+=this.buildConfig.objIdLen){const e=s.slice(t,t+this.buildConfig.objIdLen),[i]=this.unpack(1===this.buildConfig.objIdLen?"B":2===this.buildConfig.objIdLen?"H":"I",e);if(i===(1<<8*this.buildConfig.objIdLen)-1)continue;const a=!!(i&1<<8*this.buildConfig.objIdLen-1),r=i&~(1<<8*this.buildConfig.objIdLen-1);a&&!this.filesMap.has(r)&&this.filesMap.set(r,{name:null,size:0,dataPages:[]})}}for(let e=this.buildConfig.OBJ_LU_PAGES_PER_BLOCK;et[0]-e[0]);const i=[];let s=0;for(const[,t]of e.dataPages){const a=e.size-s;if(a<=0)break;const r=Math.min(t.length,a);i.push(t.slice(0,r)),s+=r}const a=new Uint8Array(s);let r=0;for(const t of i)a.set(t,r),r+=t.length;t.push({name:e.name,size:e.size,data:a})}return t}readFile(t){const e=this.listFiles().find(e=>e.name===t||e.name==="/"+t);return e?e.data:null}}const _s={pageSize:256,blockSize:4096,objNameLen:32,metaLen:4,useMagic:!0,useMagicLen:!0,alignedObjIxTables:!1},ps=async t=>{let e;const i=globalThis.requestSerialPort;if("function"==typeof i)e=await i();else{if(!navigator.serial)throw new Error("Web Serial API is not supported in this browser. Please use Chrome, Edge, or Opera on desktop, or Chrome on Android. Note: The page must be served over HTTPS or localhost.");e=await navigator.serial.requestPort()}return e.readable&&e.writable||await e.open({baudRate:h}),new Oi(e,t)},bs=async(t,e)=>{if(!t)throw new Error("Port is required");return t.readable&&t.writable||await t.open({baudRate:h}),new Oi(t,e)};export{ct as CHIP_ERASE_TIMEOUT,v as CHIP_FAMILY_ESP32,k as CHIP_FAMILY_ESP32C2,x as CHIP_FAMILY_ESP32C3,U as CHIP_FAMILY_ESP32C5,M as CHIP_FAMILY_ESP32C6,D as CHIP_FAMILY_ESP32C61,O as CHIP_FAMILY_ESP32H2,F as CHIP_FAMILY_ESP32H21,A as CHIP_FAMILY_ESP32H4,T as CHIP_FAMILY_ESP32P4,C as CHIP_FAMILY_ESP32S2,E as CHIP_FAMILY_ESP32S3,L as CHIP_FAMILY_ESP32S31,R as CHIP_FAMILY_ESP8266,_s as DEFAULT_SPIFFS_CONFIG,dt as DEFAULT_TIMEOUT,ft as ERASE_REGION_TIMEOUT_PER_MB,Pi as ESP8266_LITTLEFS_BLOCK_SIZE,Ni as ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES,$i as ESP8266_LITTLEFS_PAGE_SIZE,ji as ESP8266_SPIFFS_BLOCK_SIZE,Wi as ESP8266_SPIFFS_PAGE_SIZE,Oi as ESPLoader,tt as ESP_CHANGE_BAUDRATE,st as ESP_CHECKSUM_MAGIC,Z as ESP_ERASE_FLASH,X as ESP_ERASE_REGION,N as ESP_FLASH_BEGIN,$ as ESP_FLASH_DATA,at as ESP_FLASH_DEFL_BEGIN,rt as ESP_FLASH_DEFL_DATA,nt as ESP_FLASH_DEFL_END,W as ESP_FLASH_END,it as ESP_GET_SECURITY_INFO,j as ESP_MEM_BEGIN,H as ESP_MEM_DATA,G as ESP_MEM_END,lt as ESP_RAM_BLOCK,K as ESP_READ_FLASH,V as ESP_READ_REG,Y as ESP_SPI_ATTACH,et as ESP_SPI_FLASH_MD5,q as ESP_SPI_SET_PARAMS,J as ESP_SYNC,Q as ESP_WRITE_REG,zi as FATFS_BLOCK_SIZE_CANDIDATES,Li as FATFS_DEFAULT_BLOCK_SIZE,pt as FLASH_READ_TIMEOUT,Vi as FilesystemType,Ti as LITTLEFS_BLOCK_SIZE_CANDIDATES,Fi as LITTLEFS_DEFAULT_BLOCK_SIZE,ut as MAX_TIMEOUT,_t as MEM_END_ROM_TIMEOUT,ot as ROM_INVALID_RECV_MSG,gt as SYNC_TIMEOUT,rs as SpiffsBuildConfig,gs as SpiffsFS,fs as SpiffsReader,ht as USB_RAM_BLOCK,ps as connect,bs as connectWithPort,Xi as detectFilesystemFromImage,Zi as detectFilesystemType,a as formatMacAddr,as as formatSize,qi as getBlockSizeCandidates,Ki as getDefaultBlockSize,Qi as getESP8266FilesystemLayout,i as hexFormatter,ss as parsePartitionTable,Hi as scanESP8266Filesystem,r as sleep,s as toHex}; diff --git a/screenshots/desktop.png b/screenshots/desktop.png index 5dd18a66f8ca13dab105a242a4745a1737c0b79c..c2b3489f2c93f7ab72f05ff073fa2f2a440d4892 100644 GIT binary patch delta 19 acmeyI_Bm}r8V5TcpWxe%I^G-eSd9Ty69 Date: Tue, 7 Apr 2026 16:18:58 +0200 Subject: [PATCH 4/5] changes --- js/modules/esp32-BL5RXAvE.js | 16 + js/modules/esp32-BRKoi17y.js | 1 - js/modules/esp32c2-Btgr_lwh.js | 1 - js/modules/esp32c2-JZd7VMTK.js | 16 + js/modules/esp32c3--2RgnV8f.js | 16 + js/modules/esp32c3-CHKfoI8W.js | 1 - js/modules/esp32c5-BDW4KtLo.js | 1 - js/modules/esp32c5-D7Zxncy7.js | 16 + js/modules/esp32c6-B8dieLFx.js | 16 + js/modules/esp32c6-il8tTxAG.js | 1 - js/modules/esp32c61-CVOVhUkw.js | 16 + js/modules/esp32c61-thKzxBGf.js | 1 - js/modules/esp32h2-C7Y4kn-J.js | 16 + js/modules/esp32h2-CxoUHv_P.js | 1 - js/modules/esp32p4-BN3KBRYS.js | 16 + js/modules/esp32p4-D3jLP-jY.js | 1 - js/modules/esp32p4r3-CW9u2O6_.js | 16 + js/modules/esp32p4r3-CqI71ojR.js | 1 - js/modules/esp32s2-iX3WoDbg.js | 1 - js/modules/esp32s2-t0j-Iiag.js | 16 + js/modules/esp32s3-B8l06aKE.js | 16 + js/modules/esp32s3-DGwDVIgz.js | 1 - js/modules/esp8266-CUwxJpGa.js | 1 - js/modules/esp8266-nEkNAo8K.js | 16 + js/modules/esptool.js | 10298 ++++++++++++++++++++++++++++- 25 files changed, 10489 insertions(+), 13 deletions(-) create mode 100644 js/modules/esp32-BL5RXAvE.js delete mode 100644 js/modules/esp32-BRKoi17y.js delete mode 100644 js/modules/esp32c2-Btgr_lwh.js create mode 100644 js/modules/esp32c2-JZd7VMTK.js create mode 100644 js/modules/esp32c3--2RgnV8f.js delete mode 100644 js/modules/esp32c3-CHKfoI8W.js delete mode 100644 js/modules/esp32c5-BDW4KtLo.js create mode 100644 js/modules/esp32c5-D7Zxncy7.js create mode 100644 js/modules/esp32c6-B8dieLFx.js delete mode 100644 js/modules/esp32c6-il8tTxAG.js create mode 100644 js/modules/esp32c61-CVOVhUkw.js delete mode 100644 js/modules/esp32c61-thKzxBGf.js create mode 100644 js/modules/esp32h2-C7Y4kn-J.js delete mode 100644 js/modules/esp32h2-CxoUHv_P.js create mode 100644 js/modules/esp32p4-BN3KBRYS.js delete mode 100644 js/modules/esp32p4-D3jLP-jY.js create mode 100644 js/modules/esp32p4r3-CW9u2O6_.js delete mode 100644 js/modules/esp32p4r3-CqI71ojR.js delete mode 100644 js/modules/esp32s2-iX3WoDbg.js create mode 100644 js/modules/esp32s2-t0j-Iiag.js create mode 100644 js/modules/esp32s3-B8l06aKE.js delete mode 100644 js/modules/esp32s3-DGwDVIgz.js delete mode 100644 js/modules/esp8266-CUwxJpGa.js create mode 100644 js/modules/esp8266-nEkNAo8K.js diff --git a/js/modules/esp32-BL5RXAvE.js b/js/modules/esp32-BL5RXAvE.js new file mode 100644 index 00000000..6103adea --- /dev/null +++ b/js/modules/esp32-BL5RXAvE.js @@ -0,0 +1,16 @@ +var entry = 1074521712; +var text = "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"; +var text_start = 1074520064; +var data = "DMD8P3HoC0AH6QtAke0LQKfpC0Aq6QtAp+kLQADqC0AH6wtAfesLQCLrC0Ad6AtAs+oLQPzqC0Ae6gtAnusLQEjqC0Ce6wtA/ugLQGDpC0Cn6QtAAOoLQBDpC0Bs7AtAVu0LQIjtC0By7QtAiO0LQIjtC0CI7QtAiO0LQIjtC0CI7QtAiO0LQIjtC0D/6wtAiO0LQIfsC0BW7QtA"; +var data_start = 1073605548; +var bss_start = 1073528832; +var esp32 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32 as default, entry, text, text_start }; diff --git a/js/modules/esp32-BRKoi17y.js b/js/modules/esp32-BRKoi17y.js deleted file mode 100644 index a26ae236..00000000 --- a/js/modules/esp32-BRKoi17y.js +++ /dev/null @@ -1 +0,0 @@ -var A=1074521712,g="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",C=1074520064,I="DMD8P3HoC0AH6QtAke0LQKfpC0Aq6QtAp+kLQADqC0AH6wtAfesLQCLrC0Ad6AtAs+oLQPzqC0Ae6gtAnusLQEjqC0Ce6wtA/ugLQGDpC0Cn6QtAAOoLQBDpC0Bs7AtAVu0LQIjtC0By7QtAiO0LQIjtC0CI7QtAiO0LQIjtC0CI7QtAiO0LQIjtC0D/6wtAiO0LQIfsC0BW7QtA",B=1073605548,Q=1073528832,D={entry:A,text:g,text_start:C,data:I,data_start:B,bss_start:Q};export{Q as bss_start,I as data,B as data_start,D as default,A as entry,g as text,C as text_start}; diff --git a/js/modules/esp32c2-Btgr_lwh.js b/js/modules/esp32c2-Btgr_lwh.js deleted file mode 100644 index 3ab9a450..00000000 --- a/js/modules/esp32c2-Btgr_lwh.js +++ /dev/null @@ -1 +0,0 @@ -var A=1077413350,B="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",E=1077411840,w="DEDKP+IIOEBICThA3Ak4QLAKOEAYCzhAxgo4QNAHOEBsCjhArAo4QPgJOECABzhAIAo4QIAHOEDACDhACAk4QEgJOEDcCThA0gg4QP4HOEAyCDhAzgg4QAoNOEBICThA1As4QM4MOEBcBzhA8Aw4QFwHOEBcBzhAXAc4QFwHOEBcBzhAXAc4QFwHOEBcBzhAegs4QFwHOEDsCzhAzgw4QA==",Q=1070295980,g=1070219264,c={entry:A,text:B,text_start:E,data:w,data_start:Q,bss_start:g};export{g as bss_start,w as data,Q as data_start,c as default,A as entry,B as text,E as text_start}; diff --git a/js/modules/esp32c2-JZd7VMTK.js b/js/modules/esp32c2-JZd7VMTK.js new file mode 100644 index 00000000..f4f9b01b --- /dev/null +++ b/js/modules/esp32c2-JZd7VMTK.js @@ -0,0 +1,16 @@ +var entry = 1077413350; +var text = "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"; +var text_start = 1077411840; +var data = "DEDKP+IIOEBICThA3Ak4QLAKOEAYCzhAxgo4QNAHOEBsCjhArAo4QPgJOECABzhAIAo4QIAHOEDACDhACAk4QEgJOEDcCThA0gg4QP4HOEAyCDhAzgg4QAoNOEBICThA1As4QM4MOEBcBzhA8Aw4QFwHOEBcBzhAXAc4QFwHOEBcBzhAXAc4QFwHOEBcBzhAegs4QFwHOEDsCzhAzgw4QA=="; +var data_start = 1070295980; +var bss_start = 1070219264; +var esp32c2 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32c2 as default, entry, text, text_start }; diff --git a/js/modules/esp32c3--2RgnV8f.js b/js/modules/esp32c3--2RgnV8f.js new file mode 100644 index 00000000..96f525e3 --- /dev/null +++ b/js/modules/esp32c3--2RgnV8f.js @@ -0,0 +1,16 @@ +var entry = 1077413654; +var text = "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"; +var text_start = 1077411840; +var data = "FEDIP9oKOEBECzhA1gs4QKoMOEASDThAwAw4QLQJOEBmDDhApgw4QPILOEBkCThAGgw4QGQJOEC4CjhAAgs4QEQLOEDWCzhAygo4QNwJOEAoCjhAxgo4QAwPOEBECzhAzg04QMgOOEAiCThA7g44QCIJOEAiCThAIgk4QCIJOEAiCThAIgk4QCIJOEAiCThAdA04QCIJOEDmDThAyA44QA=="; +var data_start = 1070164916; +var bss_start = 1070088192; +var esp32c3 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32c3 as default, entry, text, text_start }; diff --git a/js/modules/esp32c3-CHKfoI8W.js b/js/modules/esp32c3-CHKfoI8W.js deleted file mode 100644 index f3be7436..00000000 --- a/js/modules/esp32c3-CHKfoI8W.js +++ /dev/null @@ -1 +0,0 @@ -var A=1077413654,E="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",B=1077411840,w="FEDIP9oKOEBECzhA1gs4QKoMOEASDThAwAw4QLQJOEBmDDhApgw4QPILOEBkCThAGgw4QGQJOEC4CjhAAgs4QEQLOEDWCzhAygo4QNwJOEAoCjhAxgo4QAwPOEBECzhAzg04QMgOOEAiCThA7g44QCIJOEAiCThAIgk4QCIJOEAiCThAIgk4QCIJOEAiCThAdA04QCIJOEDmDThAyA44QA==",g=1070164916,D=1070088192,M={entry:A,text:E,text_start:B,data:w,data_start:g,bss_start:D};export{D as bss_start,w as data,g as data_start,M as default,A as entry,E as text,B as text_start}; diff --git a/js/modules/esp32c5-BDW4KtLo.js b/js/modules/esp32c5-BDW4KtLo.js deleted file mode 100644 index 5c99c03f..00000000 --- a/js/modules/esp32c5-BDW4KtLo.js +++ /dev/null @@ -1 +0,0 @@ -var A=1082133196,B="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",E=1082130432,w="FACEQDAPgECaD4BALhCAQAIRgEBqEYBAGBGAQIoNgEC+EIBA/hCAQEoQgEA6DYBAchCAQDoNgEAMD4BAWA+AQJoPgEAuEIBAHg+AQLINgEDgDYBAGg+AQGQTgECaD4BAJhKAQCATgED0DIBARhOAQPQMgED0DIBA9AyAQPQMgED0DIBA9AyAQPQMgED0DIBAzBGAQPQMgEA+EoBAIBOAQA==",g=1082469300,C=1082392576,Q={entry:A,text:B,text_start:E,data:w,data_start:g,bss_start:C};export{C as bss_start,w as data,g as data_start,Q as default,A as entry,B as text,E as text_start}; diff --git a/js/modules/esp32c5-D7Zxncy7.js b/js/modules/esp32c5-D7Zxncy7.js new file mode 100644 index 00000000..7b84591a --- /dev/null +++ b/js/modules/esp32c5-D7Zxncy7.js @@ -0,0 +1,16 @@ +var entry = 1082133196; +var text = "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"; +var text_start = 1082130432; +var data = "FACEQDAPgECaD4BALhCAQAIRgEBqEYBAGBGAQIoNgEC+EIBA/hCAQEoQgEA6DYBAchCAQDoNgEAMD4BAWA+AQJoPgEAuEIBAHg+AQLINgEDgDYBAGg+AQGQTgECaD4BAJhKAQCATgED0DIBARhOAQPQMgED0DIBA9AyAQPQMgED0DIBA9AyAQPQMgED0DIBAzBGAQPQMgEA+EoBAIBOAQA=="; +var data_start = 1082469300; +var bss_start = 1082392576; +var esp32c5 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32c5 as default, entry, text, text_start }; diff --git a/js/modules/esp32c6-B8dieLFx.js b/js/modules/esp32c6-B8dieLFx.js new file mode 100644 index 00000000..9242f279 --- /dev/null +++ b/js/modules/esp32c6-B8dieLFx.js @@ -0,0 +1,16 @@ +var entry = 1082132230; +var text = "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"; +var text_start = 1082130432; +var data = "EACEQIYKgEDwCoBAfguAQFIMgEC6DIBAaAyAQHgJgEAODIBATgyAQJoLgEAoCYBAwguAQCgJgEBkCoBArgqAQPAKgEB+C4BAdgqAQKAJgEDUCYBAcgqAQLQOgEDwCoBAdg2AQHAOgEDmCIBAlg6AQOYIgEDmCIBA5giAQOYIgEDmCIBA5giAQOYIgEDmCIBAHA2AQOYIgECODYBAcA6AQA=="; +var data_start = 1082469296; +var bss_start = 1082392576; +var esp32c6 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32c6 as default, entry, text, text_start }; diff --git a/js/modules/esp32c6-il8tTxAG.js b/js/modules/esp32c6-il8tTxAG.js deleted file mode 100644 index 18699a7b..00000000 --- a/js/modules/esp32c6-il8tTxAG.js +++ /dev/null @@ -1 +0,0 @@ -var A=1082132230,B="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",E=1082130432,w="EACEQIYKgEDwCoBAfguAQFIMgEC6DIBAaAyAQHgJgEAODIBATgyAQJoLgEAoCYBAwguAQCgJgEBkCoBArgqAQPAKgEB+C4BAdgqAQKAJgEDUCYBAcgqAQLQOgEDwCoBAdg2AQHAOgEDmCIBAlg6AQOYIgEDmCIBA5giAQOYIgEDmCIBA5giAQOYIgEDmCIBAHA2AQOYIgECODYBAcA6AQA==",g=1082469296,Q=1082392576,c={entry:A,text:B,text_start:E,data:w,data_start:g,bss_start:Q};export{Q as bss_start,w as data,g as data_start,c as default,A as entry,B as text,E as text_start}; diff --git a/js/modules/esp32c61-CVOVhUkw.js b/js/modules/esp32c61-CVOVhUkw.js new file mode 100644 index 00000000..c82a8ee9 --- /dev/null +++ b/js/modules/esp32c61-CVOVhUkw.js @@ -0,0 +1,16 @@ +var entry = 1082132230; +var text = "QRG39wBgIsQmwkrAEUcGxrdEgEDYyz6JM4TnAJOEBAAcQJGLmeeyQCJEkkQCSUEBgoADJQkAnEATdfUPgpfNtwERtwcAYE7Gg6mHAErIN0mAQCbKUsQGziLMk4THAT6KEwkJAIBAE3T0DxnIAyUKAIMnCQB9FBN19Q+Cl2X43bfyQGJEtwcAYCOoNwHSREJJskkiSgVhgoCTBwAMkEEqh2MY9QCFRwXGI6AFAHlVgoCFRmMH1gAJRWMNpgB9VYKAQgWTB7ANQYVjE/cCiUecwfW3EwbADWMVxwCUwT6FgoCTB9AN4xz3/JTBEwWwDYKAt3WBQEERk4WFugbGcT9jTQUEt3eBQJOHB7IDpwcIg9ZHCBOGFgAjkscINpcjAKcAA9dHCJFnk4cHBGMa9wI394BAEwcHsqFnupcDpgcItzaBQJOGBrZjH+YAI6bHCCOg1wgjkgcIIaD5V+MK9fyyQEEBgoAjptcII6DnCN23NzcAYBMHRwUcQ52L9f83JwBgEwdHBRxDnYv1/4KAQREGxvk/NzcAYLcGAAgjJgcCkwfHAhTDFEP9/ohDskATRfX/BYlBAYKAQREGxsk/fd23NwBgNwcAQJjDmEN9/7JAQQGCgEERJsK3xIBAk4QEAUrAA6kEAQbGIsRjCQkERTcxxb1HAURj1icBgER9jBM0FABdP7U3mES3BwABPoaTFscAGcA3BoAA/Rf1j7c2AGDcwpDCnEL9/5MH9P/Fm8EHMwn5QD6XI6gkAZjEskAiRJJEAklBAYKAAREGzhU3NwXOP2wAURWXAID/54AA9KqHBUWd57JHk/cHID7GsTe3NwBgmEe3BkAANwXOP1WPmMeyRVEVlwCA/+eAYPEzNaAA8kAFYYKAQRG3x4BABsaThwcBBUcjgOcAE9fFAJjHBWd9F8zDyMf5jTqVqpWxgQ1njMsjqgcAMzbAALqXI4bHsKU/GcETBVAMskBBAYKAeXEi1DfEgEAm0k7OLsYG1krQqokTBAQBlwCA/+eAgOOyRUREY/OVAK6EucgDKUQAJpkTWckAHEhjVfAAHERjX/kCvTV93UhAJobOhZcAgP/ngMDfAcWTB0AMXMhcQLJQAlmml1zAXETySYWPXMQiVJJURWEXA4D/ZwAD3q09Zb+yUCJUklQCWfJJRWGCgAERIsw3xIBAEwQEAY1nopeDx8ewBs4mykrITsaBy2JE8kDSREJJskkFYaG3RERj85UAroSxwAMpRACqiSaZE1nJABxIY1XwABxEY175AtE7fd1IQCaGzoWXAID/54Cg2RN19Q8BxZMHQAxcyFxAppdcwFxEhY9cxPJAYkTSREJJskkFYYKAzTNtv0ERBsaXAID/54AAzANFhQGyQHEVEzUVAEEBgoBBEQbGxTcNxbdHgECThwcA1EOZzjdnCWATB4cOHEM3Bv3/fRbxjzcGAwDxjtWPHMOyQEEBgoBBESbCBsYixErAqoRNNyHhIkSyQAJJJoWSREEBFwOA/2cAY78pRZcAgP/ngAC9WRSDJwkAhYOFi5HjbfSyQCJEt/cAYITDAkmSREEBgoBhZDf5AGATBARqEQnZv0ERBsYTBwAMYxrlABMFsA1RPxMFwA2yQEEBabcTB7AN4xvl/kE3EwXQDfW3QREixCbCBsYqhLMEtQBjF5QAskAiRJJEQQGCgANFBAAFBE0/7bd1cSLFJsPS3AbHSsHO3hMBAYATAQGAqoQoCC6EBWqXAID/54CgJg3kKAAsCJcAgP/ngEAmKADBRU03AUWFYhaRukAqRJpECkn2WWZaSWGCgCKJY3OKAAVpSoaMGCaFlwCA/+eA4MATdfUPAe1KhowYKAiXAID/54CgIcqUMwQkQV23EwUwBl2/EwUADNm1QREGxiLEJsKtNRXlIkSyQJJEQQEXA4D/ZwDjrSlFlwCA/+eAwKlZFJxAhYOFi5HjdfQRReG/YWS39ABgEwQEapEE3bc1cSLNTsdSxVbD3t4GzybLSslawRMBAYATAQGAqokuirKKtosCwiE1gBi3BwIAGeGTBwACPoWXAID/54CAFYVnY+NXDygIlwCA/+eAABcBSQMrRPljY2kLY2FLA3mooT+mhSKFVTWBPyaGooUoCJcAgP/ngMAUppkmmWN1SQOzB2lBY/F3A7MEKkFj85oA1oQmhqKFToWXAID/54BAsBN19Q9V3SE/gUQjLAT4eVujCQT4EwUxAJcAgP/ngECedfkDRTT5LAAxNJMXBQFjwgcCk7dEAJHPhWeThwcHppeKl5OHB4CThweAI4qn+IUEwbfjH2X7kUfjjfT0KAAsCJcAgP/ngAAMRT3BRSgA9TtlNTk7kwcAAhnBtwcCAD6FlwCA/+eAQAeFYhaR+kBqRNpESkm6SSpKmkoKS/ZbDWGCgLdXQUkZcZOH94QBRYbeotym2srYztbS1NbS2tDezuLM5srqyO7GPs6XAID/54CgmX05DcE3ZwlgEweHDhxDt0aAQCOi9gC3Bv3//Rb1j8Fm1Y8cw2k5Bc23JwtgN0fYUJOHh8ETBxeqmMO3JgtgI6AGwCOgBwCThwbCmMMTh8bBFEM3BgQA0Y4UwyOgBwC3R4BAN3eBQJOHBwATBwe7IaAjoAcAkQfj7ef+8TORRWgIITvRM+Ezt/eAQJOHB7Khar6aI6D6CLdJgEC3B4BAk4kJAJOHBw8joPkAETljBgUQtwcBYBMHEAIjqOcKhUVFRZcAgP/ngCDztwWAQAFGk4UFAEVFlwCA/+eAYPS39wBgEUeYyzcFAgCXAID/54Cg87cXCWCIX4FFN8qAQHGJYRUTNRUAlwCA/+eAYJtBZpMH9v8TBwAQhWa3BQABAUW3e4FAEwoKAQ1rlwCA/+eAIJGTiwvBUpuDp8oI9d+DpMoIhUcjpgoIIwLxAoPHFAAJRyMT4QKjAvECAtRNR2OB5whRR2OP5wYpR2Oe5wCDxzQAA8ckAKIH2Y8RR2OV5wCcRJxDPtTJMaFFSBA5MYPGNACDxyQAogbdjpFnwQdj9dcEEwWwDbU2EwXADZ02EwXgDoU2UTlhOUG3twWAQAFGk4UFBBVFlwCA/+eAYOW3BwBg2EcTBQACE2cXENjHMbfJRyMT8QJFt4PHFABRR2Nn9wIFR2Nm9wABSRME8A8xpPkXk/f3D0lH42j3/jd3gUCKBxMHR7u6l5xDgocThwcDE3f3DxFG42nm/JOH9wKT9/cPDUdjb/cEN3eBQIoHEwcHwLqXnEOCh5MHQAJjl/YOAtQdRAFFdTwBRRE+9TbtNqFFSBB9FBU+dfQBSQFEcaqJ6nAQgUUBRZfwf//ngEBxAcUFRAFJUaLRRWgQOTYBRNW/BUTl+pfwf//ngKB2MzSgAM23oUfjnvb8A6mEAMBEs2eJANIH8ffv8L+FIplx8RnEMwWJQJMXBQHBg4HrQWxjYYwCFegzNIAAbbcxgZfwf//ngCB0Fe0TBASAEwQEgMG/MwWJQEGBl/B//+eAwHIF5TMEhEHptzMFiUAxgZfwf//ngCBxAe0TBASAEwQEgFW/EwRQA0W/EwRgA223EwRwA1W3oUfjivbyAUkTBAAM6aDBR82/wUcFROOd9vLMRIhEvTSpt5P3tv9BR+Of5/yYSJFnY+HnJNFHiETMSAFGY5P2AJBM7/Cv/iqEIbeT97b/QUfjm+f6nEgRZ2Nt9yDYRIhEzEgziecC0UcBRmOT9gCQTO/wz/u3x4BAk4cHAQ1nI6wHALqXKoQjpCex2bW3x4BAk4cHAQPHBwBjDAcWmETBFhMEAAxjE9cAwEuBRxMG8A5jztcEg8dUAAPHRAABSaIH2Y8Dx2QAQgddj4PHdADiB9mPYxT2GhN19A+FMhN1+Q+pOg084x8E2IPHFABJR2Nh9xoJR+N399j1F5P39w89R+Nh99iKB96XnEOChzOH9AADR4cBhQc5jmG/t8eAQJOHBwEDxwcAbcfYR2MbBxTASyOABwAxveFHY5D2AtxMmEzUSJBIzESIRJfwf//ngABcKokzNKAAQbcBSQVErb+RRwVE45f23reWAGC4XuV3/RcFZn2PUY+IRLjet5YAYLhWgUV9j1GPuNa3lgBg+F59j1GP+N63lgBg+FL5j9GP/NKX8H//54CAXk27k/f2AOOcB+QT3EYAE4SEAAFJ/VzjfInXSESX8H//54AAQRxEWEAQQH2PY4eXARRCk8f3//WPXY8YwgUJQQTZv5FHGb3BRwVE45/21JxE2EgjpvkAI6TpAKG7A6eJABOGBv8R5wHOAUkTBGAMwbWDp8kAY+bHBo2K45IG3oOmyQCBRYFHY+vHAOOCBdCdjj6XI6bZACOk6QDVubOF9ACITbMF9wCRB4jBhUXpv6FHBUTjm/bOA6TJABnAEwSADCOmCQAjpAkADbsBSRMEIAy5vRMEEAyhvQFJEwSADIG9AUkTBJAMobUTByANY4jnBhMHQA3jk+e+g8U0AIPHJAAThYQBogXdjcEV7/Av3PG2CWUTBQVxA6nEAIBEl/B//+eAADG3BwBg2Eu3BgABwRaTV0cBEgd1j72L2Y+zhycDAUWz1YcCl/B//+eAYDITBYA+l/B//+eAoC1BttRIkEjMRIhE7/A/hY2+g8U0AIPHJAAThYQBogXdjcEV7/Dv3am+g8c0AAPHJACiB9mPE40H/4MnygCB55M3XQCdy7d9gUA3yYBAt0yAQOEEBUSTjQ27EwkJAROMDAFjBw0AgyfKAJnDY0yAAGNVBAiTB3AMGaCTB5AMIyr6AAG2AyiLsAOnDQBq0DM4DQEGCLMH6UAFCDrGPtZCxO/wr7wyRyJIN8WAQKaFfBDihhAQEwWFApfwf//ngMAtglcDJ4uwg6UNADMN/UAdj76UslcjJOuwKoS+lSOgvQDhd7OFhUGul5HDJf0ThQwB7/Av0SOgjQGtt+MUBKiDJ8oA44AHqJMHgAyVv5xE45oHpu/wj/AJZRMFBXGX8H//54CAG+/wT9iX8H//54BAIIm8wETjBwSk7/Av7hMFgD6X8H//54BAGe/wD9YClBW87/CP1fZQZlTWVEZZtlkmWpZaBlv2S2ZM1kxGTbZNCWGCgAAA"; +var text_start = 1082130432; +var data = "EECAQIoKgED0CoBAgguAQFYMgEC+DIBAbAyAQHwJgEASDIBAUgyAQJ4LgEAsCYBAxguAQCwJgEBoCoBAsgqAQPQKgECCC4BAegqAQKQJgEDYCYBAdgqAQLgOgED0CoBAeg2AQHQOgEDqCIBAmg6AQOoIgEDqCIBA6giAQOoIgEDqCIBA6giAQOoIgEDqCIBAIA2AQOoIgECSDYBAdA6AQA=="; +var data_start = 1082223536; +var bss_start = 1082146816; +var esp32c61 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32c61 as default, entry, text, text_start }; diff --git a/js/modules/esp32c61-thKzxBGf.js b/js/modules/esp32c61-thKzxBGf.js deleted file mode 100644 index e36d7f32..00000000 --- a/js/modules/esp32c61-thKzxBGf.js +++ /dev/null @@ -1 +0,0 @@ -var A=1082132230,B="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",E=1082130432,w="EECAQIoKgED0CoBAgguAQFYMgEC+DIBAbAyAQHwJgEASDIBAUgyAQJ4LgEAsCYBAxguAQCwJgEBoCoBAsgqAQPQKgECCC4BAegqAQKQJgEDYCYBAdgqAQLgOgED0CoBAeg2AQHQOgEDqCIBAmg6AQOoIgEDqCIBA6giAQOoIgEDqCIBA6giAQOoIgEDqCIBAIA2AQOoIgECSDYBAdA6AQA==",Q=1082223536,g=1082146816,C={entry:A,text:B,text_start:E,data:w,data_start:Q,bss_start:g};export{g as bss_start,w as data,Q as data_start,C as default,A as entry,B as text,E as text_start}; diff --git a/js/modules/esp32h2-C7Y4kn-J.js b/js/modules/esp32h2-C7Y4kn-J.js new file mode 100644 index 00000000..c010ac28 --- /dev/null +++ b/js/modules/esp32h2-C7Y4kn-J.js @@ -0,0 +1,16 @@ +var entry = 1082132230; +var text = "QRG39wBgIsQmwkrAEUcGxrcEg0DYyz6JM4TnAJOEBAAcQJGLmeeyQCJEkkQCSUEBgoADJQkAnEATdfUPgpfNtwERtwcAYE7Gg6mHAErINwmDQCbKUsQGziLMk4THAT6KEwkJAIBAE3T0DxnIAyUKAIMnCQB9FBN19Q+Cl2X43bfyQGJEtwcAYCOoNwHSREJJskkiSgVhgoCTBwAMkEEqh2MY9QCFRwXGI6AFAHlVgoCFRmMH1gAJRWMNpgB9VYKAQgWTB7ANQYVjE/cCiUecwfW3EwbADWMVxwCUwT6FgoCTB9AN4xz3/JTBEwWwDYKAtzWEQEERk4WFugbGcT9jTQUEtzeEQJOHB7IDpwcIg9ZHCBOGFgAjkscINpcjAKcAA9dHCJFnk4cHBGMa9wI3t4NAEwcHsqFnupcDpgcIt/aDQJOGBrZjH+YAI6bHCCOg1wgjkgcIIaD5V+MK9fyyQEEBgoAjptcII6DnCN23NzcAYBMHRwUcQ52L9f83JwBgEwdHBRxDnYv1/4KAQREGxvk/NzcAYLcGAAgjJgcCkwfHAhTDFEP9/ohDskATRfX/BYlBAYKAQREGxsk/fd23NwBgNwcAQJjDmEN9/7JAQQGCgEERJsK3hINAk4QEAUrAA6kEAQbGIsRjCQkERTcxxb1HAURj1icBgER9jBM0FABdP7U3mES3BwABPoaTFscAGcA3BoAA/Rf1j7c2AGDcwpDCnEL9/5MH9P/Fm8EHMwn5QD6XI6gkAZjEskAiRJJEAklBAYKAAREGzhU3NwWFQGwAQRWXAID/54CA8qqHBUWd57JHk/cHID7GsTe3NwBgmEe3BkAANwWFQFWPmMeyRUEVlwCA/+eA4O8zNaAA8kAFYYKAQRG3h4NABsaThwcBBUcjgOcAE9fFAJjHBWd9F8zDyMf5jTqVqpWxgQ1njMsjqgcAMzbAALqXI4bHsKU/GcETBVAMskBBAYKAeXEi1DeEg0Am0k7OLsYG1krQqokTBAQBlwCA/+eAAOKyRUREY/OVAK6EucgDKUQAJpkTWckAHEhjVfAAHERjX/kCvTV93UhAJobOhZcAgP/ngEDeAcWTB0AMXMhcQLJQAlmml1zAXETySYWPXMQiVJJURWEXA4D/ZwCD3K09Zb+yUCJUklQCWfJJRWGCgAERIsw3hINAEwQEAY1nopeDx8ewBs4mykrITsaBy2JE8kDSREJJskkFYaG3RERj85UAroSxwAMpRACqiSaZE1nJABxIY1XwABxEY175AtE7fd1IQCaGzoWXAID/54Ag2BN19Q8BxZMHQAxcyFxAppdcwFxEhY9cxPJAYkTSREJJskkFYYKAzTNtv0ERBsaXAID/54DAywNFhQGyQHUVEzUVAEEBgoBBEQbGxTcNxbcHg0CThwcA1EOZzjdnCWATB8cQHEM3Bv3/fRbxjzcGAwDxjtWPHMOyQEEBgoBBESbCBsYixErAqoRNNyHhIkSyQAJJJoWSREEBFwOA/2cAo78pRZcAgP/ngEC9WRSDJwkAhYOFi5HjbfSyQCJEt/cAYITDAkmSREEBgoBhZDf5AGATBARqEQnZv0ERBsYTBwAMYxrlABMFsA1RPxMFwA2yQEEBabcTB7AN4xvl/kE3EwXQDfW3QREixCbCBsYqhLMEtQBjF5QAskAiRJJEQQGCgANFBAAFBE0/7bd1cSLFJsPS3AbHSsHO3hMBAYATAQGAqoQoCC6EBWqXAID/54BgIA3kKAAsCJcAgP/ngAAgKADBRU03AUWFYhaRukAqRJpECkn2WWZaSWGCgCKJY3OKAAVpSoaMGCaFlwCA/+eAYL8TdfUPAe1KhowYKAiXAID/54BgG8qUMwQkQV23EwUwBl2/EwUADNm1QREGxiLEJsKtNRXlIkSyQJJEQQEXA4D/ZwDjrSlFlwCA/+eAAKpZFJxAhYOFi5HjdfQNReG/YWS39ABgEwQEapEE3bc1cSLNTsdSxVbD3t4GzybLSslawRMBAYATAQGAqokuirKKtosCwiE1gBi3BwIAGeGTBwACPoWXAID/54AAEYVnY+NXDygIlwCA/+eAwBABSQMrRPljY2kLY2FLA3mooT+mhSKFVTWBPyaGooUoCJcAgP/ngIAOppkmmWN1SQOzB2lBY/F3A7MEKkFj85oA1oQmhqKFToWXAID/54DArhN19Q9V3SE/gUQjLAT4eVujCQT4EwUxAJcAgP/ngECedfkDRTT5LAAxNJMXBQFjwgcCk7dEAJHPhWeThwcHppeKl5OHB4CThweAI4qn+IUEwbfjH2X7kUfjjfT0KAAsCJcAgP/ngMAFRT3BRSgA9TtlNTk7kwcAAhnBtwcCAD6FlwCA/+eAwAKFYhaR+kBqRNpESkm6SSpKmkoKS/ZbDWGCgLdXQUkZcZOH94QBRYbeotym2srYztbS1NbS2tDezuLM5srqyO7GPs6XAID/54BgmX05DcE3ZwlgEwfHEBxDtwaDQCOi9gC3Bv3//Rb1j8Fm1Y8cw2k5Bc23JwtgN0fYUJOHx8ETBxeqmMO3JgtgI6AGwCOgBwCTh0bCmMMThwbCFEM3BgQA0Y4UwyOgBwC3B4NANzeEQJOHBwATBwe7IaAjoAcAkQfj7ef+8TORRWgIITvRM+Ezt7eDQJOHB7Khar6aI6D6CLcJg0C3B4BAk4kJAJOHBw8joPkAETljBAUQtwcBYEVFI6qnCIVFlwCA/+eAIO+3BYBAAUaThQUARUWXAID/54Ag8Lf3AGARR5jLNwUCAJcAgP/ngGDvtxcJYIhfgUU3ioNAcYlhFRM1FQCXAID/54DgmUFmkwf2/xMHABCFZrcFAAEBRbc7hEATCgoBDWuXAID/54Dgj5OLC8FSm4Onygj134OkygiFRyOmCggjAvECg8cUAAlHIxPhAqMC8QIC1E1HY4HnCFFHY4/nBilHY57nAIPHNAADxyQAogfZjxFHY5XnAJxEnEM+1NkxoUVIEAk5g8Y0AIPHJACiBt2OkWfBB2P11wQTBbANhT4TBcANrTYTBeAOlTZhOXE5Qbe3BYBAAUaThQUEFUWXAID/54Ag4bcHAGDYRxMFAAITZxcQ2Mcxt8lHIxPxAkW3g8cUAFFHY2f3AgVHY2b3AAFJEwTwDzGk+ReT9/cPSUfjaPf+NzeEQIoHEwdHu7qXnEOChxOHBwMTd/cPEUbjaeb8k4f3ApP39w8NR2Nv9wQ3N4RAigcTBwfAupecQ4KHkwdAAmOX9g4C1B1EAUXBNAFFIT7FPv02oUVIEH0UJT519AFJAURxqonqcBCBRQFFl/B//+eAQHEBxQVEAUlRotFFaBAJPgFE1b8FROX6l/B//+eAYHUzNKAAzbehR+Oe9vwDqYQAwESzZ4kA0gfx9+/w/4UimXHxGcQzBYlAkxcFAcGDgetBbGNhjAIV6DM0gABttzGBl/B//+eA4HIV7RMEBIATBASAwb8zBYlAQYGX8H//54CAcQXlMwSEQem3MwWJQDGBl/B//+eA4G8B7RMEBIATBASAVb8TBFADRb8TBGADbbcTBHADVbehR+OK9vIBSRMEAAzpoMFHzb/BRwVE45328sxEiESNPKm3k/e2/0FH45/n/JhIkWdj4eck0UeIRMxIAUZjk/YAkEzv8O/+KoQht5P3tv9BR+Ob5/qcSBFnY233INhEiETMSDOJ5wLRRwFGY5P2AJBM7/AP/LeHg0CThwcBDWcjrAcAupcqhCOkJ7HZtbeHg0CThwcBA8cHAGMMBxaYRMEWEwQADGMT1wDAS4FHEwbwDmPO1wSDx1QAA8dEAAFJogfZjwPHZABCB12Pg8d0AOIH2Y9jFPYaE3X0D5UyE3X5D7k6HTzjHwTYg8cUAElHY2H3GglH43f32PUXk/f3Dz1H42H32IoH3pecQ4KHM4f0AANHhwGFBzmOYb+3h4NAk4cHAQPHBwBtx9hHYxsHFMBLI4AHADG94UdjkPYC3EyYTNRIkEjMRIhEl/B//+eAwFoqiTM0oABBtwFJBUStv5FHBUTjl/bet5YAYLhK5Xf9FwVmfY9Rj4hEuMq3lgBg+EKBRX2PUY/4wreWAGD4Sn2PUY/4yreWAGC4QvmP0Y+8wpfwf//ngABdTbuT9/YA45wH5BPcRgAThIQAAUn9XON8iddIRJfwf//ngIBBHERYQBBAfY9jh5cBFEKTx/f/9Y9djxjCBQlBBNm/kUcZvcFHBUTjn/bUnETYSCOm+QAjpOkAobsDp4kAE4YG/xHnAc4BSRMEYAzBtYOnyQBj5scGjYrjkgbeg6bJAIFFgUdj68cA44IF0J2OPpcjptkAI6TpANW5s4X0AIhNswX3AJEHiMGFRem/oUcFROOb9s4DpMkAGcATBIAMI6YJACOkCQANuwFJEwQgDLm9EwQQDKG9AUkTBIAMgb0BSRMEkAyhtRMHIA1jiOcGEwdADeOT576DxTQAg8ckABOFhAGiBd2NwRXv8G/c8bYJZRMFBXEDqcQAgESX8H//54CAMbcHAGDYS7cGAAHBFpNXRwESB3WPvYvZj7OHJwMBRbPVhwKX8H//54CgMhMFgD6X8H//54AgLkG21EiQSMxEiETv8H+Fjb6DxTQAg8ckABOFhAGiBd2NwRXv8C/eqb6DxzQAA8ckAKIH2Y8TjQf/gyfKAIHnkzddAJ3Ltz2EQDeJg0C3DINA4QQFRJONDbsTCQkBE4wMAWMHDQCDJ8oAmcNjTIAAY1UECJMHcAwZoJMHkAwjKvoAAbYDKIuwA6cNAGrQMzgNAQYIswfpQAUIOsY+1kLE7/DvvDJHIkg3hYNApoV8EOKGEBATBYUCl/B//+eAwC2CVwMni7CDpQ0AMw39QB2PvpSyVyMk67AqhL6VI6C9AOF3s4WFQa6XkcMl/ROFDAHv8G/RI6CNAa234xQEqIMnygDjgAeokweADJW/nETjmgem7/DP8AllEwUFcZfwf//ngAAc7/CP2Jfwf//ngEAgibzAROMHBKTv8G/uEwWAPpfwf//ngMAZ7/BP1gKUFbzv8M/V9lBmVNZURlm2WSZalloGW/ZLZkzWTEZNtk0JYYKAAAA="; +var text_start = 1082130432; +var data = "EACDQIYKgEDwCoBAfguAQFIMgEC6DIBAaAyAQHgJgEAODIBATgyAQJoLgEAoCYBAwguAQCgJgEBkCoBArgqAQPAKgEB+C4BAdgqAQKAJgEDUCYBAcgqAQLQOgEDwCoBAdg2AQHAOgEDmCIBAlg6AQOYIgEDmCIBA5giAQOYIgEDmCIBA5giAQOYIgEDmCIBAHA2AQOYIgECODYBAcA6AQA=="; +var data_start = 1082403760; +var bss_start = 1082327040; +var esp32h2 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32h2 as default, entry, text, text_start }; diff --git a/js/modules/esp32h2-CxoUHv_P.js b/js/modules/esp32h2-CxoUHv_P.js deleted file mode 100644 index b4b5ae92..00000000 --- a/js/modules/esp32h2-CxoUHv_P.js +++ /dev/null @@ -1 +0,0 @@ -var A=1082132230,B="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",E=1082130432,g="EACDQIYKgEDwCoBAfguAQFIMgEC6DIBAaAyAQHgJgEAODIBATgyAQJoLgEAoCYBAwguAQCgJgEBkCoBArgqAQPAKgEB+C4BAdgqAQKAJgEDUCYBAcgqAQLQOgEDwCoBAdg2AQHAOgEDmCIBAlg6AQOYIgEDmCIBA5giAQOYIgEDmCIBA5giAQOYIgEDmCIBAHA2AQOYIgECODYBAcA6AQA==",w=1082403760,Q=1082327040,c={entry:A,text:B,text_start:E,data:g,data_start:w,bss_start:Q};export{Q as bss_start,g as data,w as data_start,c as default,A as entry,B as text,E as text_start}; diff --git a/js/modules/esp32p4-BN3KBRYS.js b/js/modules/esp32p4-BN3KBRYS.js new file mode 100644 index 00000000..27083e15 --- /dev/null +++ b/js/modules/esp32p4-BN3KBRYS.js @@ -0,0 +1,16 @@ +var entry = 1341197280; +var text = "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"; +var text_start = 1341194240; +var data = "XAD1T/gQ8U9iEfFP/hHxT9oS8U9CE/FP8BLxT04P8U+WEvFP1hLxTxoS8U/+DvFPQhLxT/4O8U/UEPFPIBHxT2IR8U/+EfFP5hDxT3gP8U+uD/FP4hDxTzwV8U9iEfFPBhTxTwAV8U8gDvFPIhXxTyAO8U8gDvFPIA7xTyAO8U8gDvFPIA7xTyAO8U8gDvFPpBPxTyAO8U8eFPFPABXxTw=="; +var data_start = 1341533180; +var bss_start = 1341456384; +var esp32p4 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32p4 as default, entry, text, text_start }; diff --git a/js/modules/esp32p4-D3jLP-jY.js b/js/modules/esp32p4-D3jLP-jY.js deleted file mode 100644 index 75db7983..00000000 --- a/js/modules/esp32p4-D3jLP-jY.js +++ /dev/null @@ -1 +0,0 @@ -var A=1341197280,E="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",B=1341194240,w="XAD1T/gQ8U9iEfFP/hHxT9oS8U9CE/FP8BLxT04P8U+WEvFP1hLxTxoS8U/+DvFPQhLxT/4O8U/UEPFPIBHxT2IR8U/+EfFP5hDxT3gP8U+uD/FP4hDxTzwV8U9iEfFPBhTxTwAV8U8gDvFPIhXxTyAO8U8gDvFPIA7xTyAO8U8gDvFPIA7xTyAO8U8gDvFPpBPxTyAO8U8eFPFPABXxTw==",U=1341533180,Q=1341456384,F={entry:A,text:E,text_start:B,data:w,data_start:U,bss_start:Q};export{Q as bss_start,w as data,U as data_start,F as default,A as entry,E as text,B as text_start}; diff --git a/js/modules/esp32p4r3-CW9u2O6_.js b/js/modules/esp32p4r3-CW9u2O6_.js new file mode 100644 index 00000000..8752c10f --- /dev/null +++ b/js/modules/esp32p4r3-CW9u2O6_.js @@ -0,0 +1,16 @@ +var entry = 1341459424; +var text = "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"; +var text_start = 1341456384; +var data = "XAD2T/gQ9U9iEfVP/hH1T9oS9U9CE/VP8BL1T04P9U+WEvVP1hL1TxoS9U/+DvVPQhL1T/4O9U/UEPVPIBH1T2IR9U/+EfVP5hD1T3gP9U+uD/VP4hD1TzwV9U9iEfVPBhT1TwAV9U8gDvVPIhX1TyAO9U8gDvVPIA71TyAO9U8gDvVPIA71TyAO9U8gDvVPpBP1TyAO9U8eFPVPABX1Tw=="; +var data_start = 1341598716; +var bss_start = 1341521920; +var esp32p4r3 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32p4r3 as default, entry, text, text_start }; diff --git a/js/modules/esp32p4r3-CqI71ojR.js b/js/modules/esp32p4r3-CqI71ojR.js deleted file mode 100644 index 75823336..00000000 --- a/js/modules/esp32p4r3-CqI71ojR.js +++ /dev/null @@ -1 +0,0 @@ -var A=1341459424,E="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",B=1341456384,w="XAD2T/gQ9U9iEfVP/hH1T9oS9U9CE/VP8BL1T04P9U+WEvVP1hL1TxoS9U/+DvVPQhL1T/4O9U/UEPVPIBH1T2IR9U/+EfVP5hD1T3gP9U+uD/VP4hD1TzwV9U9iEfVPBhT1TwAV9U8gDvVPIhX1TyAO9U8gDvVPIA71TyAO9U8gDvVPIA71TyAO9U8gDvVPpBP1TyAO9U8eFPVPABX1Tw==",Q=1341598716,U=1341521920,T={entry:A,text:E,text_start:B,data:w,data_start:Q,bss_start:U};export{U as bss_start,w as data,Q as data_start,T as default,A as entry,E as text,B as text_start}; diff --git a/js/modules/esp32s2-iX3WoDbg.js b/js/modules/esp32s2-iX3WoDbg.js deleted file mode 100644 index 1e8b80ab..00000000 --- a/js/modules/esp32s2-iX3WoDbg.js +++ /dev/null @@ -1 +0,0 @@ -var A=1073907892,g="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",C=1073905664,I="WAD9P/KLAkCHjAJAK5ECQCeNAkCqjAJAJ40CQICNAkCDjgJA+Y4CQJ6OAkB9iwJAL44CQHiOAkCejQJAGo8CQMaNAkAajwJAfowCQOCMAkAnjQJAgI0CQJCMAkC+iwJA9I8CQOKQAkAikQJABpECQCKRAkAikQJAIpECQCKRAkAikQJAIpECQCKRAkAikQJAe48CQCKRAkAQkAJA4pACQA==",B=1073622016,E=1073545216,Q={entry:A,text:g,text_start:C,data:I,data_start:B,bss_start:E};export{E as bss_start,I as data,B as data_start,Q as default,A as entry,g as text,C as text_start}; diff --git a/js/modules/esp32s2-t0j-Iiag.js b/js/modules/esp32s2-t0j-Iiag.js new file mode 100644 index 00000000..438589b6 --- /dev/null +++ b/js/modules/esp32s2-t0j-Iiag.js @@ -0,0 +1,16 @@ +var entry = 1073907892; +var text = "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"; +var text_start = 1073905664; +var data = "WAD9P/KLAkCHjAJAK5ECQCeNAkCqjAJAJ40CQICNAkCDjgJA+Y4CQJ6OAkB9iwJAL44CQHiOAkCejQJAGo8CQMaNAkAajwJAfowCQOCMAkAnjQJAgI0CQJCMAkC+iwJA9I8CQOKQAkAikQJABpECQCKRAkAikQJAIpECQCKRAkAikQJAIpECQCKRAkAikQJAe48CQCKRAkAQkAJA4pACQA=="; +var data_start = 1073622016; +var bss_start = 1073545216; +var esp32s2 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32s2 as default, entry, text, text_start }; diff --git a/js/modules/esp32s3-B8l06aKE.js b/js/modules/esp32s3-B8l06aKE.js new file mode 100644 index 00000000..1f9a018d --- /dev/null +++ b/js/modules/esp32s3-B8l06aKE.js @@ -0,0 +1,16 @@ +var entry = 1077382356; +var text = "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"; +var text_start = 1077379072; +var data = "WADKP6qQN0B/kTdAGZY3QB+SN0CikTdAH5I3QHiSN0B/kzdA9ZM3QJqTN0A1kDdAJ5M3QHSTN0CWkjdAFpQ3QL6SN0AWlDdAdpE3QNiRN0AfkjdAeJI3QIiRN0B2kDdA8JQ3QN6VN0AQljdA+pU3QBCWN0AQljdAEJY3QBCWN0AQljdAEJY3QBCWN0AQljdAd5Q3QBCWN0AMlTdA3pU3QAQInwAAAAAAAAAYAQQIBQAAAAAAAAAIAQQIBgAAAAAAAAAAAQQIIQAAAAAAIAAAEQQI3AAAAAAAIAAAEQQIDAAAAAAAIAAAAQQIEgAAAAAAIAAAESAoDAAQAQAA"; +var data_start = 1070279676; +var bss_start = 1070202880; +var esp32s3 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp32s3 as default, entry, text, text_start }; diff --git a/js/modules/esp32s3-DGwDVIgz.js b/js/modules/esp32s3-DGwDVIgz.js deleted file mode 100644 index 5b5c5de4..00000000 --- a/js/modules/esp32s3-DGwDVIgz.js +++ /dev/null @@ -1 +0,0 @@ -var A=1077382356,g="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",C=1077379072,B="WADKP6qQN0B/kTdAGZY3QB+SN0CikTdAH5I3QHiSN0B/kzdA9ZM3QJqTN0A1kDdAJ5M3QHSTN0CWkjdAFpQ3QL6SN0AWlDdAdpE3QNiRN0AfkjdAeJI3QIiRN0B2kDdA8JQ3QN6VN0AQljdA+pU3QBCWN0AQljdAEJY3QBCWN0AQljdAEJY3QBCWN0AQljdAd5Q3QBCWN0AMlTdA3pU3QAQInwAAAAAAAAAYAQQIBQAAAAAAAAAIAQQIBgAAAAAAAAAAAQQIIQAAAAAAIAAAEQQI3AAAAAAAIAAAEQQIDAAAAAAAIAAAAQQIEgAAAAAAIAAAESAoDAAQAQAA",I=1070279676,Q=1070202880,E={entry:A,text:g,text_start:C,data:B,data_start:I,bss_start:Q};export{Q as bss_start,B as data,I as data_start,E as default,A as entry,g as text,C as text_start}; diff --git a/js/modules/esp8266-CUwxJpGa.js b/js/modules/esp8266-CUwxJpGa.js deleted file mode 100644 index 1ab0638c..00000000 --- a/js/modules/esp8266-CUwxJpGa.js +++ /dev/null @@ -1 +0,0 @@ -var A=1074843652,I="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",E=1074843648,g="CIH+PwUFBAACAwcAAwMLAOzXEEAj2BBAUdgQQO7YEECd5xBAUtkQQKjZEED02RBAnecQQLraEEA32xBA+NsQQJ3nEECd5xBAkNwQQJ3nEEBt3xBANOAQQG/gEECd5xBAnecQQAvhEECd5xBA8+EQQJniEEDY4xBAl+QQQGjlEECd5xBAnecQQJ3nEECd5xBAluYQQJ3nEECM5xBAyN0QQMHYEEDa5RBA4doQQDPaEECd5xBAIOcQQGfnEECd5xBAnecQQJ3nEECd5xBAnecQQJ3nEECd5xBAnecQQFraEECX2hBA8uUQQAEAAAACAAAAAwAAAAQAAAAFAAAABwAAAAkAAAANAAAAEQAAABkAAAAhAAAAMQAAAEEAAABhAAAAgQAAAMEAAAABAQAAgQEAAAECAAABAwAAAQQAAAEGAAABCAAAAQwAAAEQAAABGAAAASAAAAEwAAABQAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABgAAAAcAAAAHAAAACAAAAAgAAAAJAAAACQAAAAoAAAAKAAAACwAAAAsAAAAMAAAADAAAAA0AAAANAAAAAAAAAAAAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAANAAAADwAAABEAAAATAAAAFwAAABsAAAAfAAAAIwAAACsAAAAzAAAAOwAAAEMAAABTAAAAYwAAAHMAAACDAAAAowAAAMMAAADjAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAgAAAAMAAAADAAAAAwAAAAMAAAAEAAAABAAAAAQAAAAEAAAABQAAAAUAAAAFAAAABQAAAAAAAAAAAAAAAAAAABAREgAIBwkGCgULBAwDDQIOAQ8AAQEAAAEAAAAEAAAA",B=1073720492,C=1073643776,Q={entry:A,text:I,text_start:E,data:g,data_start:B,bss_start:C};export{C as bss_start,g as data,B as data_start,Q as default,A as entry,I as text,E as text_start}; diff --git a/js/modules/esp8266-nEkNAo8K.js b/js/modules/esp8266-nEkNAo8K.js new file mode 100644 index 00000000..a8283d0d --- /dev/null +++ b/js/modules/esp8266-nEkNAo8K.js @@ -0,0 +1,16 @@ +var entry = 1074843652; +var text = "qBAAQAH//0ZzAAAAkIH/PwgB/z+AgAAAhIAAAEBAAABIQf8/lIH/PzH5/xLB8CAgdAJhA0XyATKv/pZyA1H0/0H2/zH0/yAgdDA1gEpVwCAAaANCFQBAMPQbQ0BA9MAgAEJVADo2wCAAIkMAIhUAMev/ICD0N5I/Ieb/Meb/Qen/OjLAIABoA1Hm/yeWEoYAAAAAAMAgACkEwCAAWQNGAgDAIABZBMAgACkDMdv/OiIMA8AgADJSAAgxEsEQDfAAoA0AAJiB/z8Agf4/T0hBSays/z+orP8/KNAQQHTqEEAMAABg//8AAAAQAAAAAAEAAAAAAYyAAAAQQAAAAAD//wBAAAAAgf4/BIH+PxAnAAAUAABg//8PAKys/z8Igf4/vKz/PwCAAAA4KQAAkI//PwiD/z8Qg/8/sKz/P6Cv/z8wnf8/jK//P5gbAAAACAAAYAkAAFAOAABQEgAAPCkAALSs/z+4rP8/1Kr/PzspAADwgf8/EK//P5Su/z+ACwAAFK7/P5St/z8BAAAAAAAAALAVAADx/wAAmKz/P7wPAECIDwBAqA8AQFg/AEBERgBALEwAQHhIAEAASgBAtEkAQMwuAEDYOQBASN8AQJDhAEBMJgBAhEkAQCG9/5KhEJARwCJhIyKgAAJhQ8JhQtJhQeJhQPJhPwHp/8AAACGz/zG0/wwEBgEAAEkCSyI3MviFuAEioIwMQyohxaoBhbcBIX3/wXv/Maz/KizAIADJAiGp/wwEOQIxqf8MUgHZ/8AAADGn/yKhAcAgAEgDICQgwCAAKQMioCAB0//AAAAB0v/AAAAB0v/AAABxnv9Rn/9Bn/8xn/9ioQAMAgHN/8AAACGd/zFj/yojwCAAOAIWc//AIADYAgwDwCAAOQIMEiJBhCINAQwkIkGFQlFDMmEiJpIJHDM3EiCGCAAAACINAzINAoAiETAiIGZCESgtwCAAKAIiYSIGAQAcIiJRQ4WrASKghBoiDIMFngEiDQNSDQKAIhFQUiAhgP9XshMioMDFmAEioO5FmAHFqAFG3P8AACINAQyzN5ICBp8AJzNDZmICxtEA9nIgZjIChncA9kIIZiIChlYARtAAZkICBo0AZlICxrEAhswAJoJ59oIChrEADJM3kgKGlQBmkgIGqQAGxgAcIzeSAkaCACczJwzzN5IChj4AJzMLDNM3kgKGiQDGvQAAZrICRk4AHBM3kgJGXgBGuQAyoNE3EmgnMxEcMzeSAkY4ADKg0DcST8ayAAAyoNI3kgKGLwAyoNM3kgJGogVGrQAsQgwOJ5UCBncFRisAIqAARYsBIqAABYsBhZsBRZsBIqCEMqAIGiILzIWNAVbc/QwOzQ5GoQAAzBWGbAVGmwAmhQLGmQAGbQUBaf/AAAD6zJwixpUAAAAgLEEBZv/AAABWkiTy3/DwLMDML8Z6BQAgMPRWE/7hLP+GAwAgIPUBXv/AAABWUiLg/8DwLMD3PuqGAwAgLEEBV//AAABW0iDy3/DwLMBWr/6GawUmhYDGAQAAAGa1Akbd/wwOwqDAhn4AAABmtQJGUQUGeAB8siAlEAwOwqDAJrICxncAKE0xF//CoMInswJGdAAcRigtOF1NDmeVAUhtRXgBzQLGawAir/sgJRDioADCoMAmsgKGagAyLQQhCf/CoMI3sgLGZgD4PRxG8POCKC04XU0OZ5UBSG3FdAHNAiHy/gwO6WIi0iv5IkZdAAAh7v4MDjICAMKgxueTAsZYAMhSKC1SxfBQIsAyoMAgw5MizRg9AmKg78YBAEIDABszQGYwIEPAVyTxMg0FUg0EIg0GgDMRACIRUEMgQDIgIg0HDA6AIgEwIiAgJsAyoMEgw5OGQwAAACHU/gwOMgIAwqDG55MCxj4AODLCoMjnEwIGPADiQgDIUgY6AByCDA4MHCcVAgY3AAYQBWZFAoYWBUYwAFAgNAwOwqDA5xIChjAAUPRBi+3NAnz1xgwAKD5SYTUB/P7AAAA4LigeYi4AICMQUiE1JgMOwCAAQiYAMDUwQDMQMCIgwCAAKQYbzOLOEPc8yMZ7/2ZFAkZ6/wac/2a1Akb/BMYWAAAAYbv+DA44BgwUUsXwLQ4wJINQToNAIhDCoMbnkktxtP7tAogHwqDJVzg+UEAUwqDAos0YjNQGDABKKigCS0QpA0szDBJAmMBXNO0W4tg5BpkHxmH/ZoUCRuwEDBwMDsYBAAAA4qAAwqD/wCB0RWAB4CB0BWABhXABVsy+Ig0BDPM3EjEnMxVmQgIGtgRmYgLGugQmMgLG8/4GGQAAHCM3kgIGsAQyoNI3EkUcEzcSAkbt/sYYACGP/ug90i0CAbr+wAAAIY3+wCAAOAIhjP4gIxDgIoLQPSBFjAE9Ai0MAbP+wAAAIqPoAbD+wAAAxt3+WF1ITTg9Ii0CBWwBBtr+ADINAyINAoAzESAzIDLD8CLNGEVKAcbT/gAiDQMyDQKAIhEwIiAxYf4iwvAiYSkoMwwUIMSDwMB0jExSISn2VQvSzRjSYSQMH8Z3BAAioMkpU8bE/iFr/nGK/rIiAGEm/oKgAyInApIhKYJhJ7DGwCc5BAwaomEnsmE2BTkBsiE2cWH+UiEkYiEpcEvAykRqVQuEUmElgmErhwQCxk4Ed7sCRk0EkUL+PFOo6VIpEGIpFShpomEoUmEmYmEqyHniKRT4+SezAsbuAzFP/jAioCgCoAIAMTb+DA4MEumT6YMp0ymj4mEm/Q7iYSjNDoYGAHIhJwwTcGEEfMRgQ5NtBDliXQtyISSG4AMAAIIhJJIhJSEm/pe42DIIABt4OYKGBgCiIScMIzBqEHzFDBRgRYNtBDliXQuG1ANyISRSISUhG/5Xt9tSBwD4glmSgC8RHPNaIkJhMVJhNbJhNhvXhXgBDBNCITFSITWyITZWEgEioCAgVRBWhQDwIDQiwvggNYPw9EGL/wwSYSH+AB9AAFKhVzYPAA9AQPCRDAbwYoMwZiCcJgwfhgAA0iEkIQD+LEM5Yl0LhpwAXQu2PCAGDwByISd8w3BhBAwSYCODbQIMMwYWAAAAXQvSISRGAAD9BoIhJYe92RvdCy0iAgAAHEAAIqGLzCDuILY85G0Pcev94CAkKbcgIUEpx+DjQcLM/VYiIMAgJCc8KEYRAJIhJ3zDkGEEDBJgI4NtAgxTId/9OWJ9DQaVAwAAAF0L0iEkRgAA/QaiISWnvdEb3QstIgIAABxAACKhi8wg7iDAICQnPOHAICQAAkDg4JEir/ggzBDyoAAWnAaGDAAAAHIhJ3zDcGEEDBJgI4NtAgxjBuf/0iEkXQuCISWHveAb3QstIgIAABxAACKhIO4gi8y2jOQhv/3CzPj6MiHW/Soj4kIA4OhBhgwAAACSIScME5BhBHzEYDSDbQMMc8bU/9IhJF0LoiElIbL9p73dQcn9Mg0A+iJKIjJCABvdG//2TwKG3P8hqv189iLSKfISHCISHSBmMGBg9GefBwYeANIhJF0LLHMGQAC2jCFGDwAAciEnfMNwYQQMEmAjg20CPDMGu/8AAF0L0iEkRgAA/QaCISWHvdkb3QstIgIAABxAACKhi8wg7iC2jORtD+CQdJJhKODoQcLM+P0GRgIAPEOG0wLSISRdCyFd/Se176IhKAtvokUAG1UWhgdWrPiGHAAMk8bKAl0L0iEkRgAA/QYhU/0ntepGBgByISd8w3BhBAwSYCODbQIsY8aY/9IhJLBbIIIhJYe935FI/dBowFApwGeyAiBiIGe/AW0PTQbQPSBQJSBSYTViYTSyYTYBrf3AAABiITRSITWyITZq3WpVYG/AVmb5Rs8C/QYmMgjGBAAA0iEkXQsMoyFh/TlifQ1GFgMAAAwPJhICRiAAIqEgImcRLAQhdP1CZxIyoAVSYTViYTRyYTOyYTYBl/3AAAByITOyITZiITRSITU9ByKgkEKgCEJDWAsiGzNWUv8ioHAMkzJH6AsiG3dWUv8clHKhWJFH/Qx4RgIAAHoimiKCQgAtAxsyR5PxIVz9MVz9DIQGAQBCQgAbIjeS90ZgASFZ/foiIgIAJzwdRg8AAACiISd8w6BhBAwSYCODbQIMswZT/9IhJF0LIU79+iJiISVnvdsb3Qs9MgMAABxAADOhMO4gMgIAi8w3POEhRv1BRv36IjICAAwSABNAACKhQE+gCyLgIhAwzMAAA0Dg4JFIBDEf/SokMD+gImMRG//2PwKG3v8hOf1CoSAMA1JhNbJhNgFZ/cAAAH0NDA9SITWyITZGFQAAAIIhJ3zDgGEEDBJgI4NtAgzjBrMCciEkXQuSISWXt+AbdwsnIgIAABxAACKhIO4gi8y2POQhJf1BBP36IiICAOAwJCpEISL9wsz9KiQyQgDg40Eb/yH9/DIiEzc/0xwzMmIT3QdtDwYcAUwEDAMiwURSYTViYTSyYTZyYTMBNf3AAAByITOB7/wioWCAh4JBEP0qKPoiMqAAIsIYgmEyASz9wAAAgiEyIQv9QqSAKij6IgwDIsIYASb9wAAAqM+CITLwKqAiIhGK/6JhLSJhLk0PUiE1YiE0ciEzsiE2BgQAACIPWBv/ECKgMiIRGzMyYhEyIS5AL8A3MuYMAikRKQGtAgwT4EMRksFESvmYD0pBKinwIhEbMykUmqpms+Ux2Pw6IowS9iorIcj8QqbQQEeCgshYKogioLwqJIJhLAwJfPNCYTkiYTDGQwAAXQvSISRGAAD9BiwzxpgAAKIhLIIKAIJhNxaIDhAooHgCG/f5Av0IDALwIhEiYThCIThwIAQiYS8L/0AiIHBxQVZf/gynhzc7cHgRkHcgAHcRcHAxQiEwcmEvDBpxqPwAGEAAqqEqhHCIkPD6EXKj/4YCAABCIS+qIkJYAPqIJ7fyBiAAciE5IICUioeioLBBm/yqiECIkHKYDMxnMlgMfQMyw/4gKUGhlfzypLDGCgAggASAh8BCITl894CHMIqE8IiAoIiQcpgMzHcyWAwwcyAyw/6CITcLiIJhN0IhNwy4ICFBh5TIICAEIHfAfPoiITlwejB6ciKksCp3IYD8IHeQklcMQiEsG5kbREJhLHIhLpcXAsa9/4IhLSYoAsaYAEaBAAzix7ICxi8AkiEl0CnApiICBiUAIZX84DCUQW/8KiNAIpAiEgwAMhEwIDGW8gAwKTEWEgUnPAJGIwAGEgAADKPHs0KRivx8+AADQOBgkWBgBCAoMCommiJAIpAikgwbc9ZCBitjPQdnvN0GBgCiISd8w6BhBAwSYCODbQIcA8Z1/tIhJF0LYiElZ73gIg0AGz0AHEAAIqEg7iCLzAzi3QPHMgJG2/+GBwAiDQGLPAATQAAyoSINACvdABxAACKhICMgIO4gwswQIWj84DCUYUL8KiNgIpAyEgwAMxEwIDGWogAwOTEgIIRGCQAAAIFf/AykfPcbNAAEQOBAkUBABCAnMCokiiJgIpAikgxNA5Yi/gADQODgkTDMwCJhKAzzJyMVIS38ciEo+jIhUfwb/yojckIABjQAAIIhKGa4Gtx/HAmSYSgGAQDSISRdCxwTISL8fPY5YgZB/jFG/CojIsLwIgIAImEmJzwdBg4AoiEnfMOgYQQMEmAjg20CHCPGNf4AANIhJF0LYiElZ73eG90LLSICAHIhJgAcQAAioYvMIO4gdzzhgiEmMTP8kiEoDBYAGEAAZqGaMwtmMsPw4CYQYgMAAAhA4OCRKmYhLPyAzMAqLwwDZrkMMf/7+kMxKPw6NDIDAE0GUmE1YmE0smE2ATv8wAAAYiE0UiE1av+yITaGAAAADA9x9PtCJxFiJxJqZGe/AoZ5//eWB4YCANIhJF0LHFNGyf8A8RT8IRX8PQ9SYTViYTSyYTZyYTMBJ/zAAAByITMh/vsyJxFCJxI6PwEi/MAAALIhNmIhNFIhNTHd+yjDCyIpw/Hb+3jP1me4hj4BYiElDOLQNsCmQw9BqftQNMCmIwJGTQDGMQIAx7ICRi4ApiMCBiUAQc/74CCUQCKQIhK8ADIRMCAxlgIBMCkxFkIFJzwChiQAxhIAAAAMo8ezRHz4kqSwAANA4GCRYGAEICgwKiaaIkAikCKSDBtz1oIGK2M9B2e83YYGAHIhJ3zDcGEEDBJgI4NtAhxzxtT9AADSISRdC4IhJYe93iINABs9ABxAACKhIO4gi8wM4t0DxzICxtv/BggAAAAiDQGLPAATQAAyoSINACvdABxAACKhICMgIO4gwswQQaL74CCUQCKQIhK8ACIRIPAxlo8AICkx8PCExggADKN892KksBsjAANA4DCRMDAE8Pcw+vNq/0D/kPKfDD0Cli/+AAJA4OCRIMzAIqD/96ICxkAAhgIAAByDBtMA0iEkXQshXPsnte/yRQBtDxtVRusADOLHMhkyDQEiDQCAMxEgIyAAHEAAIqEg7iAr3cLMEDF9++AglKoiMCKQIhIMACIRIDAxICkx1hMCDKQbJAAEQOBAkUBABDA5MDo0QXL7ijNAM5AykwxNApbz/f0DAAJA4OCRIMzAd4N8YqAOxzYaQg0BIg0AgEQRICQgABxAACKhIO4g0s0CwswQQWP74CCUqiJAIpBCEgwARBFAIDFASTHWEgIMphtGAAZA4GCRYGAEICkwKiZhWPuKImAikCKSDG0ElvL9MkUAAARA4OCRQMzAdwIIG1X9AkYCAAAAIkUBK1UGc//wYIRm9gKGswAirv8qZiF0++BmEWoiKAIiYSYhcvtyISZqYvgGFpcFdzwdBg4AAACCISd8w4BhBAwSYCODbQIckwZb/dIhJF0LkiEll73gG90LLSICAKIhJgAcQAAioYvMIO4gpzzhYiEmDBIAFkAAIqELIuAiEGDMwAAGQODgkSr/DOLHsgJGMAByISXQJ8CmIgKGJQBBJvvgIJRAIpAi0g8iEgwAMhEwIDGW8gAwKTEWMgUnPAJGJACGEgAADKPHs0SRSft8+AADQOBgkWBgBCAoMCommiJAIpAikgwbc9aCBitjPQdnvN2GBgCCISd8w4BhBAwSYCODbQIco8Yr/QAA0iEkXQuSISWXvd4iDQAbPQAcQAAioSDuIIvMDOLdA8cyAkbb/wYIAAAAIg0BizwAE0AAMqEiDQAr3QAcQAAioSAjICDuIMLMEGH5+uAglGAikCLSDzISDAAzETAgMZaCADA5MSAghMYIAIEe+wykfPcbNAAEQOBAkUBABCAnMCokiiJgIpAikgxNA5Yi/gADQODgkTDMwDEU++AiESozOAMyYSYxEvuiISYqIygCImEoFgoGpzweRg4AciEnfMNwYQQMEmAjg20CHLPG9/wAAADSISRdC4IhJYe93RvdCy0iAgCSISYAHEAAIqGLzCDuIJc84aIhJgwSABpAACKhYiEoCyLgIhAqZgAKQODgkaDMwGJhKHHc+oIhKHB1wJIhKzHZ+oAnwJAiEDoicmEqPQUntQE9AkGQ+vozbQ83tG0GEgAhuvosUzliBm4APFMht/p9DTliDCZGbABdC9IhJEYAAP0GIYX6J7XhoiEqYiEociErYCrAMcP6cCIQKiMiAgAbqiJFAKJhKhtVC29WH/0GDAAAMgIAYsb9MkUAMgIBMkUBMgICOyIyRQI7VfY24xYGATICADJFAGYmBSICASJFAWpV/QaioLB8+YKksHKhAAa9/iGW+iiyB+IChpb8wCAkJzwgRg8AgiEnfMOAYQQMEmAjg20CLAMGrPwAAF0L0iEkRgAA/QaSISWXvdkb3QstIgIAABxAACKhi8wg7iDAICQnPOHAICQAAkDg4JF8giDMEH0NRgEAAAt3wsz4oiEkd7oC9ozxIar6Mar6TQxSYTVyYTOyYTaFlAALIrIhNnIhM1IhNSDuEAwPFkwGhgwAAACCISd8w4BhBAwSYCODbQIskwYPAHIhJF0LkiEll7fgG3cLJyICAAAcQAAioSDuIIvMtozk4DB0wsz44OhBhgoAoiEnfMOgYQQMEmAjg20CLKMhWfo5YoYPAAAAciEkXQtiISVnt9kyBwAbd0FT+hv/KKSAIhEwIiAppPZPB8bd/3IhJF0LIUz6LCM5YgwGhgEAciEkXQt89iYWFEsmzGJGAwALd8LM+IIhJHe4AvaM8YFC+iFy+jFy+sl4TQxSYTViYTRyYTOCYTKyYTYFhgCCITKSISiiISYLIpnokiEq4OIQomgQciEzoiEkUiE1siE2YiE0+fjiaBSSaBWg18CwxcD9BpZWDjFf+vjYLQxFfgDw4PRNAvDw9X0MDHhiITSyITZGJQAAAJICAKICAurpkgIB6pma7vr+4gIDmpqa/5qe4gIEmv+anuICBZr/mp7iAgaa/5qe4gIHmv+a7ur/iyI6kkc5wEAjQbAisLCQYEYCAAAyAgAbIjru6v8qOb0CRzPvMUH6LQ5CYTFiYTRyYTOCYTKyYTaFdQAxO/rtAi0PBXUAQiExciEzsiE2QHfAgiEyQTT6YiE0/QKMhy0LsDjAxub/AAAA/xEh+/nq7+nS/QbcVvii8O7AfO/g94NGAgAAAAAMDN0M8q/9MSf6UiEpKCNiISTQIsDQVcDaZtED+ikjOA1xAvpSYSnKU1kNcDXADAIMFfAlg2JhJCAgdFaCAELTgEAlgxaSAMH4+S0MBSkAyQ2CISmcKJHf+Sg5FrIA8C8x8CLA1iIAxoP7MqDHIdn5li8BjB9GRfoh1vkyIgPME4ZC+jKgyDlShkD6KC2MEsY++iHi+QEO+sAAAAEQ+sAAAEY6+sg9zByGOPoio+gBCPrAAADADADGNPriYSIMfEaH+gEI+sAAAAwcDAMGCAAAyC34PfAsICAgtMwSxo76Rif7Mi0DIi0CwqABxTIADAMgw4PGIvt4fWhtWF1ITTg9KC0MDAHu+cAAAO0CDBLgwpOGHvsAAAHo+cAAAEYDACG8+UhdOC1JAiG7+TkCDAzGE/tBufkMAjgEwqDIMMKDKQRBtPk9DAwcKQQwwoNGDPsAxzICxvT9xvv9AiFDkqEQwiFC0iFB4iFA8iE/mhEN8AAACAAAYBwAAGAAAABgEAAAYCH8/xLB8OkBwCAA6AIJMckh2REh+P/AIADIAsDAdJzs0ZD5RgQAAAAx9P/AIAAoAzgNICB0wAMAC8xmDOqG9P8h7/8IMcAgAOkCyCHYEegBEsEQDfAAAAD4AgBgEAIAYAACAGAAAAAIIfz/wCAAOAIwMCRWQ/8h+f9B+v/AIAA5AjH3/8AgAEkDwCAASANWdP/AIAAoAgwTICAEMCIwDfAAAIAAAAAAQP///wAEAgBgEsHwySHBZvkJMShM2REWgghF+v8WIggoTAzzDA0nowwoLDAiEAwTINOD0NB0EBEgRfj/FmL/Id7/Me7/wCAAOQLAIAAyIgBWY/8x1//AIAAoAyAgJFZC/ygsMeX/QEIRIVv50DKDIeT/ICQQQeT/wCAAKQQhz//AIAA5AsAgADgCVnP/DBIcA9Ajk90CKEzQIsApTCgs2tLZLAgxyCHYERLBEA3wAAAATEoAQBLB4MlhwTv5+TH4POlBCXHZUe0C97MB/QMWHwTYHNrf0NxBBgEAAACF8v8oTKYSBCgsJ63yRe3/FpL/KBxNDz0OAe7/wAAAICB0jDIioMQpXCgcSDz6IvBEwCkcSTwIcchh2FHoQfgxEsEgDfAAAAD/DwAAQSD5EsHwCTEMFVJEADBcQVkkUfr/KTQ5FFoiMDC0KiMgLEEpRAwCKVRC1CsiRAwBUPnAAAAIMTKgxSAjkxLBEA3wAAAwOwBAEsHwCTEyoMA3khEioNsB+//AAAAioNxGBAAAAAAyoNs3kggB9v/AAAAioN0B9P/AAAAIMRLBEA3wAAAAEsHwySHZEQkxzQI60kYCAAAiDADCzAHF+v/XnPMCIQPCIQLYERLBEA3wAABYEAAAcBAAABiYAEAcSwBANJgAQACZAECR+/8SweDJYelB+TEJcdlRkBHA7QIi0RDNAwH1/8AAAPHv+IYKAN0Mx78B3Q9NDT0BLQ4B8P/AAAAgIHT8Qk0NPQEi0RAB7P/AAADQ7oDQzMBWHP0h5f8y0RAQIoAB5//AAAAh4f8cAxoiBfX/LQwGAQAAACKgY5Hd/5oRCHHIYdhR6EH4MRLBIA3wABLB8CKgwAkxAbr/wAAACDESwRAN8AAAAGwQAABoEAAAdBAAAHgQAAB8EAAAgBAAAJAQAACYDwBAjDsAQBLB4JH8//kx/QIhxv/JYdlRCXHpQZARwBoiOQIx8v8sAhozSQNB8P/S0RAaRMKgAFJkAMJtGgHw/8AAAGHq/yG1+BpmaAZnsgLGSQAtDQG2/8AAACGz/zHl/ypBGjNJA0Y+AAAAYa//Md//GmZoBhoz6APAJsDnsgIg4iBh3f89ARpmWQZNDvAvIAGo/8AAADHY/yAgdBozWAOMsgwEQm0W7QTGEgAAAABB0f/q/xpEWQQF8f89Di0BheP/RfD/TQ49AdAtIAGa/8AAAGHJ/+rMGmZYBiGT/xoiKAInvLwxwv9QLMAaMzgDN7ICRt3/Rur/QqAAQk1sIbn/ECKAAb//wAAAVgL/Ybn/Ig1sEGaAOAZFBwD34hH2Tg5Bsf8aROo0IkMAG+7G8f8yr/43ksEmTikhe//QPSAQIoABfv/AAAAF6P8hdv8cAxoiRdr/Ref/LAIBn/jAAACGBQBhcf9SLRoaZmgGZ7XIVzwCBtn/xu//AJGg/5oRCHHIYdhR6EH4MRLBIA3wXQJCoMAoA0eVDswyDBKGBgAMAikDfOIN8CYSBSYiEcYLAEKg2y0FR5UpDCIpAwYIACKg3CeVCAwSKQMtBA3wAEKg3XzyR5ULDBIpAyKg2w3wAHzyDfAAALYjMG0CUPZAQPNAR7UpUETAABRAADOhDAI3NgQwZsAbIvAiETAxQQtEVsT+NzYBGyIN8ACMkw3wNzYMDBIN8AAAAAAARElWMAwCDfC2IyhQ8kBA80BHtRdQRMAAFEAAM6E3MgIwIsAwMUFCxP9WBP83MgIwIsAN8MxTAAAARElWMAwCDfAAAAAAFEDmxAkgM4EAIqEN8AAAADKhDAIN8AA="; +var text_start = 1074843648; +var data = "CIH+PwUFBAACAwcAAwMLAOzXEEAj2BBAUdgQQO7YEECd5xBAUtkQQKjZEED02RBAnecQQLraEEA32xBA+NsQQJ3nEECd5xBAkNwQQJ3nEEBt3xBANOAQQG/gEECd5xBAnecQQAvhEECd5xBA8+EQQJniEEDY4xBAl+QQQGjlEECd5xBAnecQQJ3nEECd5xBAluYQQJ3nEECM5xBAyN0QQMHYEEDa5RBA4doQQDPaEECd5xBAIOcQQGfnEECd5xBAnecQQJ3nEECd5xBAnecQQJ3nEECd5xBAnecQQFraEECX2hBA8uUQQAEAAAACAAAAAwAAAAQAAAAFAAAABwAAAAkAAAANAAAAEQAAABkAAAAhAAAAMQAAAEEAAABhAAAAgQAAAMEAAAABAQAAgQEAAAECAAABAwAAAQQAAAEGAAABCAAAAQwAAAEQAAABGAAAASAAAAEwAAABQAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABgAAAAcAAAAHAAAACAAAAAgAAAAJAAAACQAAAAoAAAAKAAAACwAAAAsAAAAMAAAADAAAAA0AAAANAAAAAAAAAAAAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAANAAAADwAAABEAAAATAAAAFwAAABsAAAAfAAAAIwAAACsAAAAzAAAAOwAAAEMAAABTAAAAYwAAAHMAAACDAAAAowAAAMMAAADjAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAgAAAAMAAAADAAAAAwAAAAMAAAAEAAAABAAAAAQAAAAEAAAABQAAAAUAAAAFAAAABQAAAAAAAAAAAAAAAAAAABAREgAIBwkGCgULBAwDDQIOAQ8AAQEAAAEAAAAEAAAA"; +var data_start = 1073720492; +var bss_start = 1073643776; +var esp8266 = { + entry: entry, + text: text, + text_start: text_start, + data: data, + data_start: data_start, + bss_start: bss_start +}; + +export { bss_start, data, data_start, esp8266 as default, entry, text, text_start }; diff --git a/js/modules/esptool.js b/js/modules/esptool.js index c28babb8..501ed68f 100644 --- a/js/modules/esptool.js +++ b/js/modules/esptool.js @@ -1 +1,10297 @@ -const t=t=>{let e=[192];for(const i of t)219==i?e=e.concat([219,221]):192==i?e=e.concat([219,220]):e.push(i);return e.push(192),e},e=t=>{const e=[];for(let i=0;i"["+t.map(t=>s(t)).join(", ")+"]",s=(t,e=2)=>{const i=t.toString(16).toUpperCase();return i.startsWith("-")?"-0x"+i.substring(1).padStart(e,"0"):"0x"+i.padStart(e,"0")},a=t=>t.map(t=>t.toString(16).toUpperCase().padStart(2,"0")).join(":");const r=t=>new Promise(e=>setTimeout(e,t)),n={18:"256KB",19:"512KB",20:"1MB",21:"2MB",22:"4MB",23:"8MB",24:"16MB",25:"32MB",26:"64MB",27:"128MB",28:"256MB",32:"64MB",33:"128MB",34:"256MB",50:"256KB",51:"512KB",52:"1MB",53:"2MB",54:"4MB",55:"8MB",56:"16MB",57:"32MB",58:"64MB"},o=4096,h=115200,l=1073061888,d=1061265408,c=1610641408,u=1610647552,g=1611352064,f=1611335680,_=1611352064,p=1611335680,b=1343410176,w=1343312316,m=1<<27,y=1343312312,S=1343312892,B=544296960,I=e(" UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"),R=33382,v=50,C=12882,E=12883,k=12994,x=12995,U=12997,M=12998,D=207969,O=12914,A=12916,F=12917,T=12928,L=12849,z={5:{name:"ESP32-C3",family:x},9:{name:"ESP32-S3",family:E},12:{name:"ESP32-C2",family:k},13:{name:"ESP32-C6",family:M},16:{name:"ESP32-H2",family:O},18:{name:"ESP32-P4",family:T},20:{name:"ESP32-C61",family:D},23:{name:"ESP32-C5",family:U},25:{name:"ESP32-H21",family:F},28:{name:"ESP32-H4",family:A},32:{name:"ESP32-S31",family:L}},P={4293968129:{name:"ESP8266",family:R},15736195:{name:"ESP32",family:v},1990:{name:"ESP32-S2",family:C}},N=2,$=3,W=4,j=5,G=6,H=7,J=8,Q=9,V=10,Z=208,X=209,K=210,q=11,Y=13,tt=15,et=19,it=20,st=239,at=16,rt=17,nt=18,ot=5,ht=2048,lt=6144,dt=3e3,ct=15e4,ut=3e5,gt=100,ft=3e4,_t=500,pt=100,bt=(t,e)=>{const i=Math.floor(t*(e/486));return i{switch(t){case v:return{regBase:1072963584,baseFuse:l,macFuse:1073061888,usrOffs:28,usr1Offs:32,usr2Offs:36,mosiDlenOffs:40,misoDlenOffs:44,w0Offs:128,uartDateReg:1610612856,flashOffs:4096};case C:return{regBase:1061167104,baseFuse:d,macFuse:1061265476,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612856,flashOffs:4096};case E:return{regBase:1610620928,usrOffs:24,baseFuse:c,macFuse:1610641476,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612864,flashOffs:0};case R:return{regBase:1610613248,usrOffs:28,baseFuse:1072693328,macFuse:1072693328,usr1Offs:32,usr2Offs:36,mosiDlenOffs:-1,misoDlenOffs:-1,w0Offs:64,uartDateReg:1610612856,flashOffs:0};case k:return{regBase:1610620928,baseFuse:u,macFuse:1610647616,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case x:return{regBase:1610620928,baseFuse:1610647552,macFuse:1610647620,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case U:return{regBase:1610625024,baseFuse:g,macFuse:1611352132,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:8192};case M:return{regBase:1610625024,baseFuse:f,macFuse:1611335748,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case D:return{regBase:1610625024,baseFuse:_,macFuse:1611352132,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case O:return{regBase:1610625024,baseFuse:p,macFuse:1611335748,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case A:return{regBase:1611239424,baseFuse:1611339776,macFuse:1611339844,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610686588,flashOffs:8192};case F:return{regBase:1610625024,baseFuse:1611350016,macFuse:1611350084,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1610612860,flashOffs:0};case T:return{regBase:1342754816,baseFuse:b,macFuse:1343410244,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:1343004812,flashOffs:8192};case L:return{regBase:542113792,baseFuse:B,macFuse:544297028,usrOffs:24,usr1Offs:28,usr2Offs:32,mosiDlenOffs:36,misoDlenOffs:40,w0Offs:88,uartDateReg:540582028,flashOffs:8192};default:return{regBase:-1,baseFuse:-1,macFuse:-1,usrOffs:-1,usr1Offs:-1,usr2Offs:-1,mosiDlenOffs:-1,misoDlenOffs:-1,w0Offs:-1,uartDateReg:-1,flashOffs:-1}}};class mt extends Error{constructor(t){super(t),this.name="SlipReadError"}}const yt=async(t,i)=>{let s;if(t==A||t==F||t==L)return null;if(t==v)s=await import("./esp32-BRKoi17y.js");else if(t==C)s=await import("./esp32s2-iX3WoDbg.js");else if(t==E)s=await import("./esp32s3-DGwDVIgz.js");else if(t==R)s=await import("./esp8266-CUwxJpGa.js");else if(t==k)s=await import("./esp32c2-Btgr_lwh.js");else if(t==x)s=await import("./esp32c3-CHKfoI8W.js");else if(t==U)s=await import("./esp32c5-BDW4KtLo.js");else if(t==M)s=await import("./esp32c6-il8tTxAG.js");else if(t==D)s=await import("./esp32c61-thKzxBGf.js");else if(t==O)s=await import("./esp32h2-CxoUHv_P.js");else{if(t!=T)return null;s=null!=i&&i>=300?await import("./esp32p4r3-CqI71ojR.js"):await import("./esp32p4-D3jLP-jY.js")}return{...s,text:e(atob(s.text)),data:e(atob(s.data))}},St={239:"Winbond",200:"GigaDevice",157:"ISSI",194:"Macronix/MXIC",32:"XMC / Micron",28:"EON",133:"Puya",104:"BOYA",161:"Fudan Microelectronics (FM)",1:"Spansion/Cypress",94:"Zbit",55:"AMIC",224:"Berg Micro"},Bt={66073:"S25FL256S (256Mbit)",81941:"S25FL016K (16Mbit)",81942:"S25FL032K (32Mbit)",90135:"S25FL064L (64Mbit)",90136:"S25FL128L (128Mbit)",1847315:"EN25Q40 (4Mbit)",1847316:"EN25Q80A (8Mbit)",1847317:"EN25Q16 (16Mbit)",1847318:"EN25Q32B (32Mbit)",1847319:"EN25Q64 (64Mbit)",1847320:"EN25Q128 (128Mbit)",1863701:"EN25QH16 (16Mbit)",1863702:"EN25QH32 (32Mbit)",1863703:"EN25QH64 (64Mbit)",1863704:"EN25QH128 (128Mbit)",2113557:"XM25QH16C (16Mbit)",2113558:"XM25QH32B (32Mbit)",2113559:"XM25QH64C (64Mbit)",2113560:"XM25QH128C (128Mbit)",2113561:"XM25QH256C (256Mbit)",2113817:"XM25QU256C (256Mbit)",2125847:"XM25QH64A (64Mbit)",2125848:"XM25QH128A (128Mbit)",2144790:"N25Q032A (32Mbit)",2144791:"N25Q064A (64Mbit)",2144792:"N25Q128A (128Mbit)",2145045:"N25Q016A (16Mbit)",3612693:"A25L016 (16Mbit)",3612694:"A25L032 (32Mbit)",3620886:"A25LQ032 (32Mbit)",6176789:"ZB25VQ16 (16Mbit)",6176790:"ZB25VQ32 (32Mbit)",6176791:"ZB25VQ64 (64Mbit)",6176792:"ZB25VQ128 (128Mbit)",6832149:"BY25Q16 (16Mbit)",6832150:"BY25Q32 (32Mbit)",6832151:"BY25Q64 (64Mbit)",6832152:"BY25Q128 (128Mbit)",8740885:"P25Q16H (16Mbit)",8740886:"P25Q32H (32Mbit)",8740887:"P25Q64H (64Mbit)",8740888:"P25Q128H (128Mbit)",10313749:"IS25LP016 (16Mbit)",10313750:"IS25LP032 (32Mbit)",10313751:"IS25LP064 (64Mbit)",10313752:"IS25LP128 (128Mbit)",10313753:"IS25LP256 (256Mbit)",10317845:"IS25WP016 (16Mbit)",10317846:"IS25WP032 (32Mbit)",10317847:"IS25WP064 (64Mbit)",10317848:"IS25WP128 (128Mbit)",10317849:"IS25WP256 (256Mbit)",10567700:"FM25Q08 (8Mbit)",10567701:"FM25Q16 (16Mbit)",10567702:"FM25Q32 (32Mbit)",10567703:"FM25Q64 (64Mbit)",10567704:"FM25Q128 (128Mbit)",12722192:"MX25L512E (512Kbit)",12722193:"MX25L1005C (1Mbit)",12722194:"MX25L2005C (2Mbit)",12722195:"MX25L4005 (4Mbit)",12722196:"MX25L8005 (8Mbit)",12722197:"MX25L1605D (16Mbit)",12722198:"MX25L3205D (32Mbit)",12722199:"MX25L6405D (64Mbit)",12722200:"MX25L12805D (128Mbit)",12722201:"MX25L25635E (256Mbit)",12722202:"MX25L51245G (512Mbit)",12738070:"MX25L3233F (32Mbit)",13123601:"GD25Q10 (1Mbit)",13123602:"GD25Q20 (2Mbit)",13123603:"GD25Q40 (4Mbit)",13123604:"GD25Q80 (8Mbit)",13123605:"GD25Q16 (16Mbit)",13123606:"GD25Q32 (32Mbit)",13123607:"GD25Q64 (64Mbit)",13123608:"GD25Q127C (128Mbit)",13123609:"GD25Q256 (256Mbit)",13123616:"GD25Q512 (512Mbit)",13131801:"GD25LQ256D (256Mbit)",14696469:"BG25Q16A (16Mbit)",14696470:"BG25Q32 (32Mbit)",14696471:"BG25Q64 (64Mbit)",14696472:"BG25Q128 (128Mbit)",15679508:"W25Q80 (8Mbit)",15679509:"W25Q16 (16Mbit)",15679510:"W25Q32 (32Mbit)",15679511:"W25Q64 (64Mbit)",15679512:"W25Q128 (128Mbit)",15679513:"W25Q256 (256Mbit)",15679520:"W25Q512JV (512Mbit)",15683602:"W25Q20BW (2Mbit)",15683603:"W25Q40BW (4Mbit)",15687697:"W25Q10EW (1Mbit)",15687698:"W25Q20EW (2Mbit)",15687699:"W25Q40EW (4Mbit)"};function It(t){let e=t.length;for(;--e>=0;)t[e]=0}const Rt=256,vt=286,Ct=30,Et=15,kt=new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]),xt=new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]),Ut=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]),Mt=new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),Dt=new Array(576);It(Dt);const Ot=new Array(60);It(Ot);const At=new Array(512);It(At);const Ft=new Array(256);It(Ft);const Tt=new Array(29);It(Tt);const Lt=new Array(Ct);function zt(t,e,i,s,a){this.static_tree=t,this.extra_bits=e,this.extra_base=i,this.elems=s,this.max_length=a,this.has_stree=t&&t.length}let Pt,Nt,$t;function Wt(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}It(Lt);const jt=t=>t<256?At[t]:At[256+(t>>>7)],Gt=(t,e)=>{t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255},Ht=(t,e,i)=>{t.bi_valid>16-i?(t.bi_buf|=e<>16-t.bi_valid,t.bi_valid+=i-16):(t.bi_buf|=e<{Ht(t,i[2*e],i[2*e+1])},Qt=(t,e)=>{let i=0;do{i|=1&t,t>>>=1,i<<=1}while(--e>0);return i>>>1},Vt=(t,e,i)=>{const s=new Array(16);let a,r,n=0;for(a=1;a<=Et;a++)n=n+i[a-1]<<1,s[a]=n;for(r=0;r<=e;r++){let e=t[2*r+1];0!==e&&(t[2*r]=Qt(s[e]++,e))}},Zt=t=>{let e;for(e=0;e{t.bi_valid>8?Gt(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0},Kt=(t,e,i,s)=>{const a=2*e,r=2*i;return t[a]{const s=t.heap[i];let a=i<<1;for(;a<=t.heap_len&&(a{let s,a,r,n,o=0;if(0!==t.sym_next)do{s=255&t.pending_buf[t.sym_buf+o++],s+=(255&t.pending_buf[t.sym_buf+o++])<<8,a=t.pending_buf[t.sym_buf+o++],0===s?Jt(t,a,e):(r=Ft[a],Jt(t,r+Rt+1,e),n=kt[r],0!==n&&(a-=Tt[r],Ht(t,a,n)),s--,r=jt(s),Jt(t,r,i),n=xt[r],0!==n&&(s-=Lt[r],Ht(t,s,n)))}while(o{const i=e.dyn_tree,s=e.stat_desc.static_tree,a=e.stat_desc.has_stree,r=e.stat_desc.elems;let n,o,h,l=-1;for(t.heap_len=0,t.heap_max=573,n=0;n>1;n>=1;n--)qt(t,i,n);h=r;do{n=t.heap[1],t.heap[1]=t.heap[t.heap_len--],qt(t,i,1),o=t.heap[1],t.heap[--t.heap_max]=n,t.heap[--t.heap_max]=o,i[2*h]=i[2*n]+i[2*o],t.depth[h]=(t.depth[n]>=t.depth[o]?t.depth[n]:t.depth[o])+1,i[2*n+1]=i[2*o+1]=h,t.heap[1]=h++,qt(t,i,1)}while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],((t,e)=>{const i=e.dyn_tree,s=e.max_code,a=e.stat_desc.static_tree,r=e.stat_desc.has_stree,n=e.stat_desc.extra_bits,o=e.stat_desc.extra_base,h=e.stat_desc.max_length;let l,d,c,u,g,f,_=0;for(u=0;u<=Et;u++)t.bl_count[u]=0;for(i[2*t.heap[t.heap_max]+1]=0,l=t.heap_max+1;l<573;l++)d=t.heap[l],u=i[2*i[2*d+1]+1]+1,u>h&&(u=h,_++),i[2*d+1]=u,d>s||(t.bl_count[u]++,g=0,d>=o&&(g=n[d-o]),f=i[2*d],t.opt_len+=f*(u+g),r&&(t.static_len+=f*(a[2*d+1]+g)));if(0!==_){do{for(u=h-1;0===t.bl_count[u];)u--;t.bl_count[u]--,t.bl_count[u+1]+=2,t.bl_count[h]--,_-=2}while(_>0);for(u=h;0!==u;u--)for(d=t.bl_count[u];0!==d;)c=t.heap[--l],c>s||(i[2*c+1]!==u&&(t.opt_len+=(u-i[2*c+1])*i[2*c],i[2*c+1]=u),d--)}})(t,e),Vt(i,l,t.bl_count)},ee=(t,e,i)=>{let s,a,r=-1,n=e[1],o=0,h=7,l=4;for(0===n&&(h=138,l=3),e[2*(i+1)+1]=65535,s=0;s<=i;s++)a=n,n=e[2*(s+1)+1],++o{let s,a,r=-1,n=e[1],o=0,h=7,l=4;for(0===n&&(h=138,l=3),s=0;s<=i;s++)if(a=n,n=e[2*(s+1)+1],!(++o{Ht(t,0+(s?1:0),3),Xt(t),Gt(t,i),Gt(t,~i),i&&t.pending_buf.set(t.window.subarray(e,e+i),t.pending),t.pending+=i};var re=(t,e,i,s)=>{let a,r,n=0;t.level>0?(2===t.strm.data_type&&(t.strm.data_type=(t=>{let e,i=4093624447;for(e=0;e<=31;e++,i>>>=1)if(1&i&&0!==t.dyn_ltree[2*e])return 0;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return 1;for(e=32;e{let e;for(ee(t,t.dyn_ltree,t.l_desc.max_code),ee(t,t.dyn_dtree,t.d_desc.max_code),te(t,t.bl_desc),e=18;e>=3&&0===t.bl_tree[2*Mt[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e})(t),a=t.opt_len+3+7>>>3,r=t.static_len+3+7>>>3,r<=a&&(a=r)):a=r=i+5,i+4<=a&&-1!==e?ae(t,e,i,s):4===t.strategy||r===a?(Ht(t,2+(s?1:0),3),Yt(t,Dt,Ot)):(Ht(t,4+(s?1:0),3),((t,e,i,s)=>{let a;for(Ht(t,e-257,5),Ht(t,i-1,5),Ht(t,s-4,4),a=0;a{se||((()=>{let t,e,i,s,a;const r=new Array(16);for(i=0,s=0;s<28;s++)for(Tt[s]=i,t=0;t<1<>=7;s(t.pending_buf[t.sym_buf+t.sym_next++]=e,t.pending_buf[t.sym_buf+t.sym_next++]=e>>8,t.pending_buf[t.sym_buf+t.sym_next++]=i,0===e?t.dyn_ltree[2*i]++:(t.matches++,e--,t.dyn_ltree[2*(Ft[i]+Rt+1)]++,t.dyn_dtree[2*jt(e)]++),t.sym_next===t.sym_end),_tr_align:t=>{Ht(t,2,3),Jt(t,256,Dt),(t=>{16===t.bi_valid?(Gt(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)})(t)}};var oe=(t,e,i,s)=>{let a=65535&t,r=t>>>16&65535,n=0;for(;0!==i;){n=i>2e3?2e3:i,i-=n;do{a=a+e[s++]|0,r=r+a|0}while(--n);a%=65521,r%=65521}return a|r<<16};const he=new Uint32Array((()=>{let t,e=[];for(var i=0;i<256;i++){t=i;for(var s=0;s<8;s++)t=1&t?3988292384^t>>>1:t>>>1;e[i]=t}return e})());var le=(t,e,i,s)=>{const a=he,r=s+i;t^=-1;for(let i=s;i>>8^a[255&(t^e[i])];return-1^t},de={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"},ce={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_OK:0,Z_STREAM_END:1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_UNKNOWN:2,Z_DEFLATED:8};const{_tr_init:ue,_tr_stored_block:ge,_tr_flush_block:fe,_tr_tally:_e,_tr_align:pe}=ne,{Z_NO_FLUSH:be,Z_PARTIAL_FLUSH:we,Z_FULL_FLUSH:me,Z_FINISH:ye,Z_BLOCK:Se,Z_OK:Be,Z_STREAM_END:Ie,Z_STREAM_ERROR:Re,Z_DATA_ERROR:ve,Z_BUF_ERROR:Ce,Z_DEFAULT_COMPRESSION:Ee,Z_FILTERED:ke,Z_HUFFMAN_ONLY:xe,Z_RLE:Ue,Z_FIXED:Me,Z_DEFAULT_STRATEGY:De,Z_UNKNOWN:Oe,Z_DEFLATED:Ae}=ce,Fe=258,Te=262,Le=42,ze=113,Pe=666,Ne=(t,e)=>(t.msg=de[e],e),$e=t=>2*t-(t>4?9:0),We=t=>{let e=t.length;for(;--e>=0;)t[e]=0},je=t=>{let e,i,s,a=t.w_size;e=t.hash_size,s=e;do{i=t.head[--s],t.head[s]=i>=a?i-a:0}while(--e);e=a,s=e;do{i=t.prev[--s],t.prev[s]=i>=a?i-a:0}while(--e)};let Ge=(t,e,i)=>(e<{const e=t.state;let i=e.pending;i>t.avail_out&&(i=t.avail_out),0!==i&&(t.output.set(e.pending_buf.subarray(e.pending_out,e.pending_out+i),t.next_out),t.next_out+=i,e.pending_out+=i,t.total_out+=i,t.avail_out-=i,e.pending-=i,0===e.pending&&(e.pending_out=0))},Je=(t,e)=>{fe(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,He(t.strm)},Qe=(t,e)=>{t.pending_buf[t.pending++]=e},Ve=(t,e)=>{t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e},Ze=(t,e,i,s)=>{let a=t.avail_in;return a>s&&(a=s),0===a?0:(t.avail_in-=a,e.set(t.input.subarray(t.next_in,t.next_in+a),i),1===t.state.wrap?t.adler=oe(t.adler,e,a,i):2===t.state.wrap&&(t.adler=le(t.adler,e,a,i)),t.next_in+=a,t.total_in+=a,a)},Xe=(t,e)=>{let i,s,a=t.max_chain_length,r=t.strstart,n=t.prev_length,o=t.nice_match;const h=t.strstart>t.w_size-Te?t.strstart-(t.w_size-Te):0,l=t.window,d=t.w_mask,c=t.prev,u=t.strstart+Fe;let g=l[r+n-1],f=l[r+n];t.prev_length>=t.good_match&&(a>>=2),o>t.lookahead&&(o=t.lookahead);do{if(i=e,l[i+n]===f&&l[i+n-1]===g&&l[i]===l[r]&&l[++i]===l[r+1]){r+=2,i++;do{}while(l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&l[++r]===l[++i]&&rn){if(t.match_start=e,n=s,s>=o)break;g=l[r+n-1],f=l[r+n]}}}while((e=c[e&d])>h&&0!==--a);return n<=t.lookahead?n:t.lookahead},Ke=t=>{const e=t.w_size;let i,s,a;do{if(s=t.window_size-t.lookahead-t.strstart,t.strstart>=e+(e-Te)&&(t.window.set(t.window.subarray(e,e+e-s),0),t.match_start-=e,t.strstart-=e,t.block_start-=e,t.insert>t.strstart&&(t.insert=t.strstart),je(t),s+=e),0===t.strm.avail_in)break;if(i=Ze(t.strm,t.window,t.strstart+t.lookahead,s),t.lookahead+=i,t.lookahead+t.insert>=3)for(a=t.strstart-t.insert,t.ins_h=t.window[a],t.ins_h=Ge(t,t.ins_h,t.window[a+1]);t.insert&&(t.ins_h=Ge(t,t.ins_h,t.window[a+3-1]),t.prev[a&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=a,a++,t.insert--,!(t.lookahead+t.insert<3)););}while(t.lookahead{let i,s,a,r=t.pending_buf_size-5>t.w_size?t.w_size:t.pending_buf_size-5,n=0,o=t.strm.avail_in;do{if(i=65535,a=t.bi_valid+42>>3,t.strm.avail_outs+t.strm.avail_in&&(i=s+t.strm.avail_in),i>a&&(i=a),i>8,t.pending_buf[t.pending-2]=~i,t.pending_buf[t.pending-1]=~i>>8,He(t.strm),s&&(s>i&&(s=i),t.strm.output.set(t.window.subarray(t.block_start,t.block_start+s),t.strm.next_out),t.strm.next_out+=s,t.strm.avail_out-=s,t.strm.total_out+=s,t.block_start+=s,i-=s),i&&(Ze(t.strm,t.strm.output,t.strm.next_out,i),t.strm.next_out+=i,t.strm.avail_out-=i,t.strm.total_out+=i)}while(0===n);return o-=t.strm.avail_in,o&&(o>=t.w_size?(t.matches=2,t.window.set(t.strm.input.subarray(t.strm.next_in-t.w_size,t.strm.next_in),0),t.strstart=t.w_size,t.insert=t.strstart):(t.window_size-t.strstart<=o&&(t.strstart-=t.w_size,t.window.set(t.window.subarray(t.w_size,t.w_size+t.strstart),0),t.matches<2&&t.matches++,t.insert>t.strstart&&(t.insert=t.strstart)),t.window.set(t.strm.input.subarray(t.strm.next_in-o,t.strm.next_in),t.strstart),t.strstart+=o,t.insert+=o>t.w_size-t.insert?t.w_size-t.insert:o),t.block_start=t.strstart),t.high_watera&&t.block_start>=t.w_size&&(t.block_start-=t.w_size,t.strstart-=t.w_size,t.window.set(t.window.subarray(t.w_size,t.w_size+t.strstart),0),t.matches<2&&t.matches++,a+=t.w_size,t.insert>t.strstart&&(t.insert=t.strstart)),a>t.strm.avail_in&&(a=t.strm.avail_in),a&&(Ze(t.strm,t.window,t.strstart,a),t.strstart+=a,t.insert+=a>t.w_size-t.insert?t.w_size-t.insert:a),t.high_water>3,a=t.pending_buf_size-a>65535?65535:t.pending_buf_size-a,r=a>t.w_size?t.w_size:a,s=t.strstart-t.block_start,(s>=r||(s||e===ye)&&e!==be&&0===t.strm.avail_in&&s<=a)&&(i=s>a?a:s,n=e===ye&&0===t.strm.avail_in&&i===s?1:0,ge(t,t.block_start,i,n),t.block_start+=i,He(t.strm)),n?3:1)},Ye=(t,e)=>{let i,s;for(;;){if(t.lookahead=3&&(t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+3-1]),i=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!==i&&t.strstart-i<=t.w_size-Te&&(t.match_length=Xe(t,i)),t.match_length>=3)if(s=_e(t,t.strstart-t.match_start,t.match_length-3),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=3){t.match_length--;do{t.strstart++,t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+3-1]),i=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart}while(0!==--t.match_length);t.strstart++}else t.strstart+=t.match_length,t.match_length=0,t.ins_h=t.window[t.strstart],t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+1]);else s=_e(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++;if(s&&(Je(t,!1),0===t.strm.avail_out))return 1}return t.insert=t.strstart<2?t.strstart:2,e===ye?(Je(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(Je(t,!1),0===t.strm.avail_out)?1:2},ti=(t,e)=>{let i,s,a;for(;;){if(t.lookahead=3&&(t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+3-1]),i=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),t.prev_length=t.match_length,t.prev_match=t.match_start,t.match_length=2,0!==i&&t.prev_length4096)&&(t.match_length=2)),t.prev_length>=3&&t.match_length<=t.prev_length){a=t.strstart+t.lookahead-3,s=_e(t,t.strstart-1-t.prev_match,t.prev_length-3),t.lookahead-=t.prev_length-1,t.prev_length-=2;do{++t.strstart<=a&&(t.ins_h=Ge(t,t.ins_h,t.window[t.strstart+3-1]),i=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart)}while(0!==--t.prev_length);if(t.match_available=0,t.match_length=2,t.strstart++,s&&(Je(t,!1),0===t.strm.avail_out))return 1}else if(t.match_available){if(s=_e(t,0,t.window[t.strstart-1]),s&&Je(t,!1),t.strstart++,t.lookahead--,0===t.strm.avail_out)return 1}else t.match_available=1,t.strstart++,t.lookahead--}return t.match_available&&(s=_e(t,0,t.window[t.strstart-1]),t.match_available=0),t.insert=t.strstart<2?t.strstart:2,e===ye?(Je(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(Je(t,!1),0===t.strm.avail_out)?1:2};function ei(t,e,i,s,a){this.good_length=t,this.max_lazy=e,this.nice_length=i,this.max_chain=s,this.func=a}const ii=[new ei(0,0,0,0,qe),new ei(4,4,8,4,Ye),new ei(4,5,16,8,Ye),new ei(4,6,32,32,Ye),new ei(4,4,16,16,ti),new ei(8,16,32,32,ti),new ei(8,16,128,128,ti),new ei(8,32,128,256,ti),new ei(32,128,258,1024,ti),new ei(32,258,258,4096,ti)];function si(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=Ae,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new Uint16Array(1146),this.dyn_dtree=new Uint16Array(122),this.bl_tree=new Uint16Array(78),We(this.dyn_ltree),We(this.dyn_dtree),We(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new Uint16Array(16),this.heap=new Uint16Array(573),We(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new Uint16Array(573),We(this.depth),this.sym_buf=0,this.lit_bufsize=0,this.sym_next=0,this.sym_end=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}const ai=t=>{if(!t)return 1;const e=t.state;return!e||e.strm!==t||e.status!==Le&&57!==e.status&&69!==e.status&&73!==e.status&&91!==e.status&&103!==e.status&&e.status!==ze&&e.status!==Pe?1:0},ri=t=>{if(ai(t))return Ne(t,Re);t.total_in=t.total_out=0,t.data_type=Oe;const e=t.state;return e.pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=2===e.wrap?57:e.wrap?Le:ze,t.adler=2===e.wrap?0:1,e.last_flush=-2,ue(e),Be},ni=t=>{const e=ri(t);var i;return e===Be&&((i=t.state).window_size=2*i.w_size,We(i.head),i.max_lazy_match=ii[i.level].max_lazy,i.good_match=ii[i.level].good_length,i.nice_match=ii[i.level].nice_length,i.max_chain_length=ii[i.level].max_chain,i.strstart=0,i.block_start=0,i.lookahead=0,i.insert=0,i.match_length=i.prev_length=2,i.match_available=0,i.ins_h=0),e},oi=(t,e,i,s,a,r)=>{if(!t)return Re;let n=1;if(e===Ee&&(e=6),s<0?(n=0,s=-s):s>15&&(n=2,s-=16),a<1||a>9||i!==Ae||s<8||s>15||e<0||e>9||r<0||r>Me||8===s&&1!==n)return Ne(t,Re);8===s&&(s=9);const o=new si;return t.state=o,o.strm=t,o.status=Le,o.wrap=n,o.gzhead=null,o.w_bits=s,o.w_size=1<oi(t,e,Ae,15,8,De),deflateInit2:oi,deflateReset:ni,deflateResetKeep:ri,deflateSetHeader:(t,e)=>ai(t)||2!==t.state.wrap?Re:(t.state.gzhead=e,Be),deflate:(t,e)=>{if(ai(t)||e>Se||e<0)return t?Ne(t,Re):Re;const i=t.state;if(!t.output||0!==t.avail_in&&!t.input||i.status===Pe&&e!==ye)return Ne(t,0===t.avail_out?Ce:Re);const s=i.last_flush;if(i.last_flush=e,0!==i.pending){if(He(t),0===t.avail_out)return i.last_flush=-1,Be}else if(0===t.avail_in&&$e(e)<=$e(s)&&e!==ye)return Ne(t,Ce);if(i.status===Pe&&0!==t.avail_in)return Ne(t,Ce);if(i.status===Le&&0===i.wrap&&(i.status=ze),i.status===Le){let e=Ae+(i.w_bits-8<<4)<<8,s=-1;if(s=i.strategy>=xe||i.level<2?0:i.level<6?1:6===i.level?2:3,e|=s<<6,0!==i.strstart&&(e|=32),e+=31-e%31,Ve(i,e),0!==i.strstart&&(Ve(i,t.adler>>>16),Ve(i,65535&t.adler)),t.adler=1,i.status=ze,He(t),0!==i.pending)return i.last_flush=-1,Be}if(57===i.status)if(t.adler=0,Qe(i,31),Qe(i,139),Qe(i,8),i.gzhead)Qe(i,(i.gzhead.text?1:0)+(i.gzhead.hcrc?2:0)+(i.gzhead.extra?4:0)+(i.gzhead.name?8:0)+(i.gzhead.comment?16:0)),Qe(i,255&i.gzhead.time),Qe(i,i.gzhead.time>>8&255),Qe(i,i.gzhead.time>>16&255),Qe(i,i.gzhead.time>>24&255),Qe(i,9===i.level?2:i.strategy>=xe||i.level<2?4:0),Qe(i,255&i.gzhead.os),i.gzhead.extra&&i.gzhead.extra.length&&(Qe(i,255&i.gzhead.extra.length),Qe(i,i.gzhead.extra.length>>8&255)),i.gzhead.hcrc&&(t.adler=le(t.adler,i.pending_buf,i.pending,0)),i.gzindex=0,i.status=69;else if(Qe(i,0),Qe(i,0),Qe(i,0),Qe(i,0),Qe(i,0),Qe(i,9===i.level?2:i.strategy>=xe||i.level<2?4:0),Qe(i,3),i.status=ze,He(t),0!==i.pending)return i.last_flush=-1,Be;if(69===i.status){if(i.gzhead.extra){let e=i.pending,s=(65535&i.gzhead.extra.length)-i.gzindex;for(;i.pending+s>i.pending_buf_size;){let a=i.pending_buf_size-i.pending;if(i.pending_buf.set(i.gzhead.extra.subarray(i.gzindex,i.gzindex+a),i.pending),i.pending=i.pending_buf_size,i.gzhead.hcrc&&i.pending>e&&(t.adler=le(t.adler,i.pending_buf,i.pending-e,e)),i.gzindex+=a,He(t),0!==i.pending)return i.last_flush=-1,Be;e=0,s-=a}let a=new Uint8Array(i.gzhead.extra);i.pending_buf.set(a.subarray(i.gzindex,i.gzindex+s),i.pending),i.pending+=s,i.gzhead.hcrc&&i.pending>e&&(t.adler=le(t.adler,i.pending_buf,i.pending-e,e)),i.gzindex=0}i.status=73}if(73===i.status){if(i.gzhead.name){let e,s=i.pending;do{if(i.pending===i.pending_buf_size){if(i.gzhead.hcrc&&i.pending>s&&(t.adler=le(t.adler,i.pending_buf,i.pending-s,s)),He(t),0!==i.pending)return i.last_flush=-1,Be;s=0}e=i.gzindexs&&(t.adler=le(t.adler,i.pending_buf,i.pending-s,s)),i.gzindex=0}i.status=91}if(91===i.status){if(i.gzhead.comment){let e,s=i.pending;do{if(i.pending===i.pending_buf_size){if(i.gzhead.hcrc&&i.pending>s&&(t.adler=le(t.adler,i.pending_buf,i.pending-s,s)),He(t),0!==i.pending)return i.last_flush=-1,Be;s=0}e=i.gzindexs&&(t.adler=le(t.adler,i.pending_buf,i.pending-s,s))}i.status=103}if(103===i.status){if(i.gzhead.hcrc){if(i.pending+2>i.pending_buf_size&&(He(t),0!==i.pending))return i.last_flush=-1,Be;Qe(i,255&t.adler),Qe(i,t.adler>>8&255),t.adler=0}if(i.status=ze,He(t),0!==i.pending)return i.last_flush=-1,Be}if(0!==t.avail_in||0!==i.lookahead||e!==be&&i.status!==Pe){let s=0===i.level?qe(i,e):i.strategy===xe?((t,e)=>{let i;for(;;){if(0===t.lookahead&&(Ke(t),0===t.lookahead)){if(e===be)return 1;break}if(t.match_length=0,i=_e(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,i&&(Je(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,e===ye?(Je(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(Je(t,!1),0===t.strm.avail_out)?1:2})(i,e):i.strategy===Ue?((t,e)=>{let i,s,a,r;const n=t.window;for(;;){if(t.lookahead<=Fe){if(Ke(t),t.lookahead<=Fe&&e===be)return 1;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=3&&t.strstart>0&&(a=t.strstart-1,s=n[a],s===n[++a]&&s===n[++a]&&s===n[++a])){r=t.strstart+Fe;do{}while(s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&s===n[++a]&&at.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=3?(i=_e(t,1,t.match_length-3),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(i=_e(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),i&&(Je(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,e===ye?(Je(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(Je(t,!1),0===t.strm.avail_out)?1:2})(i,e):ii[i.level].func(i,e);if(3!==s&&4!==s||(i.status=Pe),1===s||3===s)return 0===t.avail_out&&(i.last_flush=-1),Be;if(2===s&&(e===we?pe(i):e!==Se&&(ge(i,0,0,!1),e===me&&(We(i.head),0===i.lookahead&&(i.strstart=0,i.block_start=0,i.insert=0))),He(t),0===t.avail_out))return i.last_flush=-1,Be}return e!==ye?Be:i.wrap<=0?Ie:(2===i.wrap?(Qe(i,255&t.adler),Qe(i,t.adler>>8&255),Qe(i,t.adler>>16&255),Qe(i,t.adler>>24&255),Qe(i,255&t.total_in),Qe(i,t.total_in>>8&255),Qe(i,t.total_in>>16&255),Qe(i,t.total_in>>24&255)):(Ve(i,t.adler>>>16),Ve(i,65535&t.adler)),He(t),i.wrap>0&&(i.wrap=-i.wrap),0!==i.pending?Be:Ie)},deflateEnd:t=>{if(ai(t))return Re;const e=t.state.status;return t.state=null,e===ze?Ne(t,ve):Be},deflateSetDictionary:(t,e)=>{let i=e.length;if(ai(t))return Re;const s=t.state,a=s.wrap;if(2===a||1===a&&s.status!==Le||s.lookahead)return Re;if(1===a&&(t.adler=oe(t.adler,e,i,0)),s.wrap=0,i>=s.w_size){0===a&&(We(s.head),s.strstart=0,s.block_start=0,s.insert=0);let t=new Uint8Array(s.w_size);t.set(e.subarray(i-s.w_size,i),0),e=t,i=s.w_size}const r=t.avail_in,n=t.next_in,o=t.input;for(t.avail_in=i,t.next_in=0,t.input=e,Ke(s);s.lookahead>=3;){let t=s.strstart,e=s.lookahead-2;do{s.ins_h=Ge(s,s.ins_h,s.window[t+3-1]),s.prev[t&s.w_mask]=s.head[s.ins_h],s.head[s.ins_h]=t,t++}while(--e);s.strstart=t,s.lookahead=2,Ke(s)}return s.strstart+=s.lookahead,s.block_start=s.strstart,s.insert=s.lookahead,s.lookahead=0,s.match_length=s.prev_length=2,s.match_available=0,t.next_in=n,t.input=o,t.avail_in=r,s.wrap=a,Be},deflateInfo:"pako deflate (from Nodeca project)"};const li=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var di=function(t){const e=Array.prototype.slice.call(arguments,1);for(;e.length;){const i=e.shift();if(i){if("object"!=typeof i)throw new TypeError(i+"must be non-object");for(const e in i)li(i,e)&&(t[e]=i[e])}}return t},ci=t=>{let e=0;for(let i=0,s=t.length;i=252?6:t>=248?5:t>=240?4:t>=224?3:t>=192?2:1;gi[254]=gi[254]=1;var fi=t=>{if("function"==typeof TextEncoder&&TextEncoder.prototype.encode)return(new TextEncoder).encode(t);let e,i,s,a,r,n=t.length,o=0;for(a=0;a>>6,e[r++]=128|63&i):i<65536?(e[r++]=224|i>>>12,e[r++]=128|i>>>6&63,e[r++]=128|63&i):(e[r++]=240|i>>>18,e[r++]=128|i>>>12&63,e[r++]=128|i>>>6&63,e[r++]=128|63&i);return e};var _i=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0};const pi=Object.prototype.toString,{Z_NO_FLUSH:bi,Z_SYNC_FLUSH:wi,Z_FULL_FLUSH:mi,Z_FINISH:yi,Z_OK:Si,Z_STREAM_END:Bi,Z_DEFAULT_COMPRESSION:Ii,Z_DEFAULT_STRATEGY:Ri,Z_DEFLATED:vi}=ce;function Ci(t){this.options=di({level:Ii,method:vi,chunkSize:16384,windowBits:15,memLevel:8,strategy:Ri},t||{});let e=this.options;e.raw&&e.windowBits>0?e.windowBits=-e.windowBits:e.gzip&&e.windowBits>0&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new _i,this.strm.avail_out=0;let i=hi.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(i!==Si)throw new Error(de[i]);if(e.header&&hi.deflateSetHeader(this.strm,e.header),e.dictionary){let t;if(t="string"==typeof e.dictionary?fi(e.dictionary):"[object ArrayBuffer]"===pi.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,i=hi.deflateSetDictionary(this.strm,t),i!==Si)throw new Error(de[i]);this._dict_set=!0}}Ci.prototype.push=function(t,e){const i=this.strm,s=this.options.chunkSize;let a,r;if(this.ended)return!1;for(r=e===~~e?e:!0===e?yi:bi,"string"==typeof t?i.input=fi(t):"[object ArrayBuffer]"===pi.call(t)?i.input=new Uint8Array(t):i.input=t,i.next_in=0,i.avail_in=i.input.length;;)if(0===i.avail_out&&(i.output=new Uint8Array(s),i.next_out=0,i.avail_out=s),(r===wi||r===mi)&&i.avail_out<=6)this.onData(i.output.subarray(0,i.next_out)),i.avail_out=0;else{if(a=hi.deflate(i,r),a===Bi)return i.next_out>0&&this.onData(i.output.subarray(0,i.next_out)),a=hi.deflateEnd(this.strm),this.onEnd(a),this.ended=!0,a===Si;if(0!==i.avail_out){if(r>0&&i.next_out>0)this.onData(i.output.subarray(0,i.next_out)),i.avail_out=0;else if(0===i.avail_in)break}else this.onData(i.output)}return!0},Ci.prototype.onData=function(t){this.chunks.push(t)},Ci.prototype.onEnd=function(t){t===Si&&(this.result=ci(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg};var Ei={deflate:function(t,e){const i=new Ci(e);if(i.push(t,!0),i.err)throw i.msg||de[i.err];return i.result}};const{deflate:ki}=Ei;var xi=ki;const Ui={b:{u:DataView.prototype.getInt8,p:DataView.prototype.setInt8,bytes:1},B:{u:DataView.prototype.getUint8,p:DataView.prototype.setUint8,bytes:1},h:{u:DataView.prototype.getInt16,p:DataView.prototype.setInt16,bytes:2},H:{u:DataView.prototype.getUint16,p:DataView.prototype.setUint16,bytes:2},i:{u:DataView.prototype.getInt32,p:DataView.prototype.setInt32,bytes:4},I:{u:DataView.prototype.getUint32,p:DataView.prototype.setUint32,bytes:4}},Mi=(t,...e)=>{let i=0;if(t.replace(/[<>]/,"").length!=e.length)throw"Pack format to Argument count mismatch";const s=[];let a=!0;for(let s=0;s"==t[s]?a=!1:(r(t[s],e[i]),i++);function r(t,e){if(!(t in Ui))throw"Unhandled character '"+t+"' in pack format";const i=Ui[t].bytes,r=new DataView(new ArrayBuffer(i));Ui[t].p.bind(r)(0,e,a);for(let t=0;t{let i=0;const s=[];let a=!0;for(const e of t)"<"==e?a=!0:">"==e?a=!1:r(e);function r(t){if(!(t in Ui))throw"Unhandled character '"+t+"' in unpack format";const r=Ui[t].bytes,n=new DataView(new ArrayBuffer(r));for(let t=0;t=this._inputBuffer.length))return this._inputBuffer[this._inputBufferReadIndex++]}_clearInputBuffer(){this._inputBuffer.length=0,this._inputBufferReadIndex=0}_compactInputBuffer(){this._inputBufferReadIndex>1e3&&this._inputBufferReadIndex>this._inputBuffer.length/2&&(this._inputBuffer.splice(0,this._inputBufferReadIndex),this._inputBufferReadIndex=0)}get _totalBytesRead(){return this._parent?this._parent._totalBytesRead:this.__totalBytesRead||0}set _totalBytesRead(t){this._parent?this._parent._totalBytesRead=t:this.__totalBytesRead=t}get _commandLock(){return this._parent?this._parent._commandLock:this.__commandLock}set _commandLock(t){this._parent?this._parent._commandLock=t:this.__commandLock=t}get _isReconfiguring(){return this._parent?this._parent._isReconfiguring:this.__isReconfiguring}set _isReconfiguring(t){this._parent?this._parent._isReconfiguring=t:this.__isReconfiguring=t}get _abandonCurrentOperation(){return this._parent?this._parent._abandonCurrentOperation:this.__abandonCurrentOperation}set _abandonCurrentOperation(t){this._parent?this._parent._abandonCurrentOperation=t:this.__abandonCurrentOperation=t}get _adaptiveBlockMultiplier(){return this._parent?this._parent._adaptiveBlockMultiplier:this.__adaptiveBlockMultiplier}set _adaptiveBlockMultiplier(t){this._parent?this._parent._adaptiveBlockMultiplier=t:this.__adaptiveBlockMultiplier=t}get _adaptiveMaxInFlightMultiplier(){return this._parent?this._parent._adaptiveMaxInFlightMultiplier:this.__adaptiveMaxInFlightMultiplier}set _adaptiveMaxInFlightMultiplier(t){this._parent?this._parent._adaptiveMaxInFlightMultiplier=t:this.__adaptiveMaxInFlightMultiplier=t}get _consecutiveSuccessfulChunks(){return this._parent?this._parent._consecutiveSuccessfulChunks:this.__consecutiveSuccessfulChunks}set _consecutiveSuccessfulChunks(t){this._parent?this._parent._consecutiveSuccessfulChunks=t:this.__consecutiveSuccessfulChunks=t}get _lastAdaptiveAdjustment(){return this._parent?this._parent._lastAdaptiveAdjustment:this.__lastAdaptiveAdjustment}set _lastAdaptiveAdjustment(t){this._parent?this._parent._lastAdaptiveAdjustment=t:this.__lastAdaptiveAdjustment=t}get _isCDCDevice(){return this._parent?this._parent._isCDCDevice:this.__isCDCDevice}set _isCDCDevice(t){this._parent?this._parent._isCDCDevice=t:this.__isCDCDevice=t}detectUSBSerialChip(t,e){const i={6790:{29986:{name:"CH340",maxBaudrate:460800},29987:{name:"CH340",maxBaudrate:460800},30084:{name:"CH340",maxBaudrate:460800},21795:{name:"CH341",maxBaudrate:2e6},21971:{name:"CH343",maxBaudrate:6e6},21972:{name:"CH9102",maxBaudrate:6e6},21976:{name:"CH9101",maxBaudrate:3e6}},4292:{6e4:{name:"CP2102(n)",maxBaudrate:3e6},60016:{name:"CP2105",maxBaudrate:2e6},60017:{name:"CP2108",maxBaudrate:2e6}},1027:{24577:{name:"FT232R",maxBaudrate:3e6},24592:{name:"FT2232",maxBaudrate:3e6},24593:{name:"FT4232",maxBaudrate:3e6},24596:{name:"FT232H",maxBaudrate:12e6},24597:{name:"FT230X",maxBaudrate:3e6}},12346:{2:{name:"ESP32-S2 Native USB",maxBaudrate:2e6},18:{name:"ESP32-P4 Native USB",maxBaudrate:2e6},4097:{name:"ESP32 Native USB",maxBaudrate:2e6}}}[t];return i&&i[e]?i[e]:{name:`Unknown (VID: 0x${t.toString(16)}, PID: 0x${e.toString(16)})`}}async initialize(){if(!this._parent){this.__inputBuffer=[],this.__inputBufferReadIndex=0,this.__totalBytesRead=0;const t=this.port.getInfo();if(t.usbVendorId&&t.usbProductId){const e=this.detectUSBSerialChip(t.usbVendorId,t.usbProductId);this.logger.log(`USB-Serial: ${e.name} (VID: 0x${t.usbVendorId.toString(16)}, PID: 0x${t.usbProductId.toString(16)})`),e.maxBaudrate&&(this._maxUSBSerialBaudrate=e.maxBaudrate,this.logger.log(`Max baudrate: ${e.maxBaudrate}`)),12346===t.usbVendorId&&2===t.usbProductId&&(this._isESP32S2NativeUSB=!0),(12346===t.usbVendorId||6790===t.usbVendorId&&21971===t.usbProductId)&&(this._isCDCDevice=!0)}this.readLoop()}await this.connectWithResetStrategies(),await this.detectChip(),this.chipFamily===T&&301===this.chipRevision&&await this.powerOnFlash();try{this._isUsbJtagOrOtg=await this.detectUsbConnectionType(),this.logger.debug("USB connection type: "+(this._isUsbJtagOrOtg?"USB-JTAG/OTG":"External Serial Chip"))}catch(t){this.logger.debug(`Could not detect USB connection type: ${t}`)}try{const t=await this.getUsbMode();this.logger.debug(`USB mode (register): ${t.mode} (uartNo=${t.uartNo})`)}catch(t){this.logger.debug(`Could not detect USB mode: ${t}`)}const t=wt(this.getChipFamily()),e=t.macFuse;for(let t=0;t<4;t++)this._efuses[t]=await this.readRegister(e+4*t);const i=null!==this.chipRevision&&void 0!==this.chipRevision?` (revision ${this.chipRevision})`:"";this.logger.log(`Connected to ${this.chipName}${i}`),this.logger.debug(`Bootloader flash offset: 0x${t.flashOffs.toString(16)}`),this._initializationSucceeded=!0}async detectChip(){try{const t=(await this.getSecurityInfo()).chipId,e=z[t];if(e)return this.chipName=e.name,this.chipFamily=e.family,this.chipRevision=await this.getChipRevision(),this.logger.debug(`${this.chipName} revision: ${this.chipRevision}`),this.chipFamily===T&&this.chipRevision>=300?this.chipVariant="rev300":this.chipFamily===T&&(this.chipVariant="rev0"),void this.logger.debug(`Detected chip via IMAGE_CHIP_ID: ${t} (${this.chipName})`);this.logger.debug(`Unknown IMAGE_CHIP_ID: ${t}, falling back to magic value detection`)}catch(t){this.logger.debug(`GET_SECURITY_INFO failed, using magic value detection: ${t}`),await this.drainInputBuffer(200),this._clearInputBuffer(),await r(gt);try{await this.sync()}catch(t){this.logger.debug(`Re-sync after GET_SECURITY_INFO failure: ${t}`)}}const t=await this.readRegister(1073745920),e=P[t>>>0];if(void 0===e)throw new Error(`Unknown Chip: Hex: ${s(t>>>0,8).toLowerCase()} Number: ${t}`);this.chipName=e.name,this.chipFamily=e.family,this.chipRevision=await this.getChipRevision(),this.logger.debug(`${this.chipName} revision: ${this.chipRevision}`),this.chipFamily===T&&(this.chipVariant=this.chipRevision>=300?"rev300":"rev0",this.logger.debug(`ESP32-P4 variant: ${this.chipVariant}`)),this.logger.debug(`Detected chip via magic value: ${s(t>>>0,8)} (${this.chipName})`)}async getChipRevision(){var t;let e=0,i=0;switch(this.chipFamily){case v:{const s=await this.readRegister(1073061900),a=await this.readRegister(1073061908);e=a>>24&3;const r=s>>15&1,n=a>>20&1;i=null!==(t={0:0,1:1,3:2,7:3}[(await this.readRegister(1073111164)>>31&1)<<2|n<<1|r])&&void 0!==t?t:0;break}case C:{const t=await this.readRegister(1061265488);e=((t>>20&1)<<3)+(await this.readRegister(1061265492)>>4&7),i=t>>18&3;break}case E:{const t=await this.readRegister(1610641488),s=await this.readRegister(1610641496);e=((s>>23&1)<<3)+(t>>18&7),i=s>>24&3;break}case k:{const t=await this.readRegister(1610647620);e=t>>16&15,i=t>>20&3;break}case x:{const t=await this.readRegister(1610647632),s=await this.readRegister(1610647640);e=((s>>23&1)<<3)+(t>>18&7),i=s>>24&3;break}case U:{const t=await this.readRegister(1611352140);e=15&t,i=t>>4&3;break}case M:{const t=await this.readRegister(1611335760);e=t>>18&15,i=t>>22&3;break}case D:{const t=await this.readRegister(1611352140);e=15&t,i=t>>4&3;break}case O:{const t=await this.readRegister(1611335760);e=t>>18&7,i=t>>21&3;break}case A:case F:break;case T:{const t=await this.readRegister(1343410252);e=15&t,i=(t>>23&1)<<2|t>>4&3;break}case L:{const t=await this.readRegister(544297036);e=15&t,i=t>>4&3;break}}return 100*i+e}async powerOnFlash(){if(this.chipFamily!==T)return;if(301!==this.chipRevision)return;this.logger.debug("Powering on flash for ESP32-P4 Rev 301 (ECO6)"),await this.writeRegister(1343291660,1),await r(10);const t=await this.readRegister(w);await this.writeRegister(w,t|m);const e=await this.readRegister(y);await this.writeRegister(y,128|e);const i=await this.readRegister(S);await this.writeRegister(S,3|i),await r(.05);const s=await this.readRegister(w);await this.writeRegister(w,-134217729&s);const a=await this.readRegister(y);await this.writeRegister(y,-2139095041&a);const n=await this.readRegister(y);await this.writeRegister(y,128|n);const o=await this.readRegister(y);await this.writeRegister(y,-129&o),await r(2),this.logger.debug("Flash powered on successfully")}async getSecurityInfo(){const[,t]=await this.checkCommand(20,[],0);if(0===t.length)throw new Error("GET_SECURITY_INFO not supported or returned empty response");if(t.length<12)throw new Error(`Invalid security info response length: ${t.length} (expected at least 12 bytes)`);return{flags:Di("=16?Di("=20?Di("t.toString(16).padStart(2,"0").toUpperCase()).join(":")}async readLoop(){this.debug&&this.logger.debug("Starting read loop"),this._reader=this.port.readable.getReader();try{let t=!0;for(;t;){const{value:e,done:i}=await this._reader.read();if(i){this._reader.releaseLock(),t=!1;break}if(!e||0===e.length)continue;const s=Array.from(e);Array.prototype.push.apply(this._inputBuffer,s),this._totalBytesRead+=e.length}}catch{}finally{if(this._isReconfiguring=!1,this._reader){try{this._reader.releaseLock(),this.logger.debug("Reader released in readLoop cleanup")}catch(t){this.logger.debug(`Reader release error in readLoop: ${t}`)}this._reader=void 0}}this.connected=!1,this._isESP32S2NativeUSB&&!this._initializationSucceeded&&(this.logger.log("ESP32-S2 Native USB detected - requesting port reselection"),this.dispatchEvent(new CustomEvent("esp32s2-usb-reconnect",{detail:{message:"ESP32-S2 Native USB requires port reselection"}}))),this._suppressDisconnect||this.dispatchEvent(new Event("disconnect")),this._suppressDisconnect=!1,this.logger.debug("Finished read loop")}async setRTS(t){await this.port.setSignals({requestToSend:t}),await this.setDTR(this.state_DTR)}async setDTR(t){this.state_DTR=t,await this.port.setSignals({dataTerminalReady:t})}async setDTRandRTS(t,e){this.state_DTR=t,this.state_RTS=e,await this.port.setSignals({dataTerminalReady:t,requestToSend:e})}async runSignalSequence(t){const e=!0===this.port.isWebUSB;for(const i of t)void 0!==i.dtr&&void 0!==i.rts?e?await this.setDTRandRTSWebUSB(i.dtr,i.rts):await this.setDTRandRTS(i.dtr,i.rts):(void 0!==i.dtr&&(e?await this.setDTRWebUSB(i.dtr):await this.setDTR(i.dtr)),void 0!==i.rts&&(e?await this.setRTSWebUSB(i.rts):await this.setRTS(i.rts))),i.delayMs&&await r(i.delayMs)}async hardResetUSBJTAGSerial(){await this.runSignalSequence([{rts:!1},{dtr:!1,delayMs:100},{dtr:!0,rts:!1,delayMs:100},{rts:!0},{dtr:!1,rts:!0,delayMs:100},{dtr:!1,rts:!1,delayMs:200}])}async hardResetClassic(){await this.runSignalSequence([{dtr:!1,rts:!0,delayMs:100},{dtr:!0,rts:!1,delayMs:50},{dtr:!1,delayMs:200}])}async hardResetToFirmware(){await this.runSignalSequence([{dtr:!1,rts:!0,delayMs:100},{rts:!1,delayMs:50},{delayMs:200}])}async hardResetUnixTight(){await this.runSignalSequence([{dtr:!0,rts:!0},{dtr:!1,rts:!1},{dtr:!1,rts:!0,delayMs:100},{dtr:!0,rts:!1,delayMs:50},{dtr:!1,rts:!1},{dtr:!1,delayMs:200}])}async setRTSWebUSB(t){this.state_RTS=t,await this.port.setSignals({requestToSend:t,dataTerminalReady:this.state_DTR})}async setDTRWebUSB(t){this.state_DTR=t,await this.port.setSignals({dataTerminalReady:t,requestToSend:this.state_RTS})}async setDTRandRTSWebUSB(t,e){this.state_DTR=t,this.state_RTS=e,await this.port.setSignals({dataTerminalReady:t,requestToSend:e})}async hardResetUSBJTAGSerialInvertedDTRWebUSB(){await this.runSignalSequence([{rts:!1,dtr:!0,delayMs:100},{dtr:!1,rts:!1,delayMs:100},{rts:!0,dtr:!0,delayMs:100},{dtr:!0,rts:!1,delayMs:200}])}async hardResetClassicLongDelayWebUSB(){await this.runSignalSequence([{dtr:!1,rts:!0,delayMs:500},{dtr:!0,rts:!1,delayMs:200},{dtr:!1,delayMs:500}])}async hardResetClassicShortDelayWebUSB(){await this.runSignalSequence([{dtr:!1,rts:!0,delayMs:50},{dtr:!0,rts:!1,delayMs:25},{dtr:!1,delayMs:100}])}async hardResetInvertedWebUSB(){await this.runSignalSequence([{dtr:!0,rts:!1,delayMs:100},{dtr:!1,rts:!0,delayMs:50},{dtr:!0,delayMs:200}])}async hardResetInvertedDTRWebUSB(){await this.runSignalSequence([{dtr:!0,rts:!0,delayMs:100},{dtr:!1,rts:!1,delayMs:50},{dtr:!0,delayMs:200}])}async hardResetInvertedRTSWebUSB(){await this.runSignalSequence([{dtr:!1,rts:!1,delayMs:100},{dtr:!0,rts:!0,delayMs:50},{dtr:!1,delayMs:200}])}isWebUSB(){return!0===this.port.isWebUSB}async connectWithResetStrategies(){const t=this.port.getInfo(),e=4097===t.usbProductId,i=12346===t.usbVendorId,s=[],a=this,n=!e&&!i;if(this.isWebUSB()){const r=4292===t.usbVendorId,o=6790===t.usbVendorId,h=12346===t.usbVendorId&&2===t.usbProductId;(e||i)&&(h?(s.push({name:"USB-JTAG/Serial (WebUSB) - ESP32-S2",fn:async()=>await a.hardResetUSBJTAGSerial()}),s.push({name:"USB-JTAG/Serial Inverted DTR (WebUSB) - ESP32-S2",fn:async()=>await a.hardResetUSBJTAGSerialInvertedDTRWebUSB()}),s.push({name:"UnixTight (WebUSB) - ESP32-S2 CDC",fn:async()=>await a.hardResetUnixTight()}),s.push({name:"Classic (WebUSB) - ESP32-S2 CDC",fn:async()=>await a.hardResetClassic()})):(s.push({name:"USB-JTAG/Serial Inverted DTR (WebUSB)",fn:async()=>await a.hardResetUSBJTAGSerialInvertedDTRWebUSB()}),s.push({name:"USB-JTAG/Serial (WebUSB)",fn:async()=>await a.hardResetUSBJTAGSerial()}),s.push({name:"Inverted DTR Classic (WebUSB)",fn:async()=>await a.hardResetInvertedDTRWebUSB()}))),n&&(o?(s.push({name:"UnixTight (WebUSB) - CH34x",fn:async()=>await a.hardResetUnixTight()}),s.push({name:"Classic (WebUSB) - CH34x",fn:async()=>await a.hardResetClassic()}),s.push({name:"Inverted Both (WebUSB) - CH34x",fn:async()=>await a.hardResetInvertedWebUSB()}),s.push({name:"Inverted RTS (WebUSB) - CH34x",fn:async()=>await a.hardResetInvertedRTSWebUSB()}),s.push({name:"Inverted DTR (WebUSB) - CH34x",fn:async()=>await a.hardResetInvertedDTRWebUSB()})):r?(s.push({name:"UnixTight (WebUSB) - CP2102",fn:async()=>await a.hardResetUnixTight()}),s.push({name:"Classic (WebUSB) - CP2102",fn:async()=>await a.hardResetClassic()}),s.push({name:"Inverted Both (WebUSB) - CP2102",fn:async()=>await a.hardResetInvertedWebUSB()}),s.push({name:"Inverted RTS (WebUSB) - CP2102",fn:async()=>await a.hardResetInvertedRTSWebUSB()}),s.push({name:"Inverted DTR (WebUSB) - CP2102",fn:async()=>await a.hardResetInvertedDTRWebUSB()})):(s.push({name:"UnixTight (WebUSB)",fn:async()=>await a.hardResetUnixTight()}),s.push({name:"Classic (WebUSB)",fn:async function(){return await a.hardResetClassic()}}),s.push({name:"Inverted Both (WebUSB)",fn:async function(){return await a.hardResetInvertedWebUSB()}}),s.push({name:"Inverted RTS (WebUSB)",fn:async function(){return await a.hardResetInvertedRTSWebUSB()}}),s.push({name:"Inverted DTR (WebUSB)",fn:async function(){return await a.hardResetInvertedDTRWebUSB()}}))),n||r||h||e||(6790!==t.usbVendorId&&s.push({name:"Classic (WebUSB)",fn:async function(){return await a.hardResetClassic()}}),s.push({name:"UnixTight (WebUSB)",fn:async function(){return await a.hardResetUnixTight()}}),s.push({name:"Classic Long Delay (WebUSB)",fn:async function(){return await a.hardResetClassicLongDelayWebUSB()}}),s.push({name:"Classic Short Delay (WebUSB)",fn:async function(){return await a.hardResetClassicShortDelayWebUSB()}}),i||s.push({name:"USB-JTAG/Serial fallback (WebUSB)",fn:async function(){return await a.hardResetUSBJTAGSerial()}}))}else(e||i)&&s.push({name:"USB-JTAG/Serial",fn:async function(){return await a.hardResetUSBJTAGSerial()}}),s.push({name:"UnixTight",fn:async function(){return await a.hardResetUnixTight()}}),e||i||s.push({name:"USB-JTAG/Serial (fallback)",fn:async function(){return await a.hardResetUSBJTAGSerial()}});let o=null;for(const t of s)try{if(!this.connected||!this.port.writable){this.logger.debug(`Port disconnected, skipping ${t.name} reset`);continue}if(this._abandonCurrentOperation=!1,await t.fn(),n){if(await this.syncWithTimeout(2e3))return void this.logger.log(`Connected USB Serial successfully with ${t.name} reset.`);throw new Error("Sync timeout or abandoned")}{const e=this.sync(),i=new Promise((t,e)=>setTimeout(()=>e(new Error("Sync timeout")),1e3));try{return await Promise.race([e,i]),void this.logger.debug(`Connected CDC/JTAG successfully with ${t.name} reset.`)}catch(t){throw new Error("Sync timeout or abandoned")}}}catch(t){if(o=t,this._abandonCurrentOperation=!0,await r(100),!this.connected||!this.port.writable){this.logger.log("Port disconnected during reset attempt");break}this._clearInputBuffer(),await this.drainInputBuffer(200),await this.flushSerialBuffers()}throw this._abandonCurrentOperation=!1,new Error(`Couldn't sync to ESP. Try resetting manually. Last error: ${null==o?void 0:o.message}`)}async watchdogReset(){await this.rtcWdtResetChipSpecific()}async rtcWdtResetChipSpecific(){let t,e,i,s;if(this.logger.debug("Hard resetting with watchdog timer..."),this.chipFamily===C)t=1061191852,e=1061191828,i=1061191832,s=1356348065;else if(this.chipFamily===E)t=1610645680,e=1610645656,i=1610645660,s=1356348065;else if(this.chipFamily===x)t=1610645672,e=1610645648,i=1610645652,s=1356348065;else if(this.chipFamily===U||this.chipFamily===M)t=1611340824,e=1611340800,i=1611340804,s=1356348065;else{if(this.chipFamily!==T)throw new Error(`rtcWdtResetChipSpecific() is not supported for ${this.chipFamily}`);t=1343315992,e=1343315968,i=1343315972,s=1356348065}await this.writeRegister(t,s,void 0,0),await this.writeRegister(i,2e3,void 0,0);await this.writeRegister(e,-805306110,void 0,0),await this.writeRegister(t,0,void 0,0),await r(500)}async resetToFirmwareMode(t=!0){this.logger.debug("Resetting from bootloader to firmware mode...");try{if(await this.detectUsbConnectionType()){let e;this.logger.debug("USB-JTAG/OTG detected - checking WDT reset support");try{e=await this.getUsbMode(),this.logger.debug(`USB mode: ${e.mode} (uartNo=${e.uartNo})`)}catch(t){this.logger.debug(`Could not get USB mode: ${t}`),e={mode:"usb-jtag-serial",uartNo:0}}if(!(this.chipFamily===C||this.chipFamily===E||this.chipFamily===T))return this.logger.debug(`${this.chipName} does not support WDT reset - using classic reset instead`),await this.hardResetToFirmware(),this.logger.debug("Classic reset to firmware complete"),!1;if(this.logger.debug(`${this.chipName} supports WDT reset - using WDT reset strategy`),this.IS_STUB){this.logger.debug("On stub - returning to ROM before WDT reset"),this.currentBaudRate!==h&&(this.logger.debug(`Changing baudrate from ${this.currentBaudRate} to 115200`),await this.reconfigurePort(h),this.currentBaudRate=h,this.logger.debug("Baudrate changed to 115200"));const t=this._consoleMode;this._consoleMode=!1,await this.hardReset(!0),await r(200),this._consoleMode=t,await this.sync(),this.IS_STUB=!1,this.logger.debug("Now on ROM")}else this.currentBaudRate!==h&&(this.logger.debug(`Not on stub, but baudrate is ${this.currentBaudRate} - changing to 115200 for WDT reset`),await this.reconfigurePort(h),this.currentBaudRate=h,this.logger.debug("Baudrate changed to 115200"));if(t&&"usb-otg"===e.mode){await this._clearForceDownloadBootIfNeeded()&&this.logger.debug("Force download boot flag cleared")}await this.rtcWdtResetChipSpecific(),this.logger.debug("WDT reset performed - device will boot to firmware");return!!("usb-otg"===e.mode||"usb-jtag-serial"===e.mode)&&(this.logger.debug(`Port will change after WDT reset (${e.mode}) - port reselection needed`),!0)}return this.logger.debug("External serial chip detected - using classic reset"),await this.hardResetToFirmware(),this.logger.debug("Classic reset to firmware complete"),!1}catch(t){throw this.logger.error(`Failed to reset to firmware mode: ${t}`),t}}async hardReset(t=!1){if(this._consoleMode)return t?void this.logger.debug("Skipping bootloader reset - device is in console mode"):(this.logger.debug("Performing hardware reset (console mode)..."),await this.resetInConsoleMode(),void this.logger.debug("Hardware reset complete"));if(t)4097===this.port.getInfo().usbProductId?(await this.hardResetUSBJTAGSerial(),this.logger.debug("USB-JTAG/Serial reset to bootloader.")):(await this.hardResetClassic(),this.logger.debug("Classic reset to bootloader."));else{this.logger.debug("Resetting to firmware mode...");if(await this.detectUsbConnectionType()){let t;this.logger.debug("USB-JTAG/OTG detected - using WDT reset");try{t=await this.getUsbMode(),this.logger.debug(`USB mode: ${t.mode} (uartNo=${t.uartNo})`)}catch(e){this.logger.debug(`Could not get USB mode: ${e}`),t={mode:"usb-jtag-serial",uartNo:0}}if("usb-otg"===t.mode)try{await this._clearForceDownloadBootIfNeeded()&&this.logger.debug("Force download boot flag cleared")}catch(t){this.logger.debug(`Could not clear force download flag: ${t}`)}return await this.rtcWdtResetChipSpecific(),void this.logger.debug(`${this.chipName}: WDT reset to firmware complete`)}this.logger.debug("External serial chip detected - using classic reset"),this.isWebUSB()?(await this.setRTSWebUSB(!0),await r(200),await this.setRTSWebUSB(!1),await r(200),this.logger.debug("Hard reset to firmware (WebUSB).")):(await this.setRTS(!0),await r(100),await this.setRTS(!1),this.logger.debug("Hard reset to firmware."))}await new Promise(t=>setTimeout(t,1e3))}macAddr(){const t=new Array(6).fill(0),e=this._efuses[0],i=this._efuses[1],s=this._efuses[2],a=this._efuses[3];let r;if(this.chipFamily==R){if(0!=a)r=[a>>16&255,a>>8&255,255&a];else if(i>>16&255){if(1!=(i>>16&255))throw new Error("Couldnt determine OUI");r=[172,208,116]}else r=[24,254,52];t[0]=r[0],t[1]=r[1],t[2]=r[2],t[3]=i>>8&255,t[4]=255&i,t[5]=e>>24&255}else if(this.chipFamily==v)t[0]=s>>8&255,t[1]=255&s,t[2]=i>>24&255,t[3]=i>>16&255,t[4]=i>>8&255,t[5]=255&i;else{if(this.chipFamily!=C&&this.chipFamily!=E&&this.chipFamily!=k&&this.chipFamily!=x&&this.chipFamily!=U&&this.chipFamily!=M&&this.chipFamily!=D&&this.chipFamily!=O&&this.chipFamily!=A&&this.chipFamily!=F&&this.chipFamily!=T&&this.chipFamily!=L)throw new Error("Unknown chip family");t[0]=i>>8&255,t[1]=255&i,t[2]=e>>24&255,t[3]=e>>16&255,t[4]=e>>8&255,t[5]=255&e}return t}async readRegister(t){this.debug&&this.logger.debug("Reading from Register "+s(t,8));const e=Mi("{a=Math.min(a,ut),await this.sendCommand(t,e,i);const[r,n]=await this.getResponse(t,a);if(null===n)throw new Error("Didn't get enough status bytes");let o=n,h=0;if(this.IS_STUB||this.chipFamily==R?h=2:[v,C,E,k,x,U,M,D,O,A,F,T,L].includes(this.chipFamily)||20===t?h=4:[2,4].includes(o.length)?h=o.length:(h=2,this.logger.debug(`Unknown chip family, defaulting to 2-byte status (opcode: ${s(t)}, data.length: ${o.length})`)),o.lengtht){throw new mt("Timed out waiting for packet "+(null===e?"header":"content"))}if(0!==this._inputBufferAvailable)for(;this._inputBufferAvailable>0;){if(Date.now()-n>t){throw new mt("Timed out waiting for packet "+(null===e?"header":"content"))}const r=this._readByte();if(null===e){if(r!=this.SLIP_END)throw this.debug&&(this.logger.debug("Read invalid data: "+s(r)),this.logger.debug("Remaining data in serial buffer: "+i(this._inputBuffer))),new mt("Invalid head of packet ("+s(r)+")");e=[]}else if(a)if(a=!1,r==this.SLIP_ESC_END)e.push(this.SLIP_END);else{if(r!=this.SLIP_ESC_ESC)throw this.debug&&(this.logger.debug("Read invalid data: "+s(r)),this.logger.debug("Remaining data in serial buffer: "+i(this._inputBuffer))),new mt("Invalid SLIP escape (0xdb, "+s(r)+")");e.push(this.SLIP_ESC)}else if(r==this.SLIP_ESC)a=!0;else{if(r==this.SLIP_END)return this.debug&&this.logger.debug("Received full packet: "+i(e)),this._compactInputBuffer(),e;e.push(r)}}else await r(1)}}else{let n=[];for(;;){if(this._abandonCurrentOperation)throw new mt("Operation abandoned (reset strategy timeout)");const o=Date.now();for(n=[];Date.now()-o0){n.push(this._readByte());break}await r(1)}if(0==n.length){throw new mt("Timed out waiting for packet "+(null===e?"header":"content"))}this.debug&&this.logger.debug("Read "+n.length+" bytes: "+i(n));for(const t of n)if(null===e){if(t!=this.SLIP_END)throw this.debug&&(this.logger.debug("Read invalid data: "+s(t)),this.logger.debug("Remaining data in serial buffer: "+i(this._inputBuffer))),new mt("Invalid head of packet ("+s(t)+")");e=[]}else if(a)if(a=!1,t==this.SLIP_ESC_END)e.push(this.SLIP_END);else{if(t!=this.SLIP_ESC_ESC)throw this.debug&&(this.logger.debug("Read invalid data: "+s(t)),this.logger.debug("Remaining data in serial buffer: "+i(this._inputBuffer))),new mt("Invalid SLIP escape (0xdb, "+s(t)+")");e.push(this.SLIP_ESC)}else if(t==this.SLIP_ESC)a=!0;else{if(t==this.SLIP_END)return this.debug&&this.logger.debug("Received full packet: "+i(e)),this._compactInputBuffer(),e;e.push(t)}}}}async getResponse(t,e=3e3){for(let i=0;i<100;i++){const i=await this.readPacket(e);if(i.length<8)continue;const[a,r,,n]=Di(">>24}async getC5CrystalFreqDetected(){const t=1048575&await this.readRegister(1610612756),e=h*t/1e6;return e>45?48:e>33?40:26}async setBaudrate(t){const e=this._parent?this._parent.chipFamily:this.chipFamily;if(this.IS_STUB||e!==U)try{const e=Mi("i&&(this.logger.log(`⚠️ WARNING: Baudrate ${t} exceeds USB-Serial chip limit (${i})!`),this.logger.log("⚠️ This may cause data corruption or connection failures!")),this.logger.debug(`Changed baud rate to ${t}`)}async setBaudrateC5Rom(t){const e=await this.getC5CrystalFreqRomExpect(),i=await this.getC5CrystalFreqDetected();this.logger.log(`ROM expects crystal freq: ${e} MHz, detected ${i} MHz.`);let s=t;48===i&&40===e?s=Math.trunc(40*t/48):40===i&&48===e&&(s=Math.trunc(48*t/40)),this.logger.log(`Changing baud rate to ${s}...`);try{const t=Mi("t)return!1;if(this._abandonCurrentOperation)return!1;this._clearInputBuffer();try{if(await this._sync())return await r(gt),!0}catch(t){if(this._abandonCurrentOperation)return!1}await r(gt)}return!1}async sync(){for(let t=0;t<5;t++){this._clearInputBuffer();if(await this._sync())return await r(gt),!0;await r(gt)}throw new Error("Couldn't sync to ESP. Try resetting.")}async _sync(){await this.sendCommand(8,I);for(let t=0;t<8;t++)try{const[,t]=await this.getResponse(8,gt);if(t.length>1&&0==t[0]&&0==t[1])return!0}catch(e){this.debug&&this.logger.debug(`Sync attempt ${t+1} failed: ${e}`)}return!1}getFlashWriteSize(){return this.IS_STUB?16384:1024}async flashData(t,e,i=0,a=!1){if(t.byteLength>=8){const e=Array.from(new Uint8Array(t,0,4)),i=e[0],a=e[2],r=e[3];this.logger.log(`Image header, Magic=${s(i)}, FlashMode=${s(a)}, FlashSizeFreq=${s(r)}`)}const r=(t=function(t,e,i=255){const s=t.length%e;if(0!==s){const a=new Uint8Array(e-s).fill(i),r=new Uint8Array(t.length+a.length);return r.set(t),r.set(a,t.length),r}return t}(new Uint8Array(t),4).buffer).byteLength;let n,o=0,h=dt;a?(n=xi(new Uint8Array(t),{level:9}).buffer,o=n.byteLength,this.logger.log(`Writing data with filesize: ${r}. Compressed Size: ${o}`),h=await this.flashDeflBegin(r,o,i)):(this.logger.log(`Writing data with filesize: ${r}`),n=t,await this.flashBegin(r,i));let l=[],d=0,c=0,u=0;const g=Date.now(),f=this.getFlashWriteSize(),_=a?o:r;for(;_-u>0;)this.debug&&this.logger.log(`Writing at ${s(i+d*f,8)} `),_-u>=f?l=Array.from(new Uint8Array(n,u,f)):(l=Array.from(new Uint8Array(n,u,_-u)),a||(l=l.concat(new Array(f-l.length).fill(255)))),a?await this.flashDeflBlock(l,d,h):await this.flashBlock(l,d),d+=1,c+=a?Math.round(l.length*r/o):l.length,u+=f,e(Math.min(c,r),r);this.logger.log("Took "+(Date.now()-g)+"ms to write "+_+" bytes"),this.IS_STUB&&(await this.flashBegin(0,0),a?await this.flashDeflFinish():await this.flashFinish())}async flashBlock(t,e,i=3e3){await this.checkCommand(3,Mi("0&&(r=r.concat(Mi("0&&await this.writeRegister(s,e-1),i>0&&await this.writeRegister(a,i-1)}else{const s=t.regBase+t.usr1Offs,a=(0==i?0:i-1)<<8|(0==e?0:e-1)<<17;await this.writeRegister(s,a)}}async waitDone(t,e){for(let i=0;i<10;i++){if(0==(await this.readRegister(t)&e))return}throw Error("SPI command did not complete in time")}async runSpiFlashCommand(t,e,i=0){const a=wt(this.getChipFamily()),r=a.regBase,n=r,o=r+a.usrOffs,h=r+a.usr2Offs,l=r+a.w0Offs,d=1<<18;if(i>32)throw new Error("Reading more than 32 bits back from a SPI flash operation is unsupported");if(e.length>64)throw new Error("Writing more than 64 bytes of data with one SPI command is unsupported");const c=8*e.length,u=await this.readRegister(o),g=await this.readRegister(h);let f=1<<31;if(i>0&&(f|=268435456),c>0&&(f|=134217728),await this.setDataLengths(a,c,i),await this.writeRegister(o,f),await this.writeRegister(h,7<<28|t),0==c)await this.writeRegister(l,0);else{const t=(4-e.length%4)%4;e=e.concat(new Array(t).fill(0));const i=Di("I".repeat(Math.floor(e.length/4)),e);let a=l;this.logger.debug(`Words Length: ${i.length}`);for(const t of i)this.logger.debug(`Writing word ${s(t)} to register offset ${s(a)}`),await this.writeRegister(a,t),a+=4}await this.writeRegister(n,d),await this.waitDone(n,d);const _=await this.readRegister(l);return await this.writeRegister(o,u),await this.writeRegister(h,g),_}async detectFlashSize(){this.logger.debug("Detecting Flash Size");const t=await this.flashId(),e=255&t,i=t>>16&255,s=(t>>8&255)<<8|i,a=St[e],r=Bt[e<<16|s];this.logger.log(`Flash Manufacturer: ${a||"Unknown"} (0x${e.toString(16)})`),this.logger.log(`Flash Device: ${r||`Unknown (0x${s.toString(16)})`}`),this.flashSize=n[i],this.logger.log(`Auto-detected Flash size: ${this.flashSize}`)}getEraseSize(t,e){const i=o,s=Math.floor((e+i-1)/i);let a=16-Math.floor(t/i)%16;return sr&&(a=r),await this.memBlock(s.slice(e,a),t)}}await this.memFinish(e.entry);const s=await this.readPacket(500),a=String.fromCharCode(...s);if("OHAI"!=a)throw new Error("Failed to start stub. Unexpected response: "+a);this.logger.debug("Stub is now running...");const r=new Ai(this.port,this.logger,this);return t||await r.detectFlashSize(),r}get _writer(){return this._parent?this._parent._writer:this.__writer}set _writer(t){this._parent?this._parent._writer=t:this.__writer=t}get _writeChain(){return this._parent?this._parent._writeChain:this.__writeChain}set _writeChain(t){this._parent?this._parent._writeChain=t:this.__writeChain=t}async writeToStream(t){if(this.port.writable){if(this._isReconfiguring)throw new Error("Cannot write during port reconfiguration");this._writeChain=this._writeChain.then(async()=>{if(!this.port.writable)throw new Error("Port became unavailable during write");if(!this._writer)try{this._writer=this.port.writable.getWriter()}catch(t){throw this.logger.error(`Failed to get writer: ${t}`),t}await this._writer.write(new Uint8Array(t))},async()=>{if(this.logger.debug("Previous write failed, attempting recovery for current write"),!this.port.writable)throw new Error("Port became unavailable during write");if(!this._writer)try{this._writer=this.port.writable.getWriter()}catch(t){throw this.logger.debug(`Failed to get writer in recovery: ${t}`),new Error("Cannot acquire writer lock")}await this._writer.write(new Uint8Array(t))}).catch(t=>{if(this.logger.error(`Write error: ${t}`),this._writer){try{this._writer.releaseLock()}catch{}this._writer=void 0}throw t}),await this._writeChain}else this.logger.debug("Port writable stream not available, skipping write")}async disconnect(){if(this._parent)await this._parent.disconnect();else if(this.port.writable){try{await this._writeChain}catch(t){}if(this._writer){try{await this._writer.close(),this._writer.releaseLock()}catch(t){}this._writer=void 0}else try{const t=this.port.writable.getWriter();await t.close(),t.releaseLock()}catch(t){}await new Promise(t=>{if(!this._reader)return void t(void 0);const e=setTimeout(()=>{this.logger.debug("Disconnect timeout - forcing resolution"),t(void 0)},1e3);this.addEventListener("disconnect",()=>{clearTimeout(e),t(void 0)},{once:!0});try{this._reader.cancel()}catch(i){clearTimeout(e),t(void 0)}}),this.connected=!1;try{await this.port.close(),this.logger.debug("Port closed successfully")}catch(t){this.logger.debug(`Port close error: ${t}`)}}}async releaseReaderWriter(){if(this._parent)await this._parent.releaseReaderWriter();else{try{await this._writeChain}catch(t){}if(this._writer){try{this._writer.releaseLock(),this.logger.debug("Writer released")}catch(t){this.logger.debug(`Writer release error: ${t}`)}this._writer=void 0}if(this._reader)try{this._suppressDisconnect=!0,await this._reader.cancel(),this.logger.debug("Reader cancelled - waiting for readLoop to finish"),await r(50),this.logger.debug("ReadLoop cleanup should be complete")}catch(t){this.logger.debug(`Reader cancel error: ${t}`)}}}async resetToFirmware(){return await this._resetToFirmwareIfNeeded()}async detectUsbConnectionType(){const t=this.port.getInfo(),e=t.usbProductId;if(!(12346===t.usbVendorId))return this.logger.debug("Not Espressif VID - external serial chip"),!1;const i=[2,18,4097].includes(e||0);return this.logger.debug(`USB-JTAG/OTG detection: ${i?"YES":"NO"} (PID=0x${null==e?void 0:e.toString(16)})`),i}async getUsbMode(){var t,e;const i=this._parent?this._parent.chipFamily:this.chipFamily,s=this._parent?null!==(t=this._parent.chipRevision)&&void 0!==t?t:0:null!==(e=this.chipRevision)&&void 0!==e?e:0;let a=null,r=null,n=null;switch(i){case C:a=1073741076,n=2;break;case E:a=1070526796,r=4,n=3;break;case x:a=(s<101?1070461028:1070461024)+24,r=3;break;case U:a=1082520852,r=3;break;case M:a=1082652032,r=3;break;case D:a=s<=200?1082455532:1082455524,r=s<=200?3:4;break;case O:a=1082457852,r=3;break;case A:a=1082652032,r=3;break;case T:a=s<300?1341390536:1341914824,r=6,n=5}if(null===a)return{mode:"uart",uartNo:0};const o=255&await this.readRegister(a);return null!==n&&o===n?(this.logger.debug(`USB mode: USB-OTG (uartNo=${o})`),{mode:"usb-otg",uartNo:o}):null!==r&&o===r?(this.logger.debug(`USB mode: USB-JTAG/Serial (uartNo=${o})`),{mode:"usb-jtag-serial",uartNo:o}):(this.logger.debug(`USB mode: UART (uartNo=${o})`),{mode:"uart",uartNo:o})}supportsNativeUsb(){const t=this._parent?this._parent.chipFamily:this.chipFamily;return[C,E,x,U,M,D,O,A,T].includes(t)}async _ensureStreamsReady(){if(this.isWebUSB())try{await this.port.recreateStreams(),this.logger.debug("WebUSB streams recreated");let t=30;for(;t>0&&!this.port.readable;)await r(100),t--;if(!this.port.readable)throw new Error("Readable stream not available after recreating streams");this.logger.debug("WebUSB streams are ready")}catch(t){throw this.logger.error(`Failed to recreate WebUSB streams: ${t}`),this._consoleMode=!1,t}else{let t=20;for(;t>0&&!this.port.readable;)await r(100),t--;if(!this.port.readable)throw this._consoleMode=!1,new Error("Readable stream not available after reset");this.logger.debug("Port streams are ready")}}async enterConsoleMode(){if(!this.port.writable||!this.port.readable)return this.logger.debug("Port is not open - port selection needed"),!0;let t;try{t=await this.detectUsbConnectionType(),this.logger.debug("USB connection type detected: "+(t?"USB-JTAG/OTG":"External Serial Chip")),this._isUsbJtagOrOtg=t}catch(e){if(void 0===this.isUsbJtagOrOtg)throw new Error(`Cannot enter console mode: USB connection type unknown and detection failed: ${e}`);this.logger.debug(`USB detection failed, using cached value: ${this.isUsbJtagOrOtg}`),t=this.isUsbJtagOrOtg}if(this._consoleMode=!0,t){return!!await this._resetToFirmwareIfNeeded()||(await this._ensureStreamsReady(),!1)}try{await this.releaseReaderWriter(),await r(100)}catch(t){this.logger.debug(`Failed to release locks: ${t}`)}try{await this.hardResetToFirmware(),this.logger.debug("Device reset to firmware mode")}catch(t){this.logger.debug(`Could not reset device: ${t}`)}return await this._ensureStreamsReady(),!1}async _clearForceDownloadBootIfNeeded(){try{let t,e,i;if(this.chipFamily===C)t=1061191976,e=1,i="ESP32-S2";else if(this.chipFamily===E)t=1610645804,e=1,i="ESP32-S3";else{if(this.chipFamily!==T)return!1;t=1343291400,e=4,i="ESP32-P4"}const s=await this.readRegister(t);this.logger.debug(`${i} force download boot register: 0x${s.toString(16)} (mask: 0x${e.toString(16)})`);return 0!==(s&e)?(this.logger.debug(`${i} force download boot flag is SET - clearing it`),await this.writeRegister(t,0,e,0),this.logger.debug(`${i} force download boot flag cleared`),!0):(this.logger.debug(`${i} force download boot flag is already CLEAR - no action needed`),!1)}catch(t){return this.logger.debug(`Error checking/clearing force download flag: ${t}`),!1}}async _resetToFirmwareIfNeeded(){const t=await this.detectUsbConnectionType();try{if(!this.port.writable||!this.port.readable)return this.logger.debug("Port is not open - assuming device is already in firmware mode"),!1;t?this.logger.debug("USB-JTAG/OTG: Keeping reader/writer active for WDT reset"):(await this.releaseReaderWriter(),this.logger.debug("External serial: Reader/writer released before reset"));return await this.resetToFirmwareMode(!0)?(this.logger.debug(`${this.chipName}: Port will change after WDT reset - user must reselect port`),this.dispatchEvent(new CustomEvent("usb-otg-port-change",{detail:{chipName:this.chipName,message:`${this.chipName} USB port changed after reset. Please select the new port.`,reason:"wdt-reset-to-firmware"}})),!0):(t&&(await this.releaseReaderWriter(),this.logger.debug("Reader/writer released after reset")),!1)}catch(e){return this.logger.error(`Reset to firmware mode failed: ${e}`),t?(this.logger.debug("Forcing port reselection due to USB-JTAG/OTG reset failure"),!0):(this.logger.debug("External serial reset failed, but port should still be usable"),!1)}}async reconnect(){if(this._parent)await this._parent.reconnect();else try{this.logger.log("Reconnecting serial port...");const t=this.currentBaudRate;this.connected=!1,this.__inputBuffer=[],this.__inputBufferReadIndex=0;try{await this._writeChain}catch(t){this.logger.debug(`Pending write error during reconnect: ${t}`)}if(this._isReconfiguring=!0,this._writer){try{this._writer.releaseLock()}catch(t){this.logger.debug(`Writer release error during reconnect: ${t}`)}this._writer=void 0}if(this._reader){try{await this._reader.cancel()}catch(t){this.logger.debug(`Reader cancel error: ${t}`)}this._reader=void 0}try{await this.port.close(),this.logger.debug("Port closed")}catch(t){this.logger.debug(`Port close error: ${t}`)}this.logger.debug("Opening port...");try{await this.port.open({baudRate:h}),this.connected=!0,this.currentBaudRate=h}catch(t){throw new Error(`Failed to open port: ${t}`)}if(!this.port.readable||!this.port.writable)throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);this._isReconfiguring=!1;const e=this.chipFamily,i=this.chipName,s=this.chipRevision,a=this.chipVariant,r=this.flashSize;if(await this.hardReset(!0),this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0,this.__totalBytesRead=0,this.readLoop()),await this.flushSerialBuffers(),await this.sync(),this.chipFamily=e,this.chipName=i,this.chipRevision=s,this.chipVariant=a,this.flashSize=r,this.logger.debug(`Reconnect complete (chip: ${this.chipName})`),!this.port.writable||!this.port.readable)throw new Error("Port not ready after reconnect");this.chipFamily===T&&301===this.chipRevision&&await this.powerOnFlash();const n=await this.runStub(!0);if(this.logger.debug("Stub loaded"),t!==h&&(await n.setBaudrate(t),!this.port.writable||!this.port.readable))throw new Error(`Port not ready after baudrate change (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);this.IS_STUB=!0,this.logger.debug("Reconnection successful")}catch(t){throw this._isReconfiguring=!1,t}}async reconnectToBootloader(){if(this._parent)await this._parent.reconnectToBootloader();else try{this.logger.log("Reconnecting to bootloader mode..."),this._consoleMode=!1,this.connected=!1,this.__inputBuffer=[],this.__inputBufferReadIndex=0;try{await this._writeChain}catch(t){this.logger.debug(`Pending write error during reconnect: ${t}`)}if(this._isReconfiguring=!0,this._writer){try{this._writer.releaseLock()}catch(t){this.logger.debug(`Writer release error during reconnect: ${t}`)}this._writer=void 0}if(this._reader){try{await this._reader.cancel()}catch(t){this.logger.debug(`Reader cancel error: ${t}`)}this._reader=void 0}try{await this.port.close(),this.logger.debug("Port closed")}catch(t){this.logger.debug(`Port close error: ${t}`)}this.logger.debug("Opening port...");try{await this.port.open({baudRate:h}),this.connected=!0,this.currentBaudRate=h}catch(t){throw new Error(`Failed to open port: ${t}`)}if(!this.port.readable||!this.port.writable)throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`);this._isReconfiguring=!1,this.__chipFamily=void 0,this.chipName="Unknown Chip",this.chipRevision=null,this.chipVariant=null,this.IS_STUB=!1,this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0,this.__totalBytesRead=0,this.readLoop()),await r(100),await this.connectWithResetStrategies(),await this.detectChip(),this.logger.debug(`Reconnected to bootloader: ${this.chipName}`)}catch(t){throw this._isReconfiguring=!1,t}}async exitConsoleMode(){if(this._parent)return await this._parent.exitConsoleMode();this._consoleMode=!1;const t=this.chipFamily===C||this.chipFamily===T;let e=this._isUsbJtagOrOtg;if(t&&void 0===e)try{e=await this.detectUsbConnectionType()}catch(t){this.logger.debug(`USB detection failed, assuming USB-JTAG/OTG for ${this.chipName}: ${t}`),e=!0}if(t&&e){this.logger.debug(`${this.chipName} USB: Resetting to bootloader mode`);try{await this.hardResetClassic(),this.logger.debug("Reset to bootloader initiated")}catch(t){this.logger.debug(`Reset error: ${t}`)}return await r(500),this.logger.debug(`${this.chipName}: Port changed. Please select the bootloader port.`),this.dispatchEvent(new CustomEvent("usb-otg-port-change",{detail:{chipName:this.chipName,message:`${this.chipName}: Port changed. Please select the bootloader port.`,reason:"exit-console-to-bootloader"}})),!0}return await this.reconnectToBootloader(),!1}isConsoleResetSupported(){if(this._parent)return this._parent.isConsoleResetSupported();return!(this.chipFamily===C&&(!0===this._isUsbJtagOrOtg||void 0===this._isUsbJtagOrOtg))}async resetInConsoleMode(){if(this._parent)return await this._parent.resetInConsoleMode();if(!this.isConsoleResetSupported())return this.logger.debug("Simple Console reset not supported for ESP32-S2 USB-JTAG/CDC - using exitConsoleMode to enter bootloader"),await this.exitConsoleMode(),void this.logger.debug("S2 now in bootloader mode - caller must do syncAndWdtReset on new port, then reconnect console");try{this.logger.debug("Resetting device in console mode"),await this.hardResetToFirmware(),this.logger.debug("Device reset complete")}catch(t){throw this.logger.error(`Reset failed: ${t}`),t}}async syncAndWdtReset(t){this._parent?await this._parent.syncAndWdtReset(t):(this.port=t,this.connected=!1,this.IS_STUB=!1,this.__inputBuffer=[],this.__inputBufferReadIndex=0,this.__totalBytesRead=0,this.logger.debug("Opening bootloader port at 115200..."),await this.port.open({baudRate:h}),this.connected=!0,this.currentBaudRate=h,this.readLoop(),await r(100),this.logger.debug("Syncing with bootloader ROM..."),await this.sync(),this.logger.debug("Bootloader sync OK, no stub"),this.logger.debug("Firing WDT reset..."),await this.rtcWdtResetChipSpecific(),this.logger.debug("WDT reset fired - device will boot to firmware"))}async drainInputBuffer(t=200){await r(t);let e=0;const i=Date.now();for(;e<112&&Date.now()-i<100;)if(this._inputBufferAvailable>0){void 0!==this._readByte()&&e++}else await r(1);e>0&&this.logger.debug(`Drained ${e} bytes from input buffer`),this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0)}async flushSerialBuffers(){this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0),await r(gt),this._parent||(this.__inputBuffer=[],this.__inputBufferReadIndex=0),this.logger.debug("Serial buffers flushed")}async readFlash(e,i,s,a){if(!this.IS_STUB)throw new Error("Reading flash is only supported in stub mode. Please run runStub() first.");await this.flushSerialBuffers();const n=Date.now();let o;this.logger.log(`Reading ${i} bytes from flash at address 0x${e.toString(16)}...`),this.isWebUSB()&&(this._isCDCDevice?(this._adaptiveBlockMultiplier=8,this._adaptiveMaxInFlightMultiplier=8,this._consecutiveSuccessfulChunks=0,this.logger.debug(`CDC device - Initialized: blockMultiplier=${this._adaptiveBlockMultiplier}, maxInFlightMultiplier=${this._adaptiveMaxInFlightMultiplier}`)):(this._adaptiveBlockMultiplier=1,this._adaptiveMaxInFlightMultiplier=1,this._consecutiveSuccessfulChunks=0,this.logger.debug("Non-CDC device - Fixed values: blockSize=31, maxInFlight=31"))),void 0!==(null==a?void 0:a.chunkSize)?(o=a.chunkSize,this.logger.log(`Using custom chunk size: 0x${o.toString(16)} bytes`)):o=this.isWebUSB()?16384:262144;let h=new Uint8Array(0),l=e,d=i;for(;d>0;){const e=Math.min(o,d);let n=!1,c=0;const u=5;let g=!1;for(;!n&&c<=u;){let i=new Uint8Array(0),s=0;try{let o,d;if(0===c&&this.logger.debug(`Reading chunk at 0x${l.toString(16)}, size: 0x${e.toString(16)}`),void 0!==(null==a?void 0:a.blockSize)&&void 0!==(null==a?void 0:a.maxInFlight))o=a.blockSize,d=a.maxInFlight,0===c&&this.logger.debug(`Using custom parameters: blockSize=${o}, maxInFlight=${d}`);else if(this.isWebUSB()){const t=this.port.maxTransferSize||64,e=Math.floor((t-2)/2);o=e*this._adaptiveBlockMultiplier,d=e*this._adaptiveMaxInFlightMultiplier}else{const t=63;o=65*t,d=130*t}const u=Mi("=e)break}throw t}if(a&&a.length>0){const r=new Uint8Array(a),n=new Uint8Array(i.length+r.length);n.set(i),n.set(r,i.length),i=n;if(i.length>=e||i.length>=s+d){const e=Mi("=2)){const t=this.port.maxTransferSize||64,e=Math.floor((t-2)/2),i=8,s=8;let a=!1;if(this._adaptiveBlockMultiplier1||this._adaptiveMaxInFlightMultiplier>1){this._adaptiveBlockMultiplier=1,this._adaptiveMaxInFlightMultiplier=1,this._consecutiveSuccessfulChunks=0;const t=this.port.maxTransferSize||64,e=Math.floor((t-2)/2),i=e*this._adaptiveBlockMultiplier,s=e*this._adaptiveMaxInFlightMultiplier;this.logger.debug(`Error at higher speed - reduced to minimum: blockSize=${i}, maxInFlight=${s}`)}else this.logger.debug("Error at minimum speed (blockSize=31, maxInFlight=31) - not a speed issue");if(!(t instanceof mt))throw t;if(c<=u)this.logger.debug(`Cleared buffer and retrying (attempt ${c}/${u})...`);else{if(g)throw new Error(`Failed to read chunk at 0x${l.toString(16)} after ${u} retries and recovery attempt`);g=!0,this.logger.log(`All retries exhausted at 0x${l.toString(16)}. Attempting recovery (close and reopen port)...`);try{await this.reconnect(),this.logger.log("Deep recovery successful. Resuming read from current position..."),c=0;continue}catch(t){throw new Error(`Failed to read chunk at 0x${l.toString(16)} after ${u} retries and recovery failed: ${t}`)}}}}s&&s(new Uint8Array(e),h.length,i),l+=e,d-=e,this.logger.debug(`Total progress: 0x${h.length.toString(16)} from 0x${i.toString(16)} bytes`)}const c=Date.now()-n,u=(h.length/1024/(c/1e3)).toFixed(1);return this.logger.log(`Read complete: ${h.length} bytes in ${(c/1e3).toFixed(1)} s (${u} KB/s)`),h}}class Ai extends Oi{constructor(){super(...arguments),this.IS_STUB=!0}async memBegin(t,e,i,a){const r=await yt(this.chipFamily,this.chipRevision);if(null===r)return[0,[]];const n=a,o=a+t;this.logger.debug(`Load range: ${s(n,8)}-${s(o,8)}`),this.logger.debug(`Stub data: ${s(r.data_start,8)}, len: ${r.data.length}, text: ${s(r.text_start,8)}, len: ${r.text.length}`);for(const[t,e]of[[r.data_start,r.data_start+r.data.length],[r.text_start,r.text_start+r.text.length]])if(nt)throw new Error("Software loader is resident at "+s(t,8)+"-"+s(e,8)+". Can't load binary at overlapping address range "+s(n,8)+"-"+s(o,8)+". Try changing the binary loading address.");return[0,[]]}async eraseFlash(){await this.checkCommand(208,[],0,ct)}async eraseRegion(t,e){if(t<0)throw new Error(`Invalid offset: ${t} (must be non-negative)`);if(e<0)throw new Error(`Invalid size: ${e} (must be non-negative)`);if(0===e)return void this.logger.log("eraseRegion: size is 0, skipping erase");if(t%o!==0)throw new Error(`Offset ${t} (0x${t.toString(16)}) is not aligned to flash sector size 4096 (0x${o.toString(16)})`);if(e%o!==0)throw new Error(`Size ${e} (0x${e.toString(16)}) is not aligned to flash sector size 4096 (0x${o.toString(16)})`);const i=4294967295;if(t>i)throw new Error(`Offset ${t} exceeds maximum value 4294967295`);if(e>i)throw new Error(`Size ${e} exceeds maximum value 4294967295`);if(t+e>i)throw new Error(`Region end (offset + size = ${t+e}) exceeds maximum addressable range 4294967295`);const s=bt(ft,e),a=Mi("t.length)break;const r=t.slice(s,s+i),n=r[0]|r[1]<<8;for(let t=0;t=32&&r[e]<127)i++;else if(0===r[e])break;if(i>=4){e+=5;break}}if(32768&n){const t=32767&n;t>0&&t<4096&&(e+=2)}}return e>=10}function Hi(t,e,i){const s=Ni;for(const a of s)for(let s=0;s<2;s++){const r=s*a,n=r+8;if(n+8>t.length)continue;if("littlefs"===String.fromCharCode(t[n],t[n+1],t[n+2],t[n+3],t[n+4],t[n+5],t[n+6],t[n+7])){const s=r+16,n=t[s]|t[s+1]<<8|t[s+2]<<16|t[s+3]<<24;if(0!==n&&n>>>0!=4294967295){const s=r+24;if(s+4<=t.length){const r=t[s]|t[s+1]<<8|t[s+2]<<16|t[s+3]<<24;if(r>0&&r<1e5){const t=r*a;if(t>0&&e+t<=i)return{start:e,end:e+t,size:t,page:256,block:a}}}return Ji(e,i,a)}}}if(Gi(t))return Ji(e,i,ji);if(t.length>=4){if(538182953===(t[0]|t[1]<<8|t[2]<<16|t[3]<<24)){let s=!0;if(t.length>=16){let e=!0;for(let i=4;i<16;i++)if(255!==t[i]){e=!1;break}e&&(s=!1)}if(s)return Ji(e,i,ji)}}const a=[0,4096];for(const s of a){if(t.length0&&r>0&&r<1e8){const t=r*a,n=e+s;if(t>0&&n+t<=i)return{start:n,end:n+t,size:t,page:a,block:a}}}}return null}function Ji(t,e,i){const s=e/1048576;if(s>=16){if(1048576===t)return{start:1048576,end:16752640,size:15704064,page:256,block:i};if(2097152===t)return{start:2097152,end:16752640,size:14655488,page:256,block:i}}if(s>=8){if(1048576===t)return{start:1048576,end:8364032,size:7315456,page:256,block:i};if(2097152===t)return{start:2097152,end:8364032,size:6266880,page:256,block:i}}if(s>=4){if(1048576===t)return{start:1048576,end:4169728,size:3121152,page:256,block:i};if(2097152===t)return{start:2097152,end:4169728,size:2072576,page:256,block:i};if(3145728===t)return{start:3145728,end:4169728,size:1024e3,page:256,block:i}}if(s>=2){if(1048576===t)return{start:1048576,end:2072576,size:1024e3,page:256,block:i};if(1572864===t)return{start:1572864,end:2072576,size:499712,page:256,block:i};if(1835008===t)return{start:1835008,end:2076672,size:241664,page:256,block:i};if(1966080===t)return{start:1966080,end:2076672,size:110592,page:256,block:i};if(2031616===t)return{start:2031616,end:2076672,size:45056,page:256,block:i}}if(s>=1){if(503808===t)return{start:503808,end:1028096,size:524288,page:256,block:i};if(765952===t)return{start:765952,end:1028096,size:262144,page:256,block:i};if(831488===t)return{start:831488,end:1028096,size:196608,page:256,block:i};if(864256===t)return{start:864256,end:1028096,size:163840,page:256,block:i};if(880640===t)return{start:880640,end:1028096,size:147456,page:256,block:i};if(897024===t)return{start:897024,end:1028096,size:131072,page:256,block:i};if(962560===t)return{start:962560,end:1028096,size:65536,page:256,block:i}}if(s>=.5){if(372736===t)return{start:372736,end:503808,size:131072,page:256,block:i};if(438272===t)return{start:438272,end:503808,size:65536,page:256,block:i};if(471040===t)return{start:471040,end:503808,size:32768,page:256,block:i}}return{start:t,end:e,size:e-t,page:256,block:i}}function Qi(t){return t>=16?[{start:1048576,end:16752640,size:15704064,page:256,block:8192},{start:2097152,end:16752640,size:14655488,page:256,block:8192}]:t>=8?[{start:1048576,end:8364032,size:7315456,page:256,block:8192},{start:2097152,end:8364032,size:6266880,page:256,block:8192}]:t>=4?[{start:2097152,end:4169728,size:2072576,page:256,block:8192},{start:1048576,end:4169728,size:3121152,page:256,block:8192},{start:3145728,end:4169728,size:1024e3,page:256,block:8192}]:t>=2?[{start:1048576,end:2072576,size:1024e3,page:256,block:8192},{start:1572864,end:2072576,size:499712,page:256,block:8192},{start:1835008,end:2076672,size:241664,page:256,block:8192},{start:1966080,end:2076672,size:110592,page:256,block:8192},{start:2031616,end:2076672,size:45056,page:256,block:8192}]:t>=1?[{start:897024,end:1028096,size:131072,page:256,block:8192},{start:503808,end:1028096,size:524288,page:256,block:8192},{start:765952,end:1028096,size:262144,page:256,block:8192},{start:831488,end:1028096,size:196608,page:256,block:8192},{start:864256,end:1028096,size:163840,page:256,block:8192},{start:880640,end:1028096,size:147456,page:256,block:8192},{start:962560,end:1028096,size:65536,page:256,block:8192}]:t>=.5?[{start:372736,end:503808,size:131072,page:256,block:8192},{start:438272,end:503808,size:65536,page:256,block:8192},{start:471040,end:503808,size:32768,page:256,block:8192}]:[]}var Vi;function Zi(t){return 1!==t.type?Vi.UNKNOWN:129===t.subtype?Vi.FATFS:Vi.UNKNOWN}function Xi(t,e){if(t.length<512)return Vi.UNKNOWN;const i=(null==e?void 0:e.toUpperCase().includes("ESP8266"))?Ni:Ti;for(const e of i)for(let i=0;i<2;i++){const s=i*e;if(s+20>t.length)continue;const a=s+8;if(a+8<=t.length){if("littlefs"===String.fromCharCode(t[a],t[a+1],t[a+2],t[a+3],t[a+4],t[a+5],t[a+6],t[a+7])){const e=s+16,i=t[e]|t[e+1]<<8|t[e+2]<<16|t[e+3]<<24;if(0!==i&&i>>>0!=4294967295)return Vi.LITTLEFS}}}const s=[0,4096];for(const e of s){if(t.length=e+62?String.fromCharCode(t[e+54],t[e+55],t[e+56],t[e+57],t[e+58]):"",s=t.length>=e+90?String.fromCharCode(t[e+82],t[e+83],t[e+84],t[e+85],t[e+86]):"";if(i.startsWith("FAT")||s.startsWith("FAT"))return Vi.FATFS}}if(t.length>=4){if(538182953===(t[0]|t[1]<<8|t[2]<<16|t[3]<<24))return Vi.SPIFFS}return Gi(t)?Vi.SPIFFS:Vi.UNKNOWN}function Ki(t,e){const i=null==e?void 0:e.toUpperCase().includes("ESP8266");switch(t){case Vi.FATFS:return 4096;case Vi.LITTLEFS:default:return i?Pi:4096}}function qi(t,e){const i=null==e?void 0:e.toUpperCase().includes("ESP8266");switch(t){case Vi.FATFS:return zi;case Vi.LITTLEFS:return i?Ni:Ti;default:return i?Ni:[4096,2048,1024,512]}}!function(t){t.UNKNOWN="unknown",t.LITTLEFS="littlefs",t.FATFS="fatfs",t.SPIFFS="spiffs"}(Vi||(Vi={}));const Yi={0:"app",1:"data"},ts={0:"factory",16:"ota_0",17:"ota_1",18:"ota_2",19:"ota_3",20:"ota_4",21:"ota_5",22:"ota_6",23:"ota_7",24:"ota_8",25:"ota_9",26:"ota_10",27:"ota_11",28:"ota_12",29:"ota_13",30:"ota_14",31:"ota_15",32:"test"},es={0:"ota",1:"phy",2:"nvs",3:"coredump",4:"nvs_keys",5:"efuse",128:"esphttpd",129:"fat",130:"spiffs",131:"littlefs"};function is(t){if(t.length<32)return null;if(20650!==(65535&(t[0]|t[1]<<8)))return null;const e=t[2],i=t[3],s=t[4]|t[5]<<8|t[6]<<16|t[7]<<24,a=t[8]|t[9]<<8|t[10]<<16|t[11]<<24;let r="";for(let e=12;e<28&&0!==t[e];e++)r+=String.fromCharCode(t[e]);const n=t[28]|t[29]<<8|t[30]<<16|t[31]<<24,o=Yi[e]||`unknown(0x${e.toString(16)})`;let h="";return h=0===e?ts[i]||`unknown(0x${i.toString(16)})`:1===e?es[i]||`unknown(0x${i.toString(16)})`:`0x${i.toString(16)}`,{name:r,type:e,subtype:i,offset:s,size:a,flags:n,typeName:o,subtypeName:h}}function ss(t){const e=[];for(let i=0;i=2)for(let s=0;sthis.buildConfig.objNameLen)throw new Error(`object name '${t}' too long`);const i=t;let s=0;try{this.blocks[this.blocks.length-1].beginObj(this.curObjId,e.length,i)}catch{this.createBlock().beginObj(this.curObjId,e.length,i)}for(;s0;){const s=new us(e,this.buildConfig);t.push(s.toBinary(this.blocksLim)),i--,e++}else{const e=this.imgSize-t.length*this.buildConfig.blockSize;if(e>0){const i=new Uint8Array(e);i.fill(255),t.push(i)}}const s=t.reduce((t,e)=>t+e.length,0),a=new Uint8Array(s);let r=0;for(const e of t)a.set(e,r),r+=e.length;return a}listFiles(){throw new Error("listFiles requires fromBinary to be called first")}readFile(){throw new Error("readFile requires fromBinary to be called first")}deleteFile(){throw new Error("deleteFile not yet implemented - requires filesystem recreation")}}class fs{constructor(t,e){this.imageData=t,this.buildConfig=e,this.filesMap=new Map}unpack(t,e,i=0){const s=new DataView(e.buffer,e.byteOffset+i),a=[];let r=0;for(const e of t)switch(e){case"B":a.push(s.getUint8(r)),r+=1;break;case"H":a.push("little"===this.buildConfig.endianness?s.getUint16(r,!0):s.getUint16(r,!1)),r+=2;break;case"I":a.push("little"===this.buildConfig.endianness?s.getUint32(r,!0):s.getUint32(r,!1)),r+=4}return a}parse(){const t=Math.floor(this.imageData.length/this.buildConfig.blockSize);for(let e=0;es.length);t+=this.buildConfig.objIdLen){const e=s.slice(t,t+this.buildConfig.objIdLen),[i]=this.unpack(1===this.buildConfig.objIdLen?"B":2===this.buildConfig.objIdLen?"H":"I",e);if(i===(1<<8*this.buildConfig.objIdLen)-1)continue;const a=!!(i&1<<8*this.buildConfig.objIdLen-1),r=i&~(1<<8*this.buildConfig.objIdLen-1);a&&!this.filesMap.has(r)&&this.filesMap.set(r,{name:null,size:0,dataPages:[]})}}for(let e=this.buildConfig.OBJ_LU_PAGES_PER_BLOCK;et[0]-e[0]);const i=[];let s=0;for(const[,t]of e.dataPages){const a=e.size-s;if(a<=0)break;const r=Math.min(t.length,a);i.push(t.slice(0,r)),s+=r}const a=new Uint8Array(s);let r=0;for(const t of i)a.set(t,r),r+=t.length;t.push({name:e.name,size:e.size,data:a})}return t}readFile(t){const e=this.listFiles().find(e=>e.name===t||e.name==="/"+t);return e?e.data:null}}const _s={pageSize:256,blockSize:4096,objNameLen:32,metaLen:4,useMagic:!0,useMagicLen:!0,alignedObjIxTables:!1},ps=async t=>{let e;const i=globalThis.requestSerialPort;if("function"==typeof i)e=await i();else{if(!navigator.serial)throw new Error("Web Serial API is not supported in this browser. Please use Chrome, Edge, or Opera on desktop, or Chrome on Android. Note: The page must be served over HTTPS or localhost.");e=await navigator.serial.requestPort()}return e.readable&&e.writable||await e.open({baudRate:h}),new Oi(e,t)},bs=async(t,e)=>{if(!t)throw new Error("Port is required");return t.readable&&t.writable||await t.open({baudRate:h}),new Oi(t,e)};export{ct as CHIP_ERASE_TIMEOUT,v as CHIP_FAMILY_ESP32,k as CHIP_FAMILY_ESP32C2,x as CHIP_FAMILY_ESP32C3,U as CHIP_FAMILY_ESP32C5,M as CHIP_FAMILY_ESP32C6,D as CHIP_FAMILY_ESP32C61,O as CHIP_FAMILY_ESP32H2,F as CHIP_FAMILY_ESP32H21,A as CHIP_FAMILY_ESP32H4,T as CHIP_FAMILY_ESP32P4,C as CHIP_FAMILY_ESP32S2,E as CHIP_FAMILY_ESP32S3,L as CHIP_FAMILY_ESP32S31,R as CHIP_FAMILY_ESP8266,_s as DEFAULT_SPIFFS_CONFIG,dt as DEFAULT_TIMEOUT,ft as ERASE_REGION_TIMEOUT_PER_MB,Pi as ESP8266_LITTLEFS_BLOCK_SIZE,Ni as ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES,$i as ESP8266_LITTLEFS_PAGE_SIZE,ji as ESP8266_SPIFFS_BLOCK_SIZE,Wi as ESP8266_SPIFFS_PAGE_SIZE,Oi as ESPLoader,tt as ESP_CHANGE_BAUDRATE,st as ESP_CHECKSUM_MAGIC,Z as ESP_ERASE_FLASH,X as ESP_ERASE_REGION,N as ESP_FLASH_BEGIN,$ as ESP_FLASH_DATA,at as ESP_FLASH_DEFL_BEGIN,rt as ESP_FLASH_DEFL_DATA,nt as ESP_FLASH_DEFL_END,W as ESP_FLASH_END,it as ESP_GET_SECURITY_INFO,j as ESP_MEM_BEGIN,H as ESP_MEM_DATA,G as ESP_MEM_END,lt as ESP_RAM_BLOCK,K as ESP_READ_FLASH,V as ESP_READ_REG,Y as ESP_SPI_ATTACH,et as ESP_SPI_FLASH_MD5,q as ESP_SPI_SET_PARAMS,J as ESP_SYNC,Q as ESP_WRITE_REG,zi as FATFS_BLOCK_SIZE_CANDIDATES,Li as FATFS_DEFAULT_BLOCK_SIZE,pt as FLASH_READ_TIMEOUT,Vi as FilesystemType,Ti as LITTLEFS_BLOCK_SIZE_CANDIDATES,Fi as LITTLEFS_DEFAULT_BLOCK_SIZE,ut as MAX_TIMEOUT,_t as MEM_END_ROM_TIMEOUT,ot as ROM_INVALID_RECV_MSG,gt as SYNC_TIMEOUT,rs as SpiffsBuildConfig,gs as SpiffsFS,fs as SpiffsReader,ht as USB_RAM_BLOCK,ps as connect,bs as connectWithPort,Xi as detectFilesystemFromImage,Zi as detectFilesystemType,a as formatMacAddr,as as formatSize,qi as getBlockSizeCandidates,Ki as getDefaultBlockSize,Qi as getESP8266FilesystemLayout,i as hexFormatter,ss as parsePartitionTable,Hi as scanESP8266Filesystem,r as sleep,s as toHex}; +/** + * @name slipEncode + * Take an array buffer and return back a new array where + * 0xdb is replaced with 0xdb 0xdd and 0xc0 is replaced with 0xdb 0xdc + */ +const slipEncode = (buffer) => { + let encoded = [0xc0]; + for (const byte of buffer) { + if (byte == 0xdb) { + encoded = encoded.concat([0xdb, 0xdd]); + } + else if (byte == 0xc0) { + encoded = encoded.concat([0xdb, 0xdc]); + } + else { + encoded.push(byte); + } + } + encoded.push(0xc0); + return encoded; +}; +/** + * @name toByteArray + * Convert a string to a byte array + */ +const toByteArray = (str) => { + const byteArray = []; + for (let i = 0; i < str.length; i++) { + const charcode = str.charCodeAt(i); + if (charcode <= 0xff) { + byteArray.push(charcode); + } + } + return byteArray; +}; +const hexFormatter = (bytes) => "[" + bytes.map((value) => toHex(value)).join(", ") + "]"; +const toHex = (value, size = 2) => { + const hex = value.toString(16).toUpperCase(); + if (hex.startsWith("-")) { + return "-0x" + hex.substring(1).padStart(size, "0"); + } + else { + return "0x" + hex.padStart(size, "0"); + } +}; +/** + * Format MAC address array to string (e.g., [0xAA, 0xBB, 0xCC] -> "AA:BB:CC:DD:EE:FF") + */ +const formatMacAddr = (macAddr) => { + return macAddr + .map((value) => value.toString(16).toUpperCase().padStart(2, "0")) + .join(":"); +}; +/** + * @name padTo + * Pad data to the next alignment boundary with the given fill byte (default 0xFF) + */ +function padTo(data, alignment, padCharacter = 0xff) { + const padMod = data.length % alignment; + if (padMod !== 0) { + const padding = new Uint8Array(alignment - padMod).fill(padCharacter); + const paddedData = new Uint8Array(data.length + padding.length); + paddedData.set(data); + paddedData.set(padding, data.length); + return paddedData; + } + return data; +} +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +const DETECTED_FLASH_SIZES = { + 0x12: "256KB", + 0x13: "512KB", + 0x14: "1MB", + 0x15: "2MB", + 0x16: "4MB", + 0x17: "8MB", + 0x18: "16MB", + 0x19: "32MB", + 0x1a: "64MB", + 0x1b: "128MB", + 0x1c: "256MB", + 0x20: "64MB", + 0x21: "128MB", + 0x22: "256MB", + 0x32: "256KB", + 0x33: "512KB", + 0x34: "1MB", + 0x35: "2MB", + 0x36: "4MB", + 0x37: "8MB", + 0x38: "16MB", + 0x39: "32MB", + 0x3a: "64MB", +}; +const FLASH_WRITE_SIZE = 0x400; +const STUB_FLASH_WRITE_SIZE = 0x4000; +const FLASH_SECTOR_SIZE = 0x1000; // Flash sector size, minimum unit of erase. +const ESP_ROM_BAUD = 115200; +const USB_JTAG_SERIAL_PID = 0x1001; +const ESP8266_SPI_REG_BASE = 0x60000200; +const ESP8266_BASEFUSEADDR = 0x3ff00050; +const ESP8266_MACFUSEADDR = 0x3ff00050; +const ESP8266_SPI_USR_OFFS = 0x1c; +const ESP8266_SPI_USR1_OFFS = 0x20; +const ESP8266_SPI_USR2_OFFS = 0x24; +const ESP8266_SPI_MOSI_DLEN_OFFS = -1; +const ESP8266_SPI_MISO_DLEN_OFFS = -1; +const ESP8266_SPI_W0_OFFS = 0x40; +const ESP8266_UART_DATE_REG_ADDR = 0x60000078; +const ESP8266_BOOTLOADER_FLASH_OFFSET = 0x0000; +const ESP32_SPI_REG_BASE = 0x3ff42000; +const ESP32_BASEFUSEADDR = 0x3ff5a000; +const ESP32_MACFUSEADDR = 0x3ff5a000; +const ESP32_SPI_USR_OFFS = 0x1c; +const ESP32_SPI_USR1_OFFS = 0x20; +const ESP32_SPI_USR2_OFFS = 0x24; +const ESP32_SPI_MOSI_DLEN_OFFS = 0x28; +const ESP32_SPI_MISO_DLEN_OFFS = 0x2c; +const ESP32_SPI_W0_OFFS = 0x80; +const ESP32_UART_DATE_REG_ADDR = 0x60000078; +const ESP32_BOOTLOADER_FLASH_OFFSET = 0x1000; +const ESP32_APB_CTL_DATE_ADDR = 0x3ff66000 + 0x7c; +const ESP32S2_SPI_REG_BASE = 0x3f402000; +const ESP32S2_BASEFUSEADDR = 0x3f41a000; +const ESP32S2_EFUSE_BLOCK1_ADDR = ESP32S2_BASEFUSEADDR + 0x044; +const ESP32S2_MACFUSEADDR = 0x3f41a044; +const ESP32S2_SPI_USR_OFFS = 0x18; +const ESP32S2_SPI_USR1_OFFS = 0x1c; +const ESP32S2_SPI_USR2_OFFS = 0x20; +const ESP32S2_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32S2_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32S2_SPI_W0_OFFS = 0x58; +const ESP32S2_UART_DATE_REG_ADDR = 0x60000078; +const ESP32S2_BOOTLOADER_FLASH_OFFSET = 0x1000; +// ESP32-S2 RTC Watchdog Timer registers for USB-OTG reset +const ESP32S2_RTCCNTL_BASE_REG = 0x3f408000; +const ESP32S2_RTC_CNTL_WDTWPROTECT_REG = ESP32S2_RTCCNTL_BASE_REG + 0x00ac; +const ESP32S2_RTC_CNTL_WDTCONFIG0_REG = ESP32S2_RTCCNTL_BASE_REG + 0x0094; +const ESP32S2_RTC_CNTL_WDTCONFIG1_REG = ESP32S2_RTCCNTL_BASE_REG + 0x0098; +const ESP32S2_RTC_CNTL_WDT_WKEY = 0x50d83aa1; +const ESP32S2_RTC_CNTL_OPTION1_REG = 0x3f408128; +const ESP32S2_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1; // Is download mode forced over USB? +const ESP32S2_UARTDEV_BUF_NO = 0x3ffffd14; // Variable in ROM .bss which indicates the port in use +const ESP32S2_UARTDEV_BUF_NO_USB_OTG = 2; // Value of the above indicating that USB-OTG is in use +const ESP32S3_SPI_REG_BASE = 0x60002000; +const ESP32S3_BASEFUSEADDR = 0x60007000; +const ESP32S3_EFUSE_BLOCK1_ADDR = ESP32S3_BASEFUSEADDR + 0x044; +const ESP32S3_MACFUSEADDR = 0x60007000 + 0x044; +const ESP32S3_SPI_USR_OFFS = 0x18; +const ESP32S3_SPI_USR1_OFFS = 0x1c; +const ESP32S3_SPI_USR2_OFFS = 0x20; +const ESP32S3_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32S3_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32S3_SPI_W0_OFFS = 0x58; +const ESP32S3_UART_DATE_REG_ADDR = 0x60000080; +const ESP32S3_BOOTLOADER_FLASH_OFFSET = 0x0000; +// ESP32-S3 RTC Watchdog Timer registers for USB-OTG reset +const ESP32S3_RTCCNTL_BASE_REG = 0x60008000; +const ESP32S3_RTC_CNTL_WDTWPROTECT_REG = ESP32S3_RTCCNTL_BASE_REG + 0x00b0; +const ESP32S3_RTC_CNTL_WDTCONFIG0_REG = ESP32S3_RTCCNTL_BASE_REG + 0x0098; +const ESP32S3_RTC_CNTL_WDTCONFIG1_REG = ESP32S3_RTCCNTL_BASE_REG + 0x009c; +const ESP32S3_RTC_CNTL_WDT_WKEY = 0x50d83aa1; +const ESP32S3_RTC_CNTL_OPTION1_REG = 0x6000812c; +const ESP32S3_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1; // Is download mode forced over USB? +const ESP32S3_UARTDEV_BUF_NO = 0x3fcef14c; // Variable in ROM .bss which indicates the port in use +const ESP32S3_UARTDEV_BUF_NO_USB_OTG = 3; // The above var when USB-OTG is used +const ESP32S3_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 4; // The above var when USB-JTAG/Serial is used +const ESP32C2_SPI_REG_BASE = 0x60002000; +const ESP32C2_BASEFUSEADDR = 0x60008800; +const ESP32C2_EFUSE_BLOCK2_ADDR = ESP32C2_BASEFUSEADDR + 0x040; +const ESP32C2_MACFUSEADDR = ESP32C2_BASEFUSEADDR + 0x040; +const ESP32C2_SPI_USR_OFFS = 0x18; +const ESP32C2_SPI_USR1_OFFS = 0x1c; +const ESP32C2_SPI_USR2_OFFS = 0x20; +const ESP32C2_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32C2_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32C2_SPI_W0_OFFS = 0x58; +const ESP32C2_UART_DATE_REG_ADDR = 0x6000007c; +const ESP32C2_BOOTLOADER_FLASH_OFFSET = 0x0000; +const ESP32C3_SPI_REG_BASE = 0x60002000; +const ESP32C3_BASEFUSEADDR = 0x60008800; +const ESP32C3_MACFUSEADDR = 0x60008800 + 0x044; +const ESP32C3_SPI_USR_OFFS = 0x18; +const ESP32C3_SPI_USR1_OFFS = 0x1c; +const ESP32C3_SPI_USR2_OFFS = 0x20; +const ESP32C3_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32C3_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32C3_SPI_W0_OFFS = 0x58; +const ESP32C3_UART_DATE_REG_ADDR = 0x6000007c; +const ESP32C3_BOOTLOADER_FLASH_OFFSET = 0x0000; +// ESP32-C3 RTC Watchdog Timer registers +const ESP32C3_RTC_CNTL_BASE_REG = 0x60008000; +const ESP32C3_RTC_CNTL_WDTWPROTECT_REG = ESP32C3_RTC_CNTL_BASE_REG + 0x00a8; +const ESP32C3_RTC_CNTL_WDTCONFIG0_REG = ESP32C3_RTC_CNTL_BASE_REG + 0x0090; +const ESP32C3_RTC_CNTL_WDTCONFIG1_REG = ESP32C3_RTC_CNTL_BASE_REG + 0x0094; +const ESP32C3_RTC_CNTL_WDT_WKEY = 0x50d83aa1; +const ESP32C3_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used +const ESP32C3_BUF_UART_NO_OFFSET = 24; +// Note: ESP32C3_BSS_UART_DEV_ADDR is calculated dynamically based on chip revision in esp_loader.ts +// Revision < 101: 0x3FCDF064, Revision >= 101: 0x3FCDF060 +// ESP32-C3 EFUSE registers for chip revision detection +const ESP32C3_EFUSE_RD_MAC_SPI_SYS_3_REG = 0x60008850; +const ESP32C3_EFUSE_RD_MAC_SPI_SYS_5_REG = 0x60008858; +const ESP32C5_SPI_REG_BASE = 0x60003000; +const ESP32C5_BASEFUSEADDR = 0x600b4800; +const ESP32C5_EFUSE_BLOCK1_ADDR = ESP32C5_BASEFUSEADDR + 0x044; +const ESP32C5_MACFUSEADDR = 0x600b4800 + 0x044; +const ESP32C5_SPI_USR_OFFS = 0x18; +const ESP32C5_SPI_USR1_OFFS = 0x1c; +const ESP32C5_SPI_USR2_OFFS = 0x20; +const ESP32C5_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32C5_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32C5_SPI_W0_OFFS = 0x58; +const ESP32C5_UART_DATE_REG_ADDR = 0x6000007c; +const ESP32C5_UART_CLKDIV_REG = 0x60000014; +const ESP32C5_BOOTLOADER_FLASH_OFFSET = 0x2000; +// ESP32-C5 Crystal frequency detection registers +const ESP32C5_PCR_SYSCLK_CONF_REG = 0x60096110; +const ESP32C5_PCR_SYSCLK_XTAL_FREQ_V = 0x7f << 24; +const ESP32C5_PCR_SYSCLK_XTAL_FREQ_S = 24; +// ESP32-C5 USB-JTAG/Serial detection +const ESP32C5_UARTDEV_BUF_NO = 0x4085f514; // Variable in ROM .bss which indicates the port in use +const ESP32C5_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used +const ESP32C6_SPI_REG_BASE = 0x60003000; +const ESP32C6_BASEFUSEADDR = 0x600b0800; +const ESP32C6_EFUSE_BLOCK1_ADDR = ESP32C6_BASEFUSEADDR + 0x044; +const ESP32C6_MACFUSEADDR = 0x600b0800 + 0x044; +const ESP32C6_SPI_USR_OFFS = 0x18; +const ESP32C6_SPI_USR1_OFFS = 0x1c; +const ESP32C6_SPI_USR2_OFFS = 0x20; +const ESP32C6_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32C6_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32C6_SPI_W0_OFFS = 0x58; +const ESP32C6_UART_DATE_REG_ADDR = 0x6000007c; +const ESP32C6_BOOTLOADER_FLASH_OFFSET = 0x0000; +// ESP32-C6 USB-JTAG/Serial detection +const ESP32C6_UARTDEV_BUF_NO = 0x4087f580; // Variable in ROM .bss which indicates the port in use +const ESP32C6_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used +// ESP32-C5/C6 LP Watchdog Timer registers (Low Power WDT) +const ESP32C5_C6_DR_REG_LP_WDT_BASE = 0x600b1c00; +const ESP32C5_C6_RTC_CNTL_WDTCONFIG0_REG = ESP32C5_C6_DR_REG_LP_WDT_BASE + 0x0000; // LP_WDT_RWDT_CONFIG0_REG +const ESP32C5_C6_RTC_CNTL_WDTCONFIG1_REG = ESP32C5_C6_DR_REG_LP_WDT_BASE + 0x0004; // LP_WDT_RWDT_CONFIG1_REG +const ESP32C5_C6_RTC_CNTL_WDTWPROTECT_REG = ESP32C5_C6_DR_REG_LP_WDT_BASE + 0x0018; // LP_WDT_RWDT_WPROTECT_REG +const ESP32C5_C6_RTC_CNTL_WDT_WKEY = 0x50d83aa1; // LP_WDT_SWD_WKEY +const ESP32C61_SPI_REG_BASE = 0x60003000; +const ESP32C61_BASEFUSEADDR = 0x600b4800; +const ESP32C61_EFUSE_BLOCK1_ADDR = ESP32C61_BASEFUSEADDR + 0x044; +const ESP32C61_MACFUSEADDR = 0x600b4800 + 0x044; +const ESP32C61_SPI_USR_OFFS = 0x18; +const ESP32C61_SPI_USR1_OFFS = 0x1c; +const ESP32C61_SPI_USR2_OFFS = 0x20; +const ESP32C61_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32C61_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32C61_SPI_W0_OFFS = 0x58; +const ESP32C61_UART_DATE_REG_ADDR = 0x6000007c; +const ESP32C61_BOOTLOADER_FLASH_OFFSET = 0x0000; +// ESP32-C61 USB-JTAG/Serial detection (dynamic based on chip revision) +const ESP32C61_UARTDEV_BUF_NO_REV_LE2 = 0x4084f5ec; // revision <= 2 +const ESP32C61_UARTDEV_BUF_NO_REV_GT2 = 0x4084f5e4; // revision > 2 +const ESP32C61_UARTDEV_BUF_NO_USB_JTAG_SERIAL_REV_LE2 = 3; // revision <= 2 +const ESP32C61_UARTDEV_BUF_NO_USB_JTAG_SERIAL_REV_GT2 = 4; // revision > 2 +const ESP32H2_SPI_REG_BASE = 0x60003000; +const ESP32H2_BASEFUSEADDR = 0x600b0800; +const ESP32H2_EFUSE_BLOCK1_ADDR = ESP32H2_BASEFUSEADDR + 0x044; +const ESP32H2_MACFUSEADDR = 0x600b0800 + 0x044; +const ESP32H2_SPI_USR_OFFS = 0x18; +const ESP32H2_SPI_USR1_OFFS = 0x1c; +const ESP32H2_SPI_USR2_OFFS = 0x20; +const ESP32H2_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32H2_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32H2_SPI_W0_OFFS = 0x58; +const ESP32H2_UART_DATE_REG_ADDR = 0x6000007c; +const ESP32H2_BOOTLOADER_FLASH_OFFSET = 0x0000; +// ESP32-H2 USB-JTAG/Serial detection +const ESP32H2_UARTDEV_BUF_NO = 0x4084fefc; // Variable in ROM .bss which indicates the port in use +const ESP32H2_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used +const ESP32H4_SPI_REG_BASE = 0x60099000; +const ESP32H4_BASEFUSEADDR = 0x600b1800; +const ESP32H4_MACFUSEADDR = 0x600b1800 + 0x044; +const ESP32H4_SPI_USR_OFFS = 0x18; +const ESP32H4_SPI_USR1_OFFS = 0x1c; +const ESP32H4_SPI_USR2_OFFS = 0x20; +const ESP32H4_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32H4_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32H4_SPI_W0_OFFS = 0x58; +const ESP32H4_UART_DATE_REG_ADDR = 0x60012000 + 0x7c; +const ESP32H4_BOOTLOADER_FLASH_OFFSET = 0x2000; +// ESP32-H4 USB-JTAG/Serial detection +const ESP32H4_UARTDEV_BUF_NO = 0x4087f580; // Variable in ROM .bss which indicates the port in use +const ESP32H4_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used +const ESP32H21_SPI_REG_BASE = 0x60003000; +const ESP32H21_BASEFUSEADDR = 0x600b4000; +const ESP32H21_MACFUSEADDR = 0x600b4000 + 0x044; +const ESP32H21_SPI_USR_OFFS = 0x18; +const ESP32H21_SPI_USR1_OFFS = 0x1c; +const ESP32H21_SPI_USR2_OFFS = 0x20; +const ESP32H21_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32H21_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32H21_SPI_W0_OFFS = 0x58; +const ESP32H21_UART_DATE_REG_ADDR = 0x6000007c; +const ESP32H21_BOOTLOADER_FLASH_OFFSET = 0x0000; +const ESP32P4_SPI_REG_BASE = 0x5008d000; +const ESP32P4_BASEFUSEADDR = 0x5012d000; +const ESP32P4_EFUSE_BLOCK1_ADDR = ESP32P4_BASEFUSEADDR + 0x044; +const ESP32P4_MACFUSEADDR = 0x5012d000 + 0x044; +const ESP32P4_SPI_USR_OFFS = 0x18; +const ESP32P4_SPI_USR1_OFFS = 0x1c; +const ESP32P4_SPI_USR2_OFFS = 0x20; +const ESP32P4_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32P4_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32P4_SPI_W0_OFFS = 0x58; +const ESP32P4_UART_DATE_REG_ADDR = 0x500ca000 + 0x8c; +const ESP32P4_BOOTLOADER_FLASH_OFFSET = 0x2000; +// ESP32-P4 RTC Watchdog Timer registers +const ESP32P4_DR_REG_LP_WDT_BASE = 0x50116000; +const ESP32P4_RTC_CNTL_WDTWPROTECT_REG = ESP32P4_DR_REG_LP_WDT_BASE + 0x0018; // LP_WDT_WPROTECT_REG +const ESP32P4_RTC_CNTL_WDTCONFIG0_REG = ESP32P4_DR_REG_LP_WDT_BASE + 0x0000; // LP_WDT_CONFIG0_REG +const ESP32P4_RTC_CNTL_WDTCONFIG1_REG = ESP32P4_DR_REG_LP_WDT_BASE + 0x0004; // LP_WDT_CONFIG1_REG +const ESP32P4_RTC_CNTL_WDT_WKEY = 0x50d83aa1; +// ESP32-P4 USB-JTAG/Serial and USB-OTG detection +// Note: UARTDEV_BUF_NO is dynamic based on chip revision +// Revision < 300: 0x4FF3FEB0 + 24 = 0x4FF3FEC8 +// Revision >= 300: 0x4FFBFEB0 + 24 = 0x4FFBFEC8 +const ESP32P4_UARTDEV_BUF_NO_REV0 = 0x4ff3fec8; // Variable in ROM .bss (revision < 300) +const ESP32P4_UARTDEV_BUF_NO_REV300 = 0x4ffbfec8; // Variable in ROM .bss (revision >= 300) +const ESP32P4_UARTDEV_BUF_NO_USB_OTG = 5; // The above var when USB-OTG is used +const ESP32P4_UARTDEV_BUF_NO_USB_JTAG_SERIAL = 6; // The above var when USB-JTAG/Serial is used +const ESP32P4_RTC_CNTL_OPTION1_REG = 0x50110008; +const ESP32P4_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x4; // Is download mode forced over USB? +// Flash power-on related registers and bits needed for ECO6 (Rev 301) +const ESP32P4_DR_REG_LPAON_BASE = 0x50110000; +const ESP32P4_DR_REG_PMU_BASE = ESP32P4_DR_REG_LPAON_BASE + 0x5000; +const ESP32P4_DR_REG_LP_SYS_BASE = ESP32P4_DR_REG_LPAON_BASE + 0x0; +const ESP32P4_LP_SYSTEM_REG_ANA_XPD_PAD_GROUP_REG = ESP32P4_DR_REG_LP_SYS_BASE + 0x10c; +const ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG = ESP32P4_DR_REG_PMU_BASE + 0x1bc; +const ESP32P4_PMU_ANA_0P1A_EN_CUR_LIM_0 = 1 << 27; +const ESP32P4_PMU_EXT_LDO_P0_0P1A_REG = ESP32P4_DR_REG_PMU_BASE + 0x1b8; +const ESP32P4_PMU_0P1A_FORCE_TIEH_SEL_0 = 1 << 7; +const ESP32P4_PMU_DATE_REG = ESP32P4_DR_REG_PMU_BASE + 0x3fc; +const ESP32S31_SPI_REG_BASE = 0x20500000; +const ESP32S31_BASEFUSEADDR = 0x20715000; +const ESP32S31_EFUSE_BLOCK1_ADDR = ESP32S31_BASEFUSEADDR + 0x044; +const ESP32S31_MACFUSEADDR = 0x20715000 + 0x044; +const ESP32S31_SPI_USR_OFFS = 0x18; +const ESP32S31_SPI_USR1_OFFS = 0x1c; +const ESP32S31_SPI_USR2_OFFS = 0x20; +const ESP32S31_SPI_MOSI_DLEN_OFFS = 0x24; +const ESP32S31_SPI_MISO_DLEN_OFFS = 0x28; +const ESP32S31_SPI_W0_OFFS = 0x58; +const ESP32S31_UART_DATE_REG_ADDR = 0x2038a000 + 0x8c; +const ESP32S31_BOOTLOADER_FLASH_OFFSET = 0x2000; +const SYNC_PACKET = toByteArray("\x07\x07\x12 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"); +const CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000; +// Image Chip IDs (used by ESP32-C3 and later for chip detection) +// These values for the families are made up; nothing that esptool uses. +const CHIP_FAMILY_ESP8266 = 0x8266; +const CHIP_FAMILY_ESP32 = 0x32; +const CHIP_FAMILY_ESP32S2 = 0x3252; +const CHIP_FAMILY_ESP32S3 = 0x3253; +const CHIP_FAMILY_ESP32C2 = 0x32c2; +const CHIP_FAMILY_ESP32C3 = 0x32c3; +const CHIP_FAMILY_ESP32C5 = 0x32c5; +const CHIP_FAMILY_ESP32C6 = 0x32c6; +const CHIP_FAMILY_ESP32C61 = 0x32c61; +const CHIP_FAMILY_ESP32H2 = 0x3272; +const CHIP_FAMILY_ESP32H4 = 0x3274; +const CHIP_FAMILY_ESP32H21 = 0x3275; +const CHIP_FAMILY_ESP32P4 = 0x3280; +const CHIP_FAMILY_ESP32S31 = 0x3231; +const CHIP_ID_TO_INFO = { + 5: { name: "ESP32-C3", family: CHIP_FAMILY_ESP32C3 }, + 9: { name: "ESP32-S3", family: CHIP_FAMILY_ESP32S3 }, + 12: { name: "ESP32-C2", family: CHIP_FAMILY_ESP32C2 }, + 13: { name: "ESP32-C6", family: CHIP_FAMILY_ESP32C6 }, + 16: { name: "ESP32-H2", family: CHIP_FAMILY_ESP32H2 }, + 18: { name: "ESP32-P4", family: CHIP_FAMILY_ESP32P4 }, + 20: { name: "ESP32-C61", family: CHIP_FAMILY_ESP32C61 }, + 23: { name: "ESP32-C5", family: CHIP_FAMILY_ESP32C5 }, + 25: { name: "ESP32-H21", family: CHIP_FAMILY_ESP32H21 }, + 28: { name: "ESP32-H4", family: CHIP_FAMILY_ESP32H4 }, + 32: { name: "ESP32-S31", family: CHIP_FAMILY_ESP32S31 }, +}; +const CHIP_DETECT_MAGIC_VALUES = { + 0xfff0c101: { name: "ESP8266", family: CHIP_FAMILY_ESP8266 }, + 0x00f01d83: { name: "ESP32", family: CHIP_FAMILY_ESP32 }, + 0x000007c6: { name: "ESP32-S2", family: CHIP_FAMILY_ESP32S2 }, +}; +// Commands supported by ESP8266 ROM bootloader +const ESP_FLASH_BEGIN = 0x02; +const ESP_FLASH_DATA = 0x03; +const ESP_FLASH_END = 0x04; +const ESP_MEM_BEGIN = 0x05; +const ESP_MEM_END = 0x06; +const ESP_MEM_DATA = 0x07; +const ESP_SYNC = 0x08; +const ESP_WRITE_REG = 0x09; +const ESP_READ_REG = 0x0a; +const ESP_ERASE_FLASH = 0xd0; +const ESP_ERASE_REGION = 0xd1; +const ESP_READ_FLASH = 0xd2; +const ESP_SPI_SET_PARAMS = 0x0b; +const ESP_SPI_ATTACH = 0x0d; +const ESP_CHANGE_BAUDRATE = 0x0f; +const ESP_SPI_FLASH_MD5 = 0x13; +const ESP_GET_SECURITY_INFO = 0x14; +const ESP_CHECKSUM_MAGIC = 0xef; +const ESP_FLASH_DEFL_BEGIN = 0x10; +const ESP_FLASH_DEFL_DATA = 0x11; +const ESP_FLASH_DEFL_END = 0x12; +const ROM_INVALID_RECV_MSG = 0x05; +const USB_RAM_BLOCK = 0x800; +const ESP_RAM_BLOCK = 0x1800; +// Timeouts +const DEFAULT_TIMEOUT = 3000; +const CHIP_ERASE_TIMEOUT = 150000; // timeout for full chip erase in ms +const MAX_TIMEOUT = CHIP_ERASE_TIMEOUT * 2; // longest any command can run in ms +const SYNC_TIMEOUT = 100; // timeout for syncing with bootloader in ms +const ERASE_REGION_TIMEOUT_PER_MB = 30000; // timeout (per megabyte) for erasing a region in ms +const MEM_END_ROM_TIMEOUT = 500; +const FLASH_READ_TIMEOUT = 100; // timeout for reading flash in ms +/** + * @name timeoutPerMb + * Scales timeouts which are size-specific + */ +const timeoutPerMb = (secondsPerMb, sizeBytes) => { + const result = Math.floor(secondsPerMb * (sizeBytes / 0x1e6)); + if (result < DEFAULT_TIMEOUT) { + return DEFAULT_TIMEOUT; + } + return result; +}; +const getSpiFlashAddresses = (chipFamily) => { + switch (chipFamily) { + case CHIP_FAMILY_ESP32: + return { + regBase: ESP32_SPI_REG_BASE, + baseFuse: ESP32_BASEFUSEADDR, + macFuse: ESP32_MACFUSEADDR, + usrOffs: ESP32_SPI_USR_OFFS, + usr1Offs: ESP32_SPI_USR1_OFFS, + usr2Offs: ESP32_SPI_USR2_OFFS, + mosiDlenOffs: ESP32_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32_SPI_W0_OFFS, + uartDateReg: ESP32_UART_DATE_REG_ADDR, + flashOffs: ESP32_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32S2: + return { + regBase: ESP32S2_SPI_REG_BASE, + baseFuse: ESP32S2_BASEFUSEADDR, + macFuse: ESP32S2_MACFUSEADDR, + usrOffs: ESP32S2_SPI_USR_OFFS, + usr1Offs: ESP32S2_SPI_USR1_OFFS, + usr2Offs: ESP32S2_SPI_USR2_OFFS, + mosiDlenOffs: ESP32S2_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32S2_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32S2_SPI_W0_OFFS, + uartDateReg: ESP32S2_UART_DATE_REG_ADDR, + flashOffs: ESP32S2_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32S3: + return { + regBase: ESP32S3_SPI_REG_BASE, + usrOffs: ESP32S3_SPI_USR_OFFS, + baseFuse: ESP32S3_BASEFUSEADDR, + macFuse: ESP32S3_MACFUSEADDR, + usr1Offs: ESP32S3_SPI_USR1_OFFS, + usr2Offs: ESP32S3_SPI_USR2_OFFS, + mosiDlenOffs: ESP32S3_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32S3_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32S3_SPI_W0_OFFS, + uartDateReg: ESP32S3_UART_DATE_REG_ADDR, + flashOffs: ESP32S3_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP8266: + return { + regBase: ESP8266_SPI_REG_BASE, + usrOffs: ESP8266_SPI_USR_OFFS, + baseFuse: ESP8266_BASEFUSEADDR, + macFuse: ESP8266_MACFUSEADDR, + usr1Offs: ESP8266_SPI_USR1_OFFS, + usr2Offs: ESP8266_SPI_USR2_OFFS, + mosiDlenOffs: ESP8266_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP8266_SPI_MISO_DLEN_OFFS, + w0Offs: ESP8266_SPI_W0_OFFS, + uartDateReg: ESP8266_UART_DATE_REG_ADDR, + flashOffs: ESP8266_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32C2: + return { + regBase: ESP32C2_SPI_REG_BASE, + baseFuse: ESP32C2_BASEFUSEADDR, + macFuse: ESP32C2_MACFUSEADDR, + usrOffs: ESP32C2_SPI_USR_OFFS, + usr1Offs: ESP32C2_SPI_USR1_OFFS, + usr2Offs: ESP32C2_SPI_USR2_OFFS, + mosiDlenOffs: ESP32C2_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32C2_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32C2_SPI_W0_OFFS, + uartDateReg: ESP32C2_UART_DATE_REG_ADDR, + flashOffs: ESP32C2_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32C3: + return { + regBase: ESP32C3_SPI_REG_BASE, + baseFuse: ESP32C3_BASEFUSEADDR, + macFuse: ESP32C3_MACFUSEADDR, + usrOffs: ESP32C3_SPI_USR_OFFS, + usr1Offs: ESP32C3_SPI_USR1_OFFS, + usr2Offs: ESP32C3_SPI_USR2_OFFS, + mosiDlenOffs: ESP32C3_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32C3_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32C3_SPI_W0_OFFS, + uartDateReg: ESP32C3_UART_DATE_REG_ADDR, + flashOffs: ESP32C3_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32C5: + return { + regBase: ESP32C5_SPI_REG_BASE, + baseFuse: ESP32C5_BASEFUSEADDR, + macFuse: ESP32C5_MACFUSEADDR, + usrOffs: ESP32C5_SPI_USR_OFFS, + usr1Offs: ESP32C5_SPI_USR1_OFFS, + usr2Offs: ESP32C5_SPI_USR2_OFFS, + mosiDlenOffs: ESP32C5_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32C5_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32C5_SPI_W0_OFFS, + uartDateReg: ESP32C5_UART_DATE_REG_ADDR, + flashOffs: ESP32C5_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32C6: + return { + regBase: ESP32C6_SPI_REG_BASE, + baseFuse: ESP32C6_BASEFUSEADDR, + macFuse: ESP32C6_MACFUSEADDR, + usrOffs: ESP32C6_SPI_USR_OFFS, + usr1Offs: ESP32C6_SPI_USR1_OFFS, + usr2Offs: ESP32C6_SPI_USR2_OFFS, + mosiDlenOffs: ESP32C6_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32C6_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32C6_SPI_W0_OFFS, + uartDateReg: ESP32C6_UART_DATE_REG_ADDR, + flashOffs: ESP32C6_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32C61: + return { + regBase: ESP32C61_SPI_REG_BASE, + baseFuse: ESP32C61_BASEFUSEADDR, + macFuse: ESP32C61_MACFUSEADDR, + usrOffs: ESP32C61_SPI_USR_OFFS, + usr1Offs: ESP32C61_SPI_USR1_OFFS, + usr2Offs: ESP32C61_SPI_USR2_OFFS, + mosiDlenOffs: ESP32C61_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32C61_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32C61_SPI_W0_OFFS, + uartDateReg: ESP32C61_UART_DATE_REG_ADDR, + flashOffs: ESP32C61_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32H2: + return { + regBase: ESP32H2_SPI_REG_BASE, + baseFuse: ESP32H2_BASEFUSEADDR, + macFuse: ESP32H2_MACFUSEADDR, + usrOffs: ESP32H2_SPI_USR_OFFS, + usr1Offs: ESP32H2_SPI_USR1_OFFS, + usr2Offs: ESP32H2_SPI_USR2_OFFS, + mosiDlenOffs: ESP32H2_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32H2_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32H2_SPI_W0_OFFS, + uartDateReg: ESP32H2_UART_DATE_REG_ADDR, + flashOffs: ESP32H2_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32H4: + return { + regBase: ESP32H4_SPI_REG_BASE, + baseFuse: ESP32H4_BASEFUSEADDR, + macFuse: ESP32H4_MACFUSEADDR, + usrOffs: ESP32H4_SPI_USR_OFFS, + usr1Offs: ESP32H4_SPI_USR1_OFFS, + usr2Offs: ESP32H4_SPI_USR2_OFFS, + mosiDlenOffs: ESP32H4_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32H4_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32H4_SPI_W0_OFFS, + uartDateReg: ESP32H4_UART_DATE_REG_ADDR, + flashOffs: ESP32H4_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32H21: + return { + regBase: ESP32H21_SPI_REG_BASE, + baseFuse: ESP32H21_BASEFUSEADDR, + macFuse: ESP32H21_MACFUSEADDR, + usrOffs: ESP32H21_SPI_USR_OFFS, + usr1Offs: ESP32H21_SPI_USR1_OFFS, + usr2Offs: ESP32H21_SPI_USR2_OFFS, + mosiDlenOffs: ESP32H21_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32H21_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32H21_SPI_W0_OFFS, + uartDateReg: ESP32H21_UART_DATE_REG_ADDR, + flashOffs: ESP32H21_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32P4: + return { + regBase: ESP32P4_SPI_REG_BASE, + baseFuse: ESP32P4_BASEFUSEADDR, + macFuse: ESP32P4_MACFUSEADDR, + usrOffs: ESP32P4_SPI_USR_OFFS, + usr1Offs: ESP32P4_SPI_USR1_OFFS, + usr2Offs: ESP32P4_SPI_USR2_OFFS, + mosiDlenOffs: ESP32P4_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32P4_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32P4_SPI_W0_OFFS, + uartDateReg: ESP32P4_UART_DATE_REG_ADDR, + flashOffs: ESP32P4_BOOTLOADER_FLASH_OFFSET, + }; + case CHIP_FAMILY_ESP32S31: + return { + regBase: ESP32S31_SPI_REG_BASE, + baseFuse: ESP32S31_BASEFUSEADDR, + macFuse: ESP32S31_MACFUSEADDR, + usrOffs: ESP32S31_SPI_USR_OFFS, + usr1Offs: ESP32S31_SPI_USR1_OFFS, + usr2Offs: ESP32S31_SPI_USR2_OFFS, + mosiDlenOffs: ESP32S31_SPI_MOSI_DLEN_OFFS, + misoDlenOffs: ESP32S31_SPI_MISO_DLEN_OFFS, + w0Offs: ESP32S31_SPI_W0_OFFS, + uartDateReg: ESP32S31_UART_DATE_REG_ADDR, + flashOffs: ESP32S31_BOOTLOADER_FLASH_OFFSET, + }; + default: + return { + regBase: -1, + baseFuse: -1, + macFuse: -1, + usrOffs: -1, + usr1Offs: -1, + usr2Offs: -1, + mosiDlenOffs: -1, + misoDlenOffs: -1, + w0Offs: -1, + uartDateReg: -1, + flashOffs: -1, + }; + } +}; +class SlipReadError extends Error { + constructor(message) { + super(message); + this.name = "SlipReadError"; + } +} + +const getStubCode = async (chipFamily, chipRevision) => { + let stubcode; + // Chips without stub support yet + if (chipFamily == CHIP_FAMILY_ESP32H4 || + chipFamily == CHIP_FAMILY_ESP32H21 || + chipFamily == CHIP_FAMILY_ESP32S31) { + return null; + } + if (chipFamily == CHIP_FAMILY_ESP32) { + stubcode = await import('./esp32-BL5RXAvE.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP32S2) { + stubcode = await import('./esp32s2-t0j-Iiag.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP32S3) { + stubcode = await import('./esp32s3-B8l06aKE.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP8266) { + stubcode = await import('./esp8266-nEkNAo8K.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP32C2) { + stubcode = await import('./esp32c2-JZd7VMTK.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP32C3) { + stubcode = await import('./esp32c3--2RgnV8f.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP32C5) { + stubcode = await import('./esp32c5-D7Zxncy7.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP32C6) { + stubcode = await import('./esp32c6-B8dieLFx.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP32C61) { + stubcode = await import('./esp32c61-CVOVhUkw.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP32H2) { + stubcode = await import('./esp32h2-C7Y4kn-J.js'); + } + else if (chipFamily == CHIP_FAMILY_ESP32P4) { + // ESP32-P4: Use esp32p4r3.json for Rev. 300+, esp32p4.json for older revisions + if (chipRevision !== null && chipRevision !== undefined && chipRevision >= 300) { + stubcode = await import('./esp32p4r3-CW9u2O6_.js'); + } + else { + stubcode = await import('./esp32p4-BN3KBRYS.js'); + } + } + else { + // Unknown chip family - no stub available + return null; + } + // Base64 decode the text and data + return { + ...stubcode, + text: toByteArray(atob(stubcode.text)), + data: toByteArray(atob(stubcode.data)), + }; +}; + +const FLASH_MANUFACTURERS = { + 0xef: "Winbond", + 0xc8: "GigaDevice", + 0x9d: "ISSI", + 0xc2: "Macronix/MXIC", + 0x20: "XMC / Micron", + 0x1c: "EON", + 0x85: "Puya", + 0x68: "BOYA", + 0xa1: "Fudan Microelectronics (FM)", + 0x01: "Spansion/Cypress", + 0x5e: "Zbit", + 0x37: "AMIC", + 0xe0: "Berg Micro", +}; +const FLASH_DEVICES = { + 0x010219: "S25FL256S (256Mbit)", + 0x014015: "S25FL016K (16Mbit)", + 0x014016: "S25FL032K (32Mbit)", + 0x016017: "S25FL064L (64Mbit)", + 0x016018: "S25FL128L (128Mbit)", + 0x1c3013: "EN25Q40 (4Mbit)", + 0x1c3014: "EN25Q80A (8Mbit)", + 0x1c3015: "EN25Q16 (16Mbit)", + 0x1c3016: "EN25Q32B (32Mbit)", + 0x1c3017: "EN25Q64 (64Mbit)", + 0x1c3018: "EN25Q128 (128Mbit)", + 0x1c7015: "EN25QH16 (16Mbit)", + 0x1c7016: "EN25QH32 (32Mbit)", + 0x1c7017: "EN25QH64 (64Mbit)", + 0x1c7018: "EN25QH128 (128Mbit)", + 0x204015: "XM25QH16C (16Mbit)", + 0x204016: "XM25QH32B (32Mbit)", + 0x204017: "XM25QH64C (64Mbit)", + 0x204018: "XM25QH128C (128Mbit)", + 0x204019: "XM25QH256C (256Mbit)", + 0x204119: "XM25QU256C (256Mbit)", + 0x207017: "XM25QH64A (64Mbit)", + 0x207018: "XM25QH128A (128Mbit)", + 0x20ba16: "N25Q032A (32Mbit)", + 0x20ba17: "N25Q064A (64Mbit)", + 0x20ba18: "N25Q128A (128Mbit)", + 0x20bb15: "N25Q016A (16Mbit)", + 0x372015: "A25L016 (16Mbit)", + 0x372016: "A25L032 (32Mbit)", + 0x374016: "A25LQ032 (32Mbit)", + 0x5e4015: "ZB25VQ16 (16Mbit)", + 0x5e4016: "ZB25VQ32 (32Mbit)", + 0x5e4017: "ZB25VQ64 (64Mbit)", + 0x5e4018: "ZB25VQ128 (128Mbit)", + 0x684015: "BY25Q16 (16Mbit)", + 0x684016: "BY25Q32 (32Mbit)", + 0x684017: "BY25Q64 (64Mbit)", + 0x684018: "BY25Q128 (128Mbit)", + 0x856015: "P25Q16H (16Mbit)", + 0x856016: "P25Q32H (32Mbit)", + 0x856017: "P25Q64H (64Mbit)", + 0x856018: "P25Q128H (128Mbit)", + 0x9d6015: "IS25LP016 (16Mbit)", + 0x9d6016: "IS25LP032 (32Mbit)", + 0x9d6017: "IS25LP064 (64Mbit)", + 0x9d6018: "IS25LP128 (128Mbit)", + 0x9d6019: "IS25LP256 (256Mbit)", + 0x9d7015: "IS25WP016 (16Mbit)", + 0x9d7016: "IS25WP032 (32Mbit)", + 0x9d7017: "IS25WP064 (64Mbit)", + 0x9d7018: "IS25WP128 (128Mbit)", + 0x9d7019: "IS25WP256 (256Mbit)", + 0xa14014: "FM25Q08 (8Mbit)", + 0xa14015: "FM25Q16 (16Mbit)", + 0xa14016: "FM25Q32 (32Mbit)", + 0xa14017: "FM25Q64 (64Mbit)", + 0xa14018: "FM25Q128 (128Mbit)", + 0xc22010: "MX25L512E (512Kbit)", + 0xc22011: "MX25L1005C (1Mbit)", + 0xc22012: "MX25L2005C (2Mbit)", + 0xc22013: "MX25L4005 (4Mbit)", + 0xc22014: "MX25L8005 (8Mbit)", + 0xc22015: "MX25L1605D (16Mbit)", + 0xc22016: "MX25L3205D (32Mbit)", + 0xc22017: "MX25L6405D (64Mbit)", + 0xc22018: "MX25L12805D (128Mbit)", + 0xc22019: "MX25L25635E (256Mbit)", + 0xc2201a: "MX25L51245G (512Mbit)", + 0xc25e16: "MX25L3233F (32Mbit)", + 0xc84011: "GD25Q10 (1Mbit)", + 0xc84012: "GD25Q20 (2Mbit)", + 0xc84013: "GD25Q40 (4Mbit)", + 0xc84014: "GD25Q80 (8Mbit)", + 0xc84015: "GD25Q16 (16Mbit)", + 0xc84016: "GD25Q32 (32Mbit)", + 0xc84017: "GD25Q64 (64Mbit)", + 0xc84018: "GD25Q127C (128Mbit)", + 0xc84019: "GD25Q256 (256Mbit)", + 0xc84020: "GD25Q512 (512Mbit)", + 0xc86019: "GD25LQ256D (256Mbit)", + 0xe04015: "BG25Q16A (16Mbit)", + 0xe04016: "BG25Q32 (32Mbit)", + 0xe04017: "BG25Q64 (64Mbit)", + 0xe04018: "BG25Q128 (128Mbit)", + 0xef4014: "W25Q80 (8Mbit)", + 0xef4015: "W25Q16 (16Mbit)", + 0xef4016: "W25Q32 (32Mbit)", + 0xef4017: "W25Q64 (64Mbit)", + 0xef4018: "W25Q128 (128Mbit)", + 0xef4019: "W25Q256 (256Mbit)", + 0xef4020: "W25Q512JV (512Mbit)", + 0xef5012: "W25Q20BW (2Mbit)", + 0xef5013: "W25Q40BW (4Mbit)", + 0xef6011: "W25Q10EW (1Mbit)", + 0xef6012: "W25Q20EW (2Mbit)", + 0xef6013: "W25Q40EW (4Mbit)", +}; + +/*! pako 2.1.0 https://github.com/nodeca/pako @license (MIT AND Zlib) */ +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +/* eslint-disable space-unary-ops */ + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +//const Z_FILTERED = 1; +//const Z_HUFFMAN_ONLY = 2; +//const Z_RLE = 3; +const Z_FIXED$1 = 4; +//const Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ +const Z_BINARY = 0; +const Z_TEXT = 1; +//const Z_ASCII = 1; // = Z_TEXT +const Z_UNKNOWN$1 = 2; + +/*============================================================================*/ + + +function zero$1(buf) { let len = buf.length; while (--len >= 0) { buf[len] = 0; } } + +// From zutil.h + +const STORED_BLOCK = 0; +const STATIC_TREES = 1; +const DYN_TREES = 2; +/* The three kinds of block type */ + +const MIN_MATCH$1 = 3; +const MAX_MATCH$1 = 258; +/* The minimum and maximum match lengths */ + +// From deflate.h +/* =========================================================================== + * Internal compression state. + */ + +const LENGTH_CODES$1 = 29; +/* number of length codes, not counting the special END_BLOCK code */ + +const LITERALS$1 = 256; +/* number of literal bytes 0..255 */ + +const L_CODES$1 = LITERALS$1 + 1 + LENGTH_CODES$1; +/* number of Literal or Length codes, including the END_BLOCK code */ + +const D_CODES$1 = 30; +/* number of distance codes */ + +const BL_CODES$1 = 19; +/* number of codes used to transfer the bit lengths */ + +const HEAP_SIZE$1 = 2 * L_CODES$1 + 1; +/* maximum heap size */ + +const MAX_BITS$1 = 15; +/* All codes must not exceed MAX_BITS bits */ + +const Buf_size = 16; +/* size of bit buffer in bi_buf */ + + +/* =========================================================================== + * Constants + */ + +const MAX_BL_BITS = 7; +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +const END_BLOCK = 256; +/* end of block literal code */ + +const REP_3_6 = 16; +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +const REPZ_3_10 = 17; +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +const REPZ_11_138 = 18; +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +/* eslint-disable comma-spacing,array-bracket-spacing */ +const extra_lbits = /* extra bits for each length code */ + new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]); + +const extra_dbits = /* extra bits for each distance code */ + new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]); + +const extra_blbits = /* extra bits for each bit length code */ + new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]); + +const bl_order = + new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]); +/* eslint-enable comma-spacing,array-bracket-spacing */ + +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +// We pre-fill arrays with 0 to avoid uninitialized gaps + +const DIST_CODE_LEN = 512; /* see definition of array dist_code below */ + +// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1 +const static_ltree = new Array((L_CODES$1 + 2) * 2); +zero$1(static_ltree); +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +const static_dtree = new Array(D_CODES$1 * 2); +zero$1(static_dtree); +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +const _dist_code = new Array(DIST_CODE_LEN); +zero$1(_dist_code); +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +const _length_code = new Array(MAX_MATCH$1 - MIN_MATCH$1 + 1); +zero$1(_length_code); +/* length code for each normalized match length (0 == MIN_MATCH) */ + +const base_length = new Array(LENGTH_CODES$1); +zero$1(base_length); +/* First normalized length for each code (0 = MIN_MATCH) */ + +const base_dist = new Array(D_CODES$1); +zero$1(base_dist); +/* First normalized distance for each code (0 = distance of 1) */ + + +function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) { + + this.static_tree = static_tree; /* static tree or NULL */ + this.extra_bits = extra_bits; /* extra bits for each code or NULL */ + this.extra_base = extra_base; /* base index for extra_bits */ + this.elems = elems; /* max number of elements in the tree */ + this.max_length = max_length; /* max bit length for the codes */ + + // show if `static_tree` has data or dummy - needed for monomorphic objects + this.has_stree = static_tree && static_tree.length; +} + + +let static_l_desc; +let static_d_desc; +let static_bl_desc; + + +function TreeDesc(dyn_tree, stat_desc) { + this.dyn_tree = dyn_tree; /* the dynamic tree */ + this.max_code = 0; /* largest code with non zero frequency */ + this.stat_desc = stat_desc; /* the corresponding static tree */ +} + + + +const d_code = (dist) => { + + return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; +}; + + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +const put_short = (s, w) => { +// put_byte(s, (uch)((w) & 0xff)); +// put_byte(s, (uch)((ush)(w) >> 8)); + s.pending_buf[s.pending++] = (w) & 0xff; + s.pending_buf[s.pending++] = (w >>> 8) & 0xff; +}; + + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +const send_bits = (s, value, length) => { + + if (s.bi_valid > (Buf_size - length)) { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + put_short(s, s.bi_buf); + s.bi_buf = value >> (Buf_size - s.bi_valid); + s.bi_valid += length - Buf_size; + } else { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + s.bi_valid += length; + } +}; + + +const send_code = (s, c, tree) => { + + send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/); +}; + + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +const bi_reverse = (code, len) => { + + let res = 0; + do { + res |= code & 1; + code >>>= 1; + res <<= 1; + } while (--len > 0); + return res >>> 1; +}; + + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +const bi_flush = (s) => { + + if (s.bi_valid === 16) { + put_short(s, s.bi_buf); + s.bi_buf = 0; + s.bi_valid = 0; + + } else if (s.bi_valid >= 8) { + s.pending_buf[s.pending++] = s.bi_buf & 0xff; + s.bi_buf >>= 8; + s.bi_valid -= 8; + } +}; + + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +const gen_bitlen = (s, desc) => { +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ + + const tree = desc.dyn_tree; + const max_code = desc.max_code; + const stree = desc.stat_desc.static_tree; + const has_stree = desc.stat_desc.has_stree; + const extra = desc.stat_desc.extra_bits; + const base = desc.stat_desc.extra_base; + const max_length = desc.stat_desc.max_length; + let h; /* heap index */ + let n, m; /* iterate over the tree elements */ + let bits; /* bit length */ + let xbits; /* extra bits */ + let f; /* frequency */ + let overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS$1; bits++) { + s.bl_count[bits] = 0; + } + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */ + + for (h = s.heap_max + 1; h < HEAP_SIZE$1; h++) { + n = s.heap[h]; + bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; + if (bits > max_length) { + bits = max_length; + overflow++; + } + tree[n * 2 + 1]/*.Len*/ = bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) { continue; } /* not a leaf node */ + + s.bl_count[bits]++; + xbits = 0; + if (n >= base) { + xbits = extra[n - base]; + } + f = tree[n * 2]/*.Freq*/; + s.opt_len += f * (bits + xbits); + if (has_stree) { + s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits); + } + } + if (overflow === 0) { return; } + + // Tracev((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length - 1; + while (s.bl_count[bits] === 0) { bits--; } + s.bl_count[bits]--; /* move one leaf down the tree */ + s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + s.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits !== 0; bits--) { + n = s.bl_count[bits]; + while (n !== 0) { + m = s.heap[--h]; + if (m > max_code) { continue; } + if (tree[m * 2 + 1]/*.Len*/ !== bits) { + // Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/; + tree[m * 2 + 1]/*.Len*/ = bits; + } + n--; + } + } +}; + + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +const gen_codes = (tree, max_code, bl_count) => { +// ct_data *tree; /* the tree to decorate */ +// int max_code; /* largest code with non zero frequency */ +// ushf *bl_count; /* number of codes at each bit length */ + + const next_code = new Array(MAX_BITS$1 + 1); /* next code value for each bit length */ + let code = 0; /* running code value */ + let bits; /* bit index */ + let n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS$1; bits++) { + code = (code + bl_count[bits - 1]) << 1; + next_code[bits] = code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + //Assert (code + bl_count[MAX_BITS]-1 == (1< { + + let n; /* iterates over tree elements */ + let bits; /* bit counter */ + let length; /* length value */ + let code; /* code value */ + let dist; /* distance index */ + const bl_count = new Array(MAX_BITS$1 + 1); + /* number of codes at each bit length for an optimal tree */ + + // do check in _tr_init() + //if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +/*#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif*/ + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES$1 - 1; code++) { + base_length[code] = length; + for (n = 0; n < (1 << extra_lbits[code]); n++) { + _length_code[length++] = code; + } + } + //Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length - 1] = code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1 << extra_dbits[code]); n++) { + _dist_code[dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for (; code < D_CODES$1; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { + _dist_code[256 + dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS$1; bits++) { + bl_count[bits] = 0; + } + + n = 0; + while (n <= 143) { + static_ltree[n * 2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + while (n <= 255) { + static_ltree[n * 2 + 1]/*.Len*/ = 9; + n++; + bl_count[9]++; + } + while (n <= 279) { + static_ltree[n * 2 + 1]/*.Len*/ = 7; + n++; + bl_count[7]++; + } + while (n <= 287) { + static_ltree[n * 2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes(static_ltree, L_CODES$1 + 1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES$1; n++) { + static_dtree[n * 2 + 1]/*.Len*/ = 5; + static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5); + } + + // Now data ready and we can init static trees + static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS$1 + 1, L_CODES$1, MAX_BITS$1); + static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES$1, MAX_BITS$1); + static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES$1, MAX_BL_BITS); + + //static_init_done = true; +}; + + +/* =========================================================================== + * Initialize a new block. + */ +const init_block = (s) => { + + let n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES$1; n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; } + for (n = 0; n < D_CODES$1; n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; } + for (n = 0; n < BL_CODES$1; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; } + + s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1; + s.opt_len = s.static_len = 0; + s.sym_next = s.matches = 0; +}; + + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +const bi_windup = (s) => +{ + if (s.bi_valid > 8) { + put_short(s, s.bi_buf); + } else if (s.bi_valid > 0) { + //put_byte(s, (Byte)s->bi_buf); + s.pending_buf[s.pending++] = s.bi_buf; + } + s.bi_buf = 0; + s.bi_valid = 0; +}; + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +const smaller = (tree, n, m, depth) => { + + const _n2 = n * 2; + const _m2 = m * 2; + return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || + (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); +}; + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +const pqdownheap = (s, tree, k) => { +// deflate_state *s; +// ct_data *tree; /* the tree to restore */ +// int k; /* node to move down */ + + const v = s.heap[k]; + let j = k << 1; /* left son of k */ + while (j <= s.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s.heap_len && + smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s.heap[j], s.depth)) { break; } + + /* Exchange v with the smallest son */ + s.heap[k] = s.heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s.heap[k] = v; +}; + + +// inlined manually +// const SMALLEST = 1; + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +const compress_block = (s, ltree, dtree) => { +// deflate_state *s; +// const ct_data *ltree; /* literal tree */ +// const ct_data *dtree; /* distance tree */ + + let dist; /* distance of matched string */ + let lc; /* match length or unmatched char (if dist == 0) */ + let sx = 0; /* running index in sym_buf */ + let code; /* the code to send */ + let extra; /* number of extra bits to send */ + + if (s.sym_next !== 0) { + do { + dist = s.pending_buf[s.sym_buf + sx++] & 0xff; + dist += (s.pending_buf[s.sym_buf + sx++] & 0xff) << 8; + lc = s.pending_buf[s.sym_buf + sx++]; + if (dist === 0) { + send_code(s, lc, ltree); /* send a literal byte */ + //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS$1 + 1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra !== 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + //Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra !== 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and sym_buf is ok: */ + //Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); + + } while (sx < s.sym_next); + } + + send_code(s, END_BLOCK, ltree); +}; + + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +const build_tree = (s, desc) => { +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ + + const tree = desc.dyn_tree; + const stree = desc.stat_desc.static_tree; + const has_stree = desc.stat_desc.has_stree; + const elems = desc.stat_desc.elems; + let n, m; /* iterate over heap elements */ + let max_code = -1; /* largest code with non zero frequency */ + let node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s.heap_len = 0; + s.heap_max = HEAP_SIZE$1; + + for (n = 0; n < elems; n++) { + if (tree[n * 2]/*.Freq*/ !== 0) { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; + + } else { + tree[n * 2 + 1]/*.Len*/ = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s.heap_len < 2) { + node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); + tree[node * 2]/*.Freq*/ = 1; + s.depth[node] = 0; + s.opt_len--; + + if (has_stree) { + s.static_len -= stree[node * 2 + 1]/*.Len*/; + } + /* node is 0 or 1 so it does not have extra bits */ + } + desc.max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + //pqremove(s, tree, n); /* n = node of least frequency */ + /*** pqremove ***/ + n = s.heap[1/*SMALLEST*/]; + s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; + pqdownheap(s, tree, 1/*SMALLEST*/); + /***/ + + m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ + + s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ + s.heap[--s.heap_max] = m; + + /* Create a new node father of n and m */ + tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; + s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; + tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node; + + /* and insert the new node in the heap */ + s.heap[1/*SMALLEST*/] = node++; + pqdownheap(s, tree, 1/*SMALLEST*/); + + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes(tree, max_code, s.bl_count); +}; + + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +const scan_tree = (s, tree, max_code) => { +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ + + let n; /* iterates over all tree elements */ + let prevlen = -1; /* last emitted length */ + let curlen; /* length of current code */ + + let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ + + let count = 0; /* repeat count of the current code */ + let max_count = 7; /* max repeat count */ + let min_count = 4; /* min repeat count */ + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + s.bl_tree[curlen * 2]/*.Freq*/ += count; + + } else if (curlen !== 0) { + + if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } + s.bl_tree[REP_3_6 * 2]/*.Freq*/++; + + } else if (count <= 10) { + s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++; + + } else { + s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++; + } + + count = 0; + prevlen = curlen; + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +}; + + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +const send_tree = (s, tree, max_code) => { +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ + + let n; /* iterates over all tree elements */ + let prevlen = -1; /* last emitted length */ + let curlen; /* length of current code */ + + let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ + + let count = 0; /* repeat count of the current code */ + let max_count = 7; /* max repeat count */ + let min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); + + } else if (curlen !== 0) { + if (curlen !== prevlen) { + send_code(s, curlen, s.bl_tree); + count--; + } + //Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s.bl_tree); + send_bits(s, count - 3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s.bl_tree); + send_bits(s, count - 3, 3); + + } else { + send_code(s, REPZ_11_138, s.bl_tree); + send_bits(s, count - 11, 7); + } + + count = 0; + prevlen = curlen; + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +}; + + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +const build_bl_tree = (s) => { + + let max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, s.dyn_ltree, s.l_desc.max_code); + scan_tree(s, s.dyn_dtree, s.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, s.bl_desc); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES$1 - 1; max_blindex >= 3; max_blindex--) { + if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) { + break; + } + } + /* Update opt_len to include the bit length tree and counts */ + s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; + //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + // s->opt_len, s->static_len)); + + return max_blindex; +}; + + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +const send_all_trees = (s, lcodes, dcodes, blcodes) => { +// deflate_state *s; +// int lcodes, dcodes, blcodes; /* number of codes for each tree */ + + let rank; /* index in bl_order */ + + //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + // "too many codes"); + //Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3); + } + //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */ + //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */ + //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +}; + + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "block list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +const detect_data_type = (s) => { + /* block_mask is the bit mask of block-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + let block_mask = 0xf3ffc07f; + let n; + + /* Check for non-textual ("block-listed") bytes. */ + for (n = 0; n <= 31; n++, block_mask >>>= 1) { + if ((block_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) { + return Z_BINARY; + } + } + + /* Check for textual ("allow-listed") bytes. */ + if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || + s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + for (n = 32; n < LITERALS$1; n++) { + if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + } + + /* There are no "block-listed" or "allow-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +}; + + +let static_init_done = false; + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +const _tr_init$1 = (s) => +{ + + if (!static_init_done) { + tr_static_init(); + static_init_done = true; + } + + s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); + s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); + s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); + + s.bi_buf = 0; + s.bi_valid = 0; + + /* Initialize the first block of the first file: */ + init_block(s); +}; + + +/* =========================================================================== + * Send a stored block + */ +const _tr_stored_block$1 = (s, buf, stored_len, last) => { +//DeflateState *s; +//charf *buf; /* input block */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ + + send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */ + bi_windup(s); /* align on byte boundary */ + put_short(s, stored_len); + put_short(s, ~stored_len); + if (stored_len) { + s.pending_buf.set(s.window.subarray(buf, buf + stored_len), s.pending); + } + s.pending += stored_len; +}; + + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +const _tr_align$1 = (s) => { + send_bits(s, STATIC_TREES << 1, 3); + send_code(s, END_BLOCK, static_ltree); + bi_flush(s); +}; + + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and write out the encoded block. + */ +const _tr_flush_block$1 = (s, buf, stored_len, last) => { +//DeflateState *s; +//charf *buf; /* input block, or NULL if too old */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ + + let opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + let max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s.level > 0) { + + /* Check if the file is binary or text */ + if (s.strm.data_type === Z_UNKNOWN$1) { + s.strm.data_type = detect_data_type(s); + } + + /* Construct the literal and distance trees */ + build_tree(s, s.l_desc); + // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + + build_tree(s, s.d_desc); + // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s.opt_len + 3 + 7) >>> 3; + static_lenb = (s.static_len + 3 + 7) >>> 3; + + // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + // s->sym_next / 3)); + + if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } + + } else { + // Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) { + /* 4: two words for the lengths */ + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block$1(s, buf, stored_len, last); + + } else if (s.strategy === Z_FIXED$1 || static_lenb === opt_lenb) { + + send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3); + compress_block(s, static_ltree, static_dtree); + + } else { + send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); + send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); + compress_block(s, s.dyn_ltree, s.dyn_dtree); + } + // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); + } + // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + // s->compressed_len-7*last)); +}; + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +const _tr_tally$1 = (s, dist, lc) => { +// deflate_state *s; +// unsigned dist; /* distance of matched string */ +// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ + + s.pending_buf[s.sym_buf + s.sym_next++] = dist; + s.pending_buf[s.sym_buf + s.sym_next++] = dist >> 8; + s.pending_buf[s.sym_buf + s.sym_next++] = lc; + if (dist === 0) { + /* lc is the unmatched char */ + s.dyn_ltree[lc * 2]/*.Freq*/++; + } else { + s.matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + //Assert((ush)dist < (ush)MAX_DIST(s) && + // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s.dyn_ltree[(_length_code[lc] + LITERALS$1 + 1) * 2]/*.Freq*/++; + s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; + } + + return (s.sym_next === s.sym_end); +}; + +var _tr_init_1 = _tr_init$1; +var _tr_stored_block_1 = _tr_stored_block$1; +var _tr_flush_block_1 = _tr_flush_block$1; +var _tr_tally_1 = _tr_tally$1; +var _tr_align_1 = _tr_align$1; + +var trees = { + _tr_init: _tr_init_1, + _tr_stored_block: _tr_stored_block_1, + _tr_flush_block: _tr_flush_block_1, + _tr_tally: _tr_tally_1, + _tr_align: _tr_align_1 +}; + +// Note: adler32 takes 12% for level 0 and 2% for level 6. +// It isn't worth it to make additional optimizations as in original. +// Small size is preferable. + +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +const adler32 = (adler, buf, len, pos) => { + let s1 = (adler & 0xffff) |0, + s2 = ((adler >>> 16) & 0xffff) |0, + n = 0; + + while (len !== 0) { + // Set limit ~ twice less than 5552, to keep + // s2 in 31-bits, because we force signed ints. + // in other case %= will fail. + n = len > 2000 ? 2000 : len; + len -= n; + + do { + s1 = (s1 + buf[pos++]) |0; + s2 = (s2 + s1) |0; + } while (--n); + + s1 %= 65521; + s2 %= 65521; + } + + return (s1 | (s2 << 16)) |0; +}; + + +var adler32_1 = adler32; + +// Note: we can't get significant speed boost here. +// So write code to minimize size - no pregenerated tables +// and array tools dependencies. + +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +// Use ordinary array, since untyped makes no boost here +const makeTable = () => { + let c, table = []; + + for (var n = 0; n < 256; n++) { + c = n; + for (var k = 0; k < 8; k++) { + c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); + } + table[n] = c; + } + + return table; +}; + +// Create table on load. Just 255 signed longs. Not a problem. +const crcTable = new Uint32Array(makeTable()); + + +const crc32 = (crc, buf, len, pos) => { + const t = crcTable; + const end = pos + len; + + crc ^= -1; + + for (let i = pos; i < end; i++) { + crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; + } + + return (crc ^ (-1)); // >>> 0; +}; + + +var crc32_1 = crc32; + +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +var messages = { + 2: 'need dictionary', /* Z_NEED_DICT 2 */ + 1: 'stream end', /* Z_STREAM_END 1 */ + 0: '', /* Z_OK 0 */ + '-1': 'file error', /* Z_ERRNO (-1) */ + '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ + '-3': 'data error', /* Z_DATA_ERROR (-3) */ + '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ + '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ + '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ +}; + +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +var constants$2 = { + + /* Allowed flush values; see deflate() and inflate() below for details */ + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + /* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + Z_OK: 0, + Z_STREAM_END: 1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + Z_BUF_ERROR: -5, + Z_DEFAULT_COMPRESSION: -1, + + + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + + //Z_ASCII: 1, // = Z_TEXT (deprecated) + Z_UNKNOWN: 2, + + /* The deflate compression method */ + Z_DEFLATED: 8 + //Z_NULL: null // Use -1 or null inline, depending on var type +}; + +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +const { _tr_init, _tr_stored_block, _tr_flush_block, _tr_tally, _tr_align } = trees; + + + + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + +const { + Z_NO_FLUSH: Z_NO_FLUSH$2, Z_PARTIAL_FLUSH, Z_FULL_FLUSH: Z_FULL_FLUSH$1, Z_FINISH: Z_FINISH$3, Z_BLOCK: Z_BLOCK$1, + Z_OK: Z_OK$3, Z_STREAM_END: Z_STREAM_END$3, Z_STREAM_ERROR: Z_STREAM_ERROR$2, Z_DATA_ERROR: Z_DATA_ERROR$2, Z_BUF_ERROR: Z_BUF_ERROR$1, + Z_DEFAULT_COMPRESSION: Z_DEFAULT_COMPRESSION$1, + Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED, Z_DEFAULT_STRATEGY: Z_DEFAULT_STRATEGY$1, + Z_UNKNOWN, + Z_DEFLATED: Z_DEFLATED$2 +} = constants$2; + +/*============================================================================*/ + + +const MAX_MEM_LEVEL = 9; +/* Maximum value for memLevel in deflateInit2 */ +const MAX_WBITS$1 = 15; +/* 32K LZ77 window */ +const DEF_MEM_LEVEL = 8; + + +const LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ +const LITERALS = 256; +/* number of literal bytes 0..255 */ +const L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ +const D_CODES = 30; +/* number of distance codes */ +const BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ +const HEAP_SIZE = 2 * L_CODES + 1; +/* maximum heap size */ +const MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +const MIN_MATCH = 3; +const MAX_MATCH = 258; +const MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); + +const PRESET_DICT = 0x20; + +const INIT_STATE = 42; /* zlib header -> BUSY_STATE */ +//#ifdef GZIP +const GZIP_STATE = 57; /* gzip header -> BUSY_STATE | EXTRA_STATE */ +//#endif +const EXTRA_STATE = 69; /* gzip extra block -> NAME_STATE */ +const NAME_STATE = 73; /* gzip file name -> COMMENT_STATE */ +const COMMENT_STATE = 91; /* gzip comment -> HCRC_STATE */ +const HCRC_STATE = 103; /* gzip header CRC -> BUSY_STATE */ +const BUSY_STATE = 113; /* deflate -> FINISH_STATE */ +const FINISH_STATE = 666; /* stream complete */ + +const BS_NEED_MORE = 1; /* block not completed, need more input or more output */ +const BS_BLOCK_DONE = 2; /* block flush performed */ +const BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ +const BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ + +const OS_CODE = 0x03; // Unix :) . Don't detect, use this default. + +const err = (strm, errorCode) => { + strm.msg = messages[errorCode]; + return errorCode; +}; + +const rank = (f) => { + return ((f) * 2) - ((f) > 4 ? 9 : 0); +}; + +const zero = (buf) => { + let len = buf.length; while (--len >= 0) { buf[len] = 0; } +}; + +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +const slide_hash = (s) => { + let n, m; + let p; + let wsize = s.w_size; + + n = s.hash_size; + p = n; + do { + m = s.head[--p]; + s.head[p] = (m >= wsize ? m - wsize : 0); + } while (--n); + n = wsize; +//#ifndef FASTEST + p = n; + do { + m = s.prev[--p]; + s.prev[p] = (m >= wsize ? m - wsize : 0); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +//#endif +}; + +/* eslint-disable new-cap */ +let HASH_ZLIB = (s, prev, data) => ((prev << s.hash_shift) ^ data) & s.hash_mask; +// This hash causes less collisions, https://github.com/nodeca/pako/issues/135 +// But breaks binary compatibility +//let HASH_FAST = (s, prev, data) => ((prev << 8) + (prev >> 8) + (data << 4)) & s.hash_mask; +let HASH = HASH_ZLIB; + + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also read_buf()). + */ +const flush_pending = (strm) => { + const s = strm.state; + + //_tr_flush_bits(s); + let len = s.pending; + if (len > strm.avail_out) { + len = strm.avail_out; + } + if (len === 0) { return; } + + strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len), strm.next_out); + strm.next_out += len; + s.pending_out += len; + strm.total_out += len; + strm.avail_out -= len; + s.pending -= len; + if (s.pending === 0) { + s.pending_out = 0; + } +}; + + +const flush_block_only = (s, last) => { + _tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); + s.block_start = s.strstart; + flush_pending(s.strm); +}; + + +const put_byte = (s, b) => { + s.pending_buf[s.pending++] = b; +}; + + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +const putShortMSB = (s, b) => { + + // put_byte(s, (Byte)(b >> 8)); +// put_byte(s, (Byte)(b & 0xff)); + s.pending_buf[s.pending++] = (b >>> 8) & 0xff; + s.pending_buf[s.pending++] = b & 0xff; +}; + + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->input buffer and copying from it. + * (See also flush_pending()). + */ +const read_buf = (strm, buf, start, size) => { + + let len = strm.avail_in; + + if (len > size) { len = size; } + if (len === 0) { return 0; } + + strm.avail_in -= len; + + // zmemcpy(buf, strm->next_in, len); + buf.set(strm.input.subarray(strm.next_in, strm.next_in + len), start); + if (strm.state.wrap === 1) { + strm.adler = adler32_1(strm.adler, buf, len, start); + } + + else if (strm.state.wrap === 2) { + strm.adler = crc32_1(strm.adler, buf, len, start); + } + + strm.next_in += len; + strm.total_in += len; + + return len; +}; + + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +const longest_match = (s, cur_match) => { + + let chain_length = s.max_chain_length; /* max hash chain length */ + let scan = s.strstart; /* current string */ + let match; /* matched string */ + let len; /* length of current match */ + let best_len = s.prev_length; /* best match length so far */ + let nice_match = s.nice_match; /* stop if match long enough */ + const limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? + s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; + + const _win = s.window; // shortcut + + const wmask = s.w_mask; + const prev = s.prev; + + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + const strend = s.strstart + MAX_MATCH; + let scan_end1 = _win[scan + best_len - 1]; + let scan_end = _win[scan + best_len]; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s.prev_length >= s.good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if (nice_match > s.lookahead) { nice_match = s.lookahead; } + + // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + // Assert(cur_match < s->strstart, "no future"); + match = cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ + + if (_win[match + best_len] !== scan_end || + _win[match + best_len - 1] !== scan_end1 || + _win[match] !== _win[scan] || + _win[++match] !== _win[scan + 1]) { + continue; + } + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2; + match++; + // Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + /*jshint noempty:false*/ + } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + scan < strend); + + // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) { + s.match_start = cur_match; + best_len = len; + if (len >= nice_match) { + break; + } + scan_end1 = _win[scan + best_len - 1]; + scan_end = _win[scan + best_len]; + } + } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); + + if (best_len <= s.lookahead) { + return best_len; + } + return s.lookahead; +}; + + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +const fill_window = (s) => { + + const _w_size = s.w_size; + let n, more, str; + + //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = s.window_size - s.lookahead - s.strstart; + + // JS ints have 32 bit, block below not needed + /* Deal with !@#$% 64K limit: */ + //if (sizeof(int) <= 2) { + // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + // more = wsize; + // + // } else if (more == (unsigned)(-1)) { + // /* Very unlikely, but possible on 16 bit machine if + // * strstart == 0 && lookahead == 1 (input done a byte at time) + // */ + // more--; + // } + //} + + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { + + s.window.set(s.window.subarray(_w_size, _w_size + _w_size - more), 0); + s.match_start -= _w_size; + s.strstart -= _w_size; + /* we now have strstart >= MAX_DIST */ + s.block_start -= _w_size; + if (s.insert > s.strstart) { + s.insert = s.strstart; + } + slide_hash(s); + more += _w_size; + } + if (s.strm.avail_in === 0) { + break; + } + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + //Assert(more >= 2, "more < 2"); + n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); + s.lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s.lookahead + s.insert >= MIN_MATCH) { + str = s.strstart - s.insert; + s.ins_h = s.window[str]; + + /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[str + 1]); +//#if MIN_MATCH != 3 +// Call update_hash() MIN_MATCH-3 more times +//#endif + while (s.insert) { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]); + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = str; + str++; + s.insert--; + if (s.lookahead + s.insert < MIN_MATCH) { + break; + } + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ +// if (s.high_water < s.window_size) { +// const curr = s.strstart + s.lookahead; +// let init = 0; +// +// if (s.high_water < curr) { +// /* Previous high water mark below current data -- zero WIN_INIT +// * bytes or up to end of window, whichever is less. +// */ +// init = s.window_size - curr; +// if (init > WIN_INIT) +// init = WIN_INIT; +// zmemzero(s->window + curr, (unsigned)init); +// s->high_water = curr + init; +// } +// else if (s->high_water < (ulg)curr + WIN_INIT) { +// /* High water mark at or above current data, but below current data +// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up +// * to end of window, whichever is less. +// */ +// init = (ulg)curr + WIN_INIT - s->high_water; +// if (init > s->window_size - s->high_water) +// init = s->window_size - s->high_water; +// zmemzero(s->window + s->high_water, (unsigned)init); +// s->high_water += init; +// } +// } +// +// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, +// "not enough room for search"); +}; + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunites to have a single copy from next_in to next_out. + */ +const deflate_stored = (s, flush) => { + + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. + */ + let min_block = s.pending_buf_size - 5 > s.w_size ? s.w_size : s.pending_buf_size - 5; + + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + let len, left, have, last = 0; + let used = s.strm.avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. + */ + len = 65535/* MAX_STORED */; /* maximum deflate stored block length */ + have = (s.bi_valid + 42) >> 3; /* number of header bytes */ + if (s.strm.avail_out < have) { /* need room for header */ + break; + } + /* maximum stored block length that will fit in avail_out: */ + have = s.strm.avail_out - have; + left = s.strstart - s.block_start; /* bytes left in window */ + if (len > left + s.strm.avail_in) { + len = left + s.strm.avail_in; /* limit len to the input */ + } + if (len > have) { + len = have; /* limit len to the output */ + } + + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len === 0 && flush !== Z_FINISH$3) || + flush === Z_NO_FLUSH$2 || + len !== left + s.strm.avail_in)) { + break; + } + + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush === Z_FINISH$3 && len === left + s.strm.avail_in ? 1 : 0; + _tr_stored_block(s, 0, 0, last); + + /* Replace the lengths in the dummy stored block with len. */ + s.pending_buf[s.pending - 4] = len; + s.pending_buf[s.pending - 3] = len >> 8; + s.pending_buf[s.pending - 2] = ~len; + s.pending_buf[s.pending - 1] = ~len >> 8; + + /* Write the stored block header bytes. */ + flush_pending(s.strm); + +//#ifdef ZLIB_DEBUG +// /* Update debugging counts for the data about to be copied. */ +// s->compressed_len += len << 3; +// s->bits_sent += len << 3; +//#endif + + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + if (left > len) { + left = len; + } + //zmemcpy(s->strm->next_out, s->window + s->block_start, left); + s.strm.output.set(s.window.subarray(s.block_start, s.block_start + left), s.strm.next_out); + s.strm.next_out += left; + s.strm.avail_out -= left; + s.strm.total_out += left; + s.block_start += left; + len -= left; + } + + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + read_buf(s.strm, s.strm.output, s.strm.next_out, len); + s.strm.next_out += len; + s.strm.avail_out -= len; + s.strm.total_out += len; + } + } while (last === 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s.strm.avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. + */ + if (used >= s.w_size) { /* supplant the previous history */ + s.matches = 2; /* clear hash */ + //zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s.window.set(s.strm.input.subarray(s.strm.next_in - s.w_size, s.strm.next_in), 0); + s.strstart = s.w_size; + s.insert = s.strstart; + } + else { + if (s.window_size - s.strstart <= used) { + /* Slide the window down. */ + s.strstart -= s.w_size; + //zmemcpy(s->window, s->window + s->w_size, s->strstart); + s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0); + if (s.matches < 2) { + s.matches++; /* add a pending slide_hash() */ + } + if (s.insert > s.strstart) { + s.insert = s.strstart; + } + } + //zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); + s.window.set(s.strm.input.subarray(s.strm.next_in - used, s.strm.next_in), s.strstart); + s.strstart += used; + s.insert += used > s.w_size - s.insert ? s.w_size - s.insert : used; + } + s.block_start = s.strstart; + } + if (s.high_water < s.strstart) { + s.high_water = s.strstart; + } + + /* If the last block was written to next_out, then done. */ + if (last) { + return BS_FINISH_DONE; + } + + /* If flushing and all input has been consumed, then done. */ + if (flush !== Z_NO_FLUSH$2 && flush !== Z_FINISH$3 && + s.strm.avail_in === 0 && s.strstart === s.block_start) { + return BS_BLOCK_DONE; + } + + /* Fill the window with any remaining input. */ + have = s.window_size - s.strstart; + if (s.strm.avail_in > have && s.block_start >= s.w_size) { + /* Slide the window down. */ + s.block_start -= s.w_size; + s.strstart -= s.w_size; + //zmemcpy(s->window, s->window + s->w_size, s->strstart); + s.window.set(s.window.subarray(s.w_size, s.w_size + s.strstart), 0); + if (s.matches < 2) { + s.matches++; /* add a pending slide_hash() */ + } + have += s.w_size; /* more space now */ + if (s.insert > s.strstart) { + s.insert = s.strstart; + } + } + if (have > s.strm.avail_in) { + have = s.strm.avail_in; + } + if (have) { + read_buf(s.strm, s.window, s.strstart, have); + s.strstart += have; + s.insert += have > s.w_size - s.insert ? s.w_size - s.insert : have; + } + if (s.high_water < s.strstart) { + s.high_water = s.strstart; + } + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s.bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = s.pending_buf_size - have > 65535/* MAX_STORED */ ? 65535/* MAX_STORED */ : s.pending_buf_size - have; + min_block = have > s.w_size ? s.w_size : have; + left = s.strstart - s.block_start; + if (left >= min_block || + ((left || flush === Z_FINISH$3) && flush !== Z_NO_FLUSH$2 && + s.strm.avail_in === 0 && left <= have)) { + len = left > have ? have : left; + last = flush === Z_FINISH$3 && s.strm.avail_in === 0 && + len === left ? 1 : 0; + _tr_stored_block(s, s.block_start, len, last); + s.block_start += len; + flush_pending(s.strm); + } + + /* We've done all we can with the available input and output. */ + return last ? BS_FINISH_STARTED : BS_NEED_MORE; +}; + + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +const deflate_fast = (s, flush) => { + + let hash_head; /* head of the hash chain */ + let bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { + break; /* flush the current block */ + } + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + } + if (s.match_length >= MIN_MATCH) { + // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only + + /*** _tr_tally_dist(s, s.strstart - s.match_start, + s.match_length - MIN_MATCH, bflush); ***/ + bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { + s.match_length--; /* string at strstart already in table */ + do { + s.strstart++; + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s.match_length !== 0); + s.strstart++; + } else + { + s.strstart += s.match_length; + s.match_length = 0; + s.ins_h = s.window[s.strstart]; + /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + 1]); + +//#if MIN_MATCH != 3 +// Call UPDATE_HASH() MIN_MATCH-3 more times +//#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s.window[s.strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1); + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.sym_next) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +}; + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +const deflate_slow = (s, flush) => { + + let hash_head; /* head of hash chain */ + let bflush; /* set if current block must be flushed */ + + let max_insert; + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + */ + s.prev_length = s.match_length; + s.prev_match = s.match_start; + s.match_length = MIN_MATCH - 1; + + if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && + s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if (s.match_length <= 5 && + (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s.match_length = MIN_MATCH - 1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { + max_insert = s.strstart + s.lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + //check_match(s, s.strstart-1, s.prev_match, s.prev_length); + + /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, + s.prev_length - MIN_MATCH, bflush);***/ + bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s.lookahead -= s.prev_length - 1; + s.prev_length -= 2; + do { + if (++s.strstart <= max_insert) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + } while (--s.prev_length !== 0); + s.match_available = 0; + s.match_length = MIN_MATCH - 1; + s.strstart++; + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + } else if (s.match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); + + if (bflush) { + /*** FLUSH_BLOCK_ONLY(s, 0) ***/ + flush_block_only(s, false); + /***/ + } + s.strstart++; + s.lookahead--; + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s.match_available = 1; + s.strstart++; + s.lookahead--; + } + } + //Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s.match_available) { + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); + + s.match_available = 0; + } + s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.sym_next) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_BLOCK_DONE; +}; + + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +const deflate_rle = (s, flush) => { + + let bflush; /* set if current block must be flushed */ + let prev; /* byte at distance one to match */ + let scan, strend; /* scan goes up to strend for length of run */ + + const _win = s.window; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s.lookahead <= MAX_MATCH) { + fill_window(s); + if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s.match_length = 0; + if (s.lookahead >= MIN_MATCH && s.strstart > 0) { + scan = s.strstart - 1; + prev = _win[scan]; + if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { + strend = s.strstart + MAX_MATCH; + do { + /*jshint noempty:false*/ + } while (prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + scan < strend); + s.match_length = MAX_MATCH - (strend - scan); + if (s.match_length > s.lookahead) { + s.match_length = s.lookahead; + } + } + //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s.match_length >= MIN_MATCH) { + //check_match(s, s.strstart, s.strstart - 1, s.match_length); + + /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ + bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + s.strstart += s.match_length; + s.match_length = 0; + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.sym_next) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +}; + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +const deflate_huff = (s, flush) => { + + let bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s.lookahead === 0) { + fill_window(s); + if (s.lookahead === 0) { + if (flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s.match_length = 0; + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart]); + s.lookahead--; + s.strstart++; + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.sym_next) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +}; + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +function Config(good_length, max_lazy, nice_length, max_chain, func) { + + this.good_length = good_length; + this.max_lazy = max_lazy; + this.nice_length = nice_length; + this.max_chain = max_chain; + this.func = func; +} + +const configuration_table = [ + /* good lazy nice chain */ + new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ + new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ + new Config(4, 5, 16, 8, deflate_fast), /* 2 */ + new Config(4, 6, 32, 32, deflate_fast), /* 3 */ + + new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ + new Config(8, 16, 32, 32, deflate_slow), /* 5 */ + new Config(8, 16, 128, 128, deflate_slow), /* 6 */ + new Config(8, 32, 128, 256, deflate_slow), /* 7 */ + new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ + new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ +]; + + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +const lm_init = (s) => { + + s.window_size = 2 * s.w_size; + + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + + /* Set the default configuration parameters: + */ + s.max_lazy_match = configuration_table[s.level].max_lazy; + s.good_match = configuration_table[s.level].good_length; + s.nice_match = configuration_table[s.level].nice_length; + s.max_chain_length = configuration_table[s.level].max_chain; + + s.strstart = 0; + s.block_start = 0; + s.lookahead = 0; + s.insert = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + s.ins_h = 0; +}; + + +function DeflateState() { + this.strm = null; /* pointer back to this zlib stream */ + this.status = 0; /* as the name implies */ + this.pending_buf = null; /* output still pending */ + this.pending_buf_size = 0; /* size of pending_buf */ + this.pending_out = 0; /* next pending byte to output to the stream */ + this.pending = 0; /* nb of bytes in the pending buffer */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.gzhead = null; /* gzip header information to write */ + this.gzindex = 0; /* where in extra, name, or comment */ + this.method = Z_DEFLATED$2; /* can only be DEFLATED */ + this.last_flush = -1; /* value of flush param for previous deflate call */ + + this.w_size = 0; /* LZ77 window size (32K by default) */ + this.w_bits = 0; /* log2(w_size) (8..16) */ + this.w_mask = 0; /* w_size - 1 */ + + this.window = null; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. + */ + + this.window_size = 0; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + this.prev = null; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + this.head = null; /* Heads of the hash chains or NIL. */ + + this.ins_h = 0; /* hash index of string to be inserted */ + this.hash_size = 0; /* number of elements in hash table */ + this.hash_bits = 0; /* log2(hash_size) */ + this.hash_mask = 0; /* hash_size-1 */ + + this.hash_shift = 0; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + this.block_start = 0; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + this.match_length = 0; /* length of best match */ + this.prev_match = 0; /* previous match */ + this.match_available = 0; /* set if previous match exists */ + this.strstart = 0; /* start of string to insert */ + this.match_start = 0; /* start of matching string */ + this.lookahead = 0; /* number of valid bytes ahead in window */ + + this.prev_length = 0; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + this.max_chain_length = 0; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + this.max_lazy_match = 0; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ + // That's alias to max_lazy_match, don't use directly + //this.max_insert_length = 0; + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + this.level = 0; /* compression level (1..9) */ + this.strategy = 0; /* favor or force Huffman coding*/ + + this.good_match = 0; + /* Use a faster search when the previous match is longer than this */ + + this.nice_match = 0; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + + /* Didn't use ct_data typedef below to suppress compiler warning */ + + // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + // Use flat array of DOUBLE size, with interleaved fata, + // because JS does not support effective + this.dyn_ltree = new Uint16Array(HEAP_SIZE * 2); + this.dyn_dtree = new Uint16Array((2 * D_CODES + 1) * 2); + this.bl_tree = new Uint16Array((2 * BL_CODES + 1) * 2); + zero(this.dyn_ltree); + zero(this.dyn_dtree); + zero(this.bl_tree); + + this.l_desc = null; /* desc. for literal tree */ + this.d_desc = null; /* desc. for distance tree */ + this.bl_desc = null; /* desc. for bit length tree */ + + //ush bl_count[MAX_BITS+1]; + this.bl_count = new Uint16Array(MAX_BITS + 1); + /* number of codes at each bit length for an optimal tree */ + + //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + this.heap = new Uint16Array(2 * L_CODES + 1); /* heap used to build the Huffman trees */ + zero(this.heap); + + this.heap_len = 0; /* number of elements in the heap */ + this.heap_max = 0; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + this.depth = new Uint16Array(2 * L_CODES + 1); //uch depth[2*L_CODES+1]; + zero(this.depth); + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + this.sym_buf = 0; /* buffer for distances and literals/lengths */ + + this.lit_bufsize = 0; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + this.sym_next = 0; /* running index in sym_buf */ + this.sym_end = 0; /* symbol table full when sym_next reaches this */ + + this.opt_len = 0; /* bit length of current block with optimal trees */ + this.static_len = 0; /* bit length of current block with static trees */ + this.matches = 0; /* number of string matches in current block */ + this.insert = 0; /* bytes at end of window left to insert */ + + + this.bi_buf = 0; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + this.bi_valid = 0; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + // Used for window memory init. We safely ignore it for JS. That makes + // sense only for pointers and memory check tools. + //this.high_water = 0; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ +} + + +/* ========================================================================= + * Check for a valid deflate stream state. Return 0 if ok, 1 if not. + */ +const deflateStateCheck = (strm) => { + + if (!strm) { + return 1; + } + const s = strm.state; + if (!s || s.strm !== strm || (s.status !== INIT_STATE && +//#ifdef GZIP + s.status !== GZIP_STATE && +//#endif + s.status !== EXTRA_STATE && + s.status !== NAME_STATE && + s.status !== COMMENT_STATE && + s.status !== HCRC_STATE && + s.status !== BUSY_STATE && + s.status !== FINISH_STATE)) { + return 1; + } + return 0; +}; + + +const deflateResetKeep = (strm) => { + + if (deflateStateCheck(strm)) { + return err(strm, Z_STREAM_ERROR$2); + } + + strm.total_in = strm.total_out = 0; + strm.data_type = Z_UNKNOWN; + + const s = strm.state; + s.pending = 0; + s.pending_out = 0; + + if (s.wrap < 0) { + s.wrap = -s.wrap; + /* was made negative by deflate(..., Z_FINISH); */ + } + s.status = +//#ifdef GZIP + s.wrap === 2 ? GZIP_STATE : +//#endif + s.wrap ? INIT_STATE : BUSY_STATE; + strm.adler = (s.wrap === 2) ? + 0 // crc32(0, Z_NULL, 0) + : + 1; // adler32(0, Z_NULL, 0) + s.last_flush = -2; + _tr_init(s); + return Z_OK$3; +}; + + +const deflateReset = (strm) => { + + const ret = deflateResetKeep(strm); + if (ret === Z_OK$3) { + lm_init(strm.state); + } + return ret; +}; + + +const deflateSetHeader = (strm, head) => { + + if (deflateStateCheck(strm) || strm.state.wrap !== 2) { + return Z_STREAM_ERROR$2; + } + strm.state.gzhead = head; + return Z_OK$3; +}; + + +const deflateInit2 = (strm, level, method, windowBits, memLevel, strategy) => { + + if (!strm) { // === Z_NULL + return Z_STREAM_ERROR$2; + } + let wrap = 1; + + if (level === Z_DEFAULT_COMPRESSION$1) { + level = 6; + } + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } + + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } + + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED$2 || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED || (windowBits === 8 && wrap !== 1)) { + return err(strm, Z_STREAM_ERROR$2); + } + + + if (windowBits === 8) { + windowBits = 9; + } + /* until 256-byte window bug fixed */ + + const s = new DeflateState(); + + strm.state = s; + s.strm = strm; + s.status = INIT_STATE; /* to pass state test in deflateReset() */ + + s.wrap = wrap; + s.gzhead = null; + s.w_bits = windowBits; + s.w_size = 1 << s.w_bits; + s.w_mask = s.w_size - 1; + + s.hash_bits = memLevel + 7; + s.hash_size = 1 << s.hash_bits; + s.hash_mask = s.hash_size - 1; + s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); + + s.window = new Uint8Array(s.w_size * 2); + s.head = new Uint16Array(s.hash_size); + s.prev = new Uint16Array(s.w_size); + + // Don't need mem init magic for JS. + //s.high_water = 0; /* nothing written to s->window yet */ + + s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + /* We overlay pending_buf and sym_buf. This works since the average size + * for length/distance pairs over any compressed block is assured to be 31 + * bits or less. + * + * Analysis: The longest fixed codes are a length code of 8 bits plus 5 + * extra bits, for lengths 131 to 257. The longest fixed distance codes are + * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest + * possible fixed-codes length/distance pair is then 31 bits total. + * + * sym_buf starts one-fourth of the way into pending_buf. So there are + * three bytes in sym_buf for every four bytes in pending_buf. Each symbol + * in sym_buf is three bytes -- two for the distance and one for the + * literal/length. As each symbol is consumed, the pointer to the next + * sym_buf value to read moves forward three bytes. From that symbol, up to + * 31 bits are written to pending_buf. The closest the written pending_buf + * bits gets to the next sym_buf symbol to read is just before the last + * code is written. At that time, 31*(n-2) bits have been written, just + * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1 + * symbols are written.) The closest the writing gets to what is unread is + * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and + * can range from 128 to 32768. + * + * Therefore, at a minimum, there are 142 bits of space between what is + * written and what is read in the overlain buffers, so the symbols cannot + * be overwritten by the compressed data. That space is actually 139 bits, + * due to the three-bit fixed-code block header. + * + * That covers the case where either Z_FIXED is specified, forcing fixed + * codes, or when the use of fixed codes is chosen, because that choice + * results in a smaller compressed block than dynamic codes. That latter + * condition then assures that the above analysis also covers all dynamic + * blocks. A dynamic-code block will only be chosen to be emitted if it has + * fewer bits than a fixed-code block would for the same set of symbols. + * Therefore its average symbol length is assured to be less than 31. So + * the compressed data for a dynamic block also cannot overwrite the + * symbols from which it is being constructed. + */ + + s.pending_buf_size = s.lit_bufsize * 4; + s.pending_buf = new Uint8Array(s.pending_buf_size); + + // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`) + //s->sym_buf = s->pending_buf + s->lit_bufsize; + s.sym_buf = s.lit_bufsize; + + //s->sym_end = (s->lit_bufsize - 1) * 3; + s.sym_end = (s.lit_bufsize - 1) * 3; + /* We avoid equality with lit_bufsize*3 because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ + + s.level = level; + s.strategy = strategy; + s.method = method; + + return deflateReset(strm); +}; + +const deflateInit = (strm, level) => { + + return deflateInit2(strm, level, Z_DEFLATED$2, MAX_WBITS$1, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY$1); +}; + + +/* ========================================================================= */ +const deflate$2 = (strm, flush) => { + + if (deflateStateCheck(strm) || flush > Z_BLOCK$1 || flush < 0) { + return strm ? err(strm, Z_STREAM_ERROR$2) : Z_STREAM_ERROR$2; + } + + const s = strm.state; + + if (!strm.output || + (strm.avail_in !== 0 && !strm.input) || + (s.status === FINISH_STATE && flush !== Z_FINISH$3)) { + return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR$1 : Z_STREAM_ERROR$2); + } + + const old_flush = s.last_flush; + s.last_flush = flush; + + /* Flush as much pending output as possible */ + if (s.pending !== 0) { + flush_pending(strm); + if (strm.avail_out === 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s.last_flush = -1; + return Z_OK$3; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && + flush !== Z_FINISH$3) { + return err(strm, Z_BUF_ERROR$1); + } + + /* User must not provide more input after the first FINISH: */ + if (s.status === FINISH_STATE && strm.avail_in !== 0) { + return err(strm, Z_BUF_ERROR$1); + } + + /* Write the header */ + if (s.status === INIT_STATE && s.wrap === 0) { + s.status = BUSY_STATE; + } + if (s.status === INIT_STATE) { + /* zlib header */ + let header = (Z_DEFLATED$2 + ((s.w_bits - 8) << 4)) << 8; + let level_flags = -1; + + if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { + level_flags = 0; + } else if (s.level < 6) { + level_flags = 1; + } else if (s.level === 6) { + level_flags = 2; + } else { + level_flags = 3; + } + header |= (level_flags << 6); + if (s.strstart !== 0) { header |= PRESET_DICT; } + header += 31 - (header % 31); + + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s.strstart !== 0) { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + strm.adler = 1; // adler32(0L, Z_NULL, 0); + s.status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s.pending !== 0) { + s.last_flush = -1; + return Z_OK$3; + } + } +//#ifdef GZIP + if (s.status === GZIP_STATE) { + /* gzip header */ + strm.adler = 0; //crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (!s.gzhead) { // s->gzhead == Z_NULL + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s.status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s.pending !== 0) { + s.last_flush = -1; + return Z_OK$3; + } + } + else { + put_byte(s, (s.gzhead.text ? 1 : 0) + + (s.gzhead.hcrc ? 2 : 0) + + (!s.gzhead.extra ? 0 : 4) + + (!s.gzhead.name ? 0 : 8) + + (!s.gzhead.comment ? 0 : 16) + ); + put_byte(s, s.gzhead.time & 0xff); + put_byte(s, (s.gzhead.time >> 8) & 0xff); + put_byte(s, (s.gzhead.time >> 16) & 0xff); + put_byte(s, (s.gzhead.time >> 24) & 0xff); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, s.gzhead.os & 0xff); + if (s.gzhead.extra && s.gzhead.extra.length) { + put_byte(s, s.gzhead.extra.length & 0xff); + put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); + } + if (s.gzhead.hcrc) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending, 0); + } + s.gzindex = 0; + s.status = EXTRA_STATE; + } + } + if (s.status === EXTRA_STATE) { + if (s.gzhead.extra/* != Z_NULL*/) { + let beg = s.pending; /* start of bytes to update crc */ + let left = (s.gzhead.extra.length & 0xffff) - s.gzindex; + while (s.pending + left > s.pending_buf_size) { + let copy = s.pending_buf_size - s.pending; + // zmemcpy(s.pending_buf + s.pending, + // s.gzhead.extra + s.gzindex, copy); + s.pending_buf.set(s.gzhead.extra.subarray(s.gzindex, s.gzindex + copy), s.pending); + s.pending = s.pending_buf_size; + //--- HCRC_UPDATE(beg) ---// + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + //---// + s.gzindex += copy; + flush_pending(strm); + if (s.pending !== 0) { + s.last_flush = -1; + return Z_OK$3; + } + beg = 0; + left -= copy; + } + // JS specific: s.gzhead.extra may be TypedArray or Array for backward compatibility + // TypedArray.slice and TypedArray.from don't exist in IE10-IE11 + let gzhead_extra = new Uint8Array(s.gzhead.extra); + // zmemcpy(s->pending_buf + s->pending, + // s->gzhead->extra + s->gzindex, left); + s.pending_buf.set(gzhead_extra.subarray(s.gzindex, s.gzindex + left), s.pending); + s.pending += left; + //--- HCRC_UPDATE(beg) ---// + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + //---// + s.gzindex = 0; + } + s.status = NAME_STATE; + } + if (s.status === NAME_STATE) { + if (s.gzhead.name/* != Z_NULL*/) { + let beg = s.pending; /* start of bytes to update crc */ + let val; + do { + if (s.pending === s.pending_buf_size) { + //--- HCRC_UPDATE(beg) ---// + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + //---// + flush_pending(strm); + if (s.pending !== 0) { + s.last_flush = -1; + return Z_OK$3; + } + beg = 0; + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.name.length) { + val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + //--- HCRC_UPDATE(beg) ---// + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + //---// + s.gzindex = 0; + } + s.status = COMMENT_STATE; + } + if (s.status === COMMENT_STATE) { + if (s.gzhead.comment/* != Z_NULL*/) { + let beg = s.pending; /* start of bytes to update crc */ + let val; + do { + if (s.pending === s.pending_buf_size) { + //--- HCRC_UPDATE(beg) ---// + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + //---// + flush_pending(strm); + if (s.pending !== 0) { + s.last_flush = -1; + return Z_OK$3; + } + beg = 0; + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.comment.length) { + val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + //--- HCRC_UPDATE(beg) ---// + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + //---// + } + s.status = HCRC_STATE; + } + if (s.status === HCRC_STATE) { + if (s.gzhead.hcrc) { + if (s.pending + 2 > s.pending_buf_size) { + flush_pending(strm); + if (s.pending !== 0) { + s.last_flush = -1; + return Z_OK$3; + } + } + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + strm.adler = 0; //crc32(0L, Z_NULL, 0); + } + s.status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s.pending !== 0) { + s.last_flush = -1; + return Z_OK$3; + } + } +//#endif + + /* Start a new block or continue the current one. + */ + if (strm.avail_in !== 0 || s.lookahead !== 0 || + (flush !== Z_NO_FLUSH$2 && s.status !== FINISH_STATE)) { + let bstate = s.level === 0 ? deflate_stored(s, flush) : + s.strategy === Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + s.strategy === Z_RLE ? deflate_rle(s, flush) : + configuration_table[s.level].func(s, flush); + + if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { + s.status = FINISH_STATE; + } + if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR next call, see above */ + } + return Z_OK$3; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate === BS_BLOCK_DONE) { + if (flush === Z_PARTIAL_FLUSH) { + _tr_align(s); + } + else if (flush !== Z_BLOCK$1) { /* FULL_FLUSH or SYNC_FLUSH */ + + _tr_stored_block(s, 0, 0, false); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush === Z_FULL_FLUSH$1) { + /*** CLEAR_HASH(s); ***/ /* forget history */ + zero(s.head); // Fill with NIL (= 0); + + if (s.lookahead === 0) { + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + } + } + flush_pending(strm); + if (strm.avail_out === 0) { + s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK$3; + } + } + } + + if (flush !== Z_FINISH$3) { return Z_OK$3; } + if (s.wrap <= 0) { return Z_STREAM_END$3; } + + /* Write the trailer */ + if (s.wrap === 2) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + put_byte(s, (strm.adler >> 16) & 0xff); + put_byte(s, (strm.adler >> 24) & 0xff); + put_byte(s, strm.total_in & 0xff); + put_byte(s, (strm.total_in >> 8) & 0xff); + put_byte(s, (strm.total_in >> 16) & 0xff); + put_byte(s, (strm.total_in >> 24) & 0xff); + } + else + { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s.wrap > 0) { s.wrap = -s.wrap; } + /* write the trailer only once! */ + return s.pending !== 0 ? Z_OK$3 : Z_STREAM_END$3; +}; + + +const deflateEnd = (strm) => { + + if (deflateStateCheck(strm)) { + return Z_STREAM_ERROR$2; + } + + const status = strm.state.status; + + strm.state = null; + + return status === BUSY_STATE ? err(strm, Z_DATA_ERROR$2) : Z_OK$3; +}; + + +/* ========================================================================= + * Initializes the compression dictionary from the given byte + * sequence without producing any compressed output. + */ +const deflateSetDictionary = (strm, dictionary) => { + + let dictLength = dictionary.length; + + if (deflateStateCheck(strm)) { + return Z_STREAM_ERROR$2; + } + + const s = strm.state; + const wrap = s.wrap; + + if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) { + return Z_STREAM_ERROR$2; + } + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap === 1) { + /* adler32(strm->adler, dictionary, dictLength); */ + strm.adler = adler32_1(strm.adler, dictionary, dictLength, 0); + } + + s.wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s.w_size) { + if (wrap === 0) { /* already empty otherwise */ + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + /* use the tail */ + // dictionary = dictionary.slice(dictLength - s.w_size); + let tmpDict = new Uint8Array(s.w_size); + tmpDict.set(dictionary.subarray(dictLength - s.w_size, dictLength), 0); + dictionary = tmpDict; + dictLength = s.w_size; + } + /* insert dictionary into window and hash */ + const avail = strm.avail_in; + const next = strm.next_in; + const input = strm.input; + strm.avail_in = dictLength; + strm.next_in = 0; + strm.input = dictionary; + fill_window(s); + while (s.lookahead >= MIN_MATCH) { + let str = s.strstart; + let n = s.lookahead - (MIN_MATCH - 1); + do { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]); + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + + s.head[s.ins_h] = str; + str++; + } while (--n); + s.strstart = str; + s.lookahead = MIN_MATCH - 1; + fill_window(s); + } + s.strstart += s.lookahead; + s.block_start = s.strstart; + s.insert = s.lookahead; + s.lookahead = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + strm.next_in = next; + strm.input = input; + strm.avail_in = avail; + s.wrap = wrap; + return Z_OK$3; +}; + + +var deflateInit_1 = deflateInit; +var deflateInit2_1 = deflateInit2; +var deflateReset_1 = deflateReset; +var deflateResetKeep_1 = deflateResetKeep; +var deflateSetHeader_1 = deflateSetHeader; +var deflate_2$1 = deflate$2; +var deflateEnd_1 = deflateEnd; +var deflateSetDictionary_1 = deflateSetDictionary; +var deflateInfo = 'pako deflate (from Nodeca project)'; + +/* Not implemented +module.exports.deflateBound = deflateBound; +module.exports.deflateCopy = deflateCopy; +module.exports.deflateGetDictionary = deflateGetDictionary; +module.exports.deflateParams = deflateParams; +module.exports.deflatePending = deflatePending; +module.exports.deflatePrime = deflatePrime; +module.exports.deflateTune = deflateTune; +*/ + +var deflate_1$2 = { + deflateInit: deflateInit_1, + deflateInit2: deflateInit2_1, + deflateReset: deflateReset_1, + deflateResetKeep: deflateResetKeep_1, + deflateSetHeader: deflateSetHeader_1, + deflate: deflate_2$1, + deflateEnd: deflateEnd_1, + deflateSetDictionary: deflateSetDictionary_1, + deflateInfo: deflateInfo +}; + +const _has = (obj, key) => { + return Object.prototype.hasOwnProperty.call(obj, key); +}; + +var assign = function (obj /*from1, from2, from3, ...*/) { + const sources = Array.prototype.slice.call(arguments, 1); + while (sources.length) { + const source = sources.shift(); + if (!source) { continue; } + + if (typeof source !== 'object') { + throw new TypeError(source + 'must be non-object'); + } + + for (const p in source) { + if (_has(source, p)) { + obj[p] = source[p]; + } + } + } + + return obj; +}; + + +// Join array of chunks to single array. +var flattenChunks = (chunks) => { + // calculate data length + let len = 0; + + for (let i = 0, l = chunks.length; i < l; i++) { + len += chunks[i].length; + } + + // join chunks + const result = new Uint8Array(len); + + for (let i = 0, pos = 0, l = chunks.length; i < l; i++) { + let chunk = chunks[i]; + result.set(chunk, pos); + pos += chunk.length; + } + + return result; +}; + +var common = { + assign: assign, + flattenChunks: flattenChunks +}; + +// String encode/decode helpers + + +// Quick check if we can use fast array to bin string conversion +// +// - apply(Array) can fail on Android 2.2 +// - apply(Uint8Array) can fail on iOS 5.1 Safari +// +let STR_APPLY_UIA_OK = true; + +try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; } + + +// Table with utf8 lengths (calculated by first byte of sequence) +// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, +// because max possible codepoint is 0x10ffff +const _utf8len = new Uint8Array(256); +for (let q = 0; q < 256; q++) { + _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1); +} +_utf8len[254] = _utf8len[254] = 1; // Invalid sequence start + + +// convert string to array (typed, when possible) +var string2buf = (str) => { + if (typeof TextEncoder === 'function' && TextEncoder.prototype.encode) { + return new TextEncoder().encode(str); + } + + let buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; + + // count binary size + for (m_pos = 0; m_pos < str_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { + c2 = str.charCodeAt(m_pos + 1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; + } + + // allocate buffer + buf = new Uint8Array(buf_len); + + // convert + for (i = 0, m_pos = 0; i < buf_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { + c2 = str.charCodeAt(m_pos + 1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + if (c < 0x80) { + /* one byte */ + buf[i++] = c; + } else if (c < 0x800) { + /* two bytes */ + buf[i++] = 0xC0 | (c >>> 6); + buf[i++] = 0x80 | (c & 0x3f); + } else if (c < 0x10000) { + /* three bytes */ + buf[i++] = 0xE0 | (c >>> 12); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } else { + /* four bytes */ + buf[i++] = 0xf0 | (c >>> 18); + buf[i++] = 0x80 | (c >>> 12 & 0x3f); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } + } + + return buf; +}; + +// Helper +const buf2binstring = (buf, len) => { + // On Chrome, the arguments in a function call that are allowed is `65534`. + // If the length of the buffer is smaller than that, we can use this optimization, + // otherwise we will take a slower path. + if (len < 65534) { + if (buf.subarray && STR_APPLY_UIA_OK) { + return String.fromCharCode.apply(null, buf.length === len ? buf : buf.subarray(0, len)); + } + } + + let result = ''; + for (let i = 0; i < len; i++) { + result += String.fromCharCode(buf[i]); + } + return result; +}; + + +// convert array to string +var buf2string = (buf, max) => { + const len = max || buf.length; + + if (typeof TextDecoder === 'function' && TextDecoder.prototype.decode) { + return new TextDecoder().decode(buf.subarray(0, max)); + } + + let i, out; + + // Reserve max possible length (2 words per char) + // NB: by unknown reasons, Array is significantly faster for + // String.fromCharCode.apply than Uint16Array. + const utf16buf = new Array(len * 2); + + for (out = 0, i = 0; i < len;) { + let c = buf[i++]; + // quick process ascii + if (c < 0x80) { utf16buf[out++] = c; continue; } + + let c_len = _utf8len[c]; + // skip 5 & 6 byte codes + if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; } + + // apply mask on first byte + c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; + // join the rest + while (c_len > 1 && i < len) { + c = (c << 6) | (buf[i++] & 0x3f); + c_len--; + } + + // terminated by end of string? + if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } + + if (c < 0x10000) { + utf16buf[out++] = c; + } else { + c -= 0x10000; + utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); + utf16buf[out++] = 0xdc00 | (c & 0x3ff); + } + } + + return buf2binstring(utf16buf, out); +}; + + +// Calculate max possible position in utf8 buffer, +// that will not break sequence. If that's not possible +// - (very small limits) return max size as is. +// +// buf[] - utf8 bytes array +// max - length limit (mandatory); +var utf8border = (buf, max) => { + + max = max || buf.length; + if (max > buf.length) { max = buf.length; } + + // go back from last position, until start of sequence found + let pos = max - 1; + while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } + + // Very small and broken sequence, + // return max, because we should return something anyway. + if (pos < 0) { return max; } + + // If we came to start of buffer - that means buffer is too small, + // return max too. + if (pos === 0) { return max; } + + return (pos + _utf8len[buf[pos]] > max) ? pos : max; +}; + +var strings = { + string2buf: string2buf, + buf2string: buf2string, + utf8border: utf8border +}; + +// (C) 1995-2013 Jean-loup Gailly and Mark Adler +// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +function ZStream() { + /* next input byte */ + this.input = null; // JS specific, because we have no pointers + this.next_in = 0; + /* number of bytes available at input */ + this.avail_in = 0; + /* total number of input bytes read so far */ + this.total_in = 0; + /* next output byte should be put there */ + this.output = null; // JS specific, because we have no pointers + this.next_out = 0; + /* remaining free space at output */ + this.avail_out = 0; + /* total number of bytes output so far */ + this.total_out = 0; + /* last error message, NULL if no error */ + this.msg = ''/*Z_NULL*/; + /* not visible by applications */ + this.state = null; + /* best guess about the data type: binary or text */ + this.data_type = 2/*Z_UNKNOWN*/; + /* adler32 value of the uncompressed data */ + this.adler = 0; +} + +var zstream = ZStream; + +const toString$1 = Object.prototype.toString; + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + +const { + Z_NO_FLUSH: Z_NO_FLUSH$1, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH: Z_FINISH$2, + Z_OK: Z_OK$2, Z_STREAM_END: Z_STREAM_END$2, + Z_DEFAULT_COMPRESSION, + Z_DEFAULT_STRATEGY, + Z_DEFLATED: Z_DEFLATED$1 +} = constants$2; + +/* ===========================================================================*/ + + +/** + * class Deflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[deflate]], + * [[deflateRaw]] and [[gzip]]. + **/ + +/* internal + * Deflate.chunks -> Array + * + * Chunks of output data, if [[Deflate#onData]] not overridden. + **/ + +/** + * Deflate.result -> Uint8Array + * + * Compressed result, generated by default [[Deflate#onData]] + * and [[Deflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Deflate#push]] with `Z_FINISH` / `true` param). + **/ + +/** + * Deflate.err -> Number + * + * Error code after deflate finished. 0 (Z_OK) on success. + * You will not need it in real life, because deflate errors + * are possible only on wrong options or bad `onData` / `onEnd` + * custom handlers. + **/ + +/** + * Deflate.msg -> String + * + * Error message, if [[Deflate.err]] != 0 + **/ + + +/** + * new Deflate(options) + * - options (Object): zlib deflate options. + * + * Creates new deflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `level` + * - `windowBits` + * - `memLevel` + * - `strategy` + * - `dictionary` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw deflate + * - `gzip` (Boolean) - create gzip wrapper + * - `header` (Object) - custom header for gzip + * - `text` (Boolean) - true if compressed data believed to be text + * - `time` (Number) - modification time, unix timestamp + * - `os` (Number) - operation system code + * - `extra` (Array) - array of bytes with extra data (max 65536) + * - `name` (String) - file name (binary string) + * - `comment` (String) - comment (binary string) + * - `hcrc` (Boolean) - true if header crc should be added + * + * ##### Example: + * + * ```javascript + * const pako = require('pako') + * , chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9]) + * , chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * const deflate = new pako.Deflate({ level: 3}); + * + * deflate.push(chunk1, false); + * deflate.push(chunk2, true); // true -> last chunk + * + * if (deflate.err) { throw new Error(deflate.err); } + * + * console.log(deflate.result); + * ``` + **/ +function Deflate$1(options) { + this.options = common.assign({ + level: Z_DEFAULT_COMPRESSION, + method: Z_DEFLATED$1, + chunkSize: 16384, + windowBits: 15, + memLevel: 8, + strategy: Z_DEFAULT_STRATEGY + }, options || {}); + + let opt = this.options; + + if (opt.raw && (opt.windowBits > 0)) { + opt.windowBits = -opt.windowBits; + } + + else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) { + opt.windowBits += 16; + } + + this.err = 0; // error code, if happens (0 = Z_OK) + this.msg = ''; // error message + this.ended = false; // used to avoid multiple onEnd() calls + this.chunks = []; // chunks of compressed data + + this.strm = new zstream(); + this.strm.avail_out = 0; + + let status = deflate_1$2.deflateInit2( + this.strm, + opt.level, + opt.method, + opt.windowBits, + opt.memLevel, + opt.strategy + ); + + if (status !== Z_OK$2) { + throw new Error(messages[status]); + } + + if (opt.header) { + deflate_1$2.deflateSetHeader(this.strm, opt.header); + } + + if (opt.dictionary) { + let dict; + // Convert data if needed + if (typeof opt.dictionary === 'string') { + // If we need to compress text, change encoding to utf8. + dict = strings.string2buf(opt.dictionary); + } else if (toString$1.call(opt.dictionary) === '[object ArrayBuffer]') { + dict = new Uint8Array(opt.dictionary); + } else { + dict = opt.dictionary; + } + + status = deflate_1$2.deflateSetDictionary(this.strm, dict); + + if (status !== Z_OK$2) { + throw new Error(messages[status]); + } + + this._dict_set = true; + } +} + +/** + * Deflate#push(data[, flush_mode]) -> Boolean + * - data (Uint8Array|ArrayBuffer|String): input data. Strings will be + * converted to utf8 byte sequence. + * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. + * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. + * + * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with + * new compressed chunks. Returns `true` on success. The last data block must + * have `flush_mode` Z_FINISH (or `true`). That will flush internal pending + * buffers and call [[Deflate#onEnd]]. + * + * On fail call [[Deflate#onEnd]] with error code and return false. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ +Deflate$1.prototype.push = function (data, flush_mode) { + const strm = this.strm; + const chunkSize = this.options.chunkSize; + let status, _flush_mode; + + if (this.ended) { return false; } + + if (flush_mode === ~~flush_mode) _flush_mode = flush_mode; + else _flush_mode = flush_mode === true ? Z_FINISH$2 : Z_NO_FLUSH$1; + + // Convert data if needed + if (typeof data === 'string') { + // If we need to compress text, change encoding to utf8. + strm.input = strings.string2buf(data); + } else if (toString$1.call(data) === '[object ArrayBuffer]') { + strm.input = new Uint8Array(data); + } else { + strm.input = data; + } + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + for (;;) { + if (strm.avail_out === 0) { + strm.output = new Uint8Array(chunkSize); + strm.next_out = 0; + strm.avail_out = chunkSize; + } + + // Make sure avail_out > 6 to avoid repeating markers + if ((_flush_mode === Z_SYNC_FLUSH || _flush_mode === Z_FULL_FLUSH) && strm.avail_out <= 6) { + this.onData(strm.output.subarray(0, strm.next_out)); + strm.avail_out = 0; + continue; + } + + status = deflate_1$2.deflate(strm, _flush_mode); + + // Ended => flush and finish + if (status === Z_STREAM_END$2) { + if (strm.next_out > 0) { + this.onData(strm.output.subarray(0, strm.next_out)); + } + status = deflate_1$2.deflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return status === Z_OK$2; + } + + // Flush if out buffer full + if (strm.avail_out === 0) { + this.onData(strm.output); + continue; + } + + // Flush if requested and has data + if (_flush_mode > 0 && strm.next_out > 0) { + this.onData(strm.output.subarray(0, strm.next_out)); + strm.avail_out = 0; + continue; + } + + if (strm.avail_in === 0) break; + } + + return true; +}; + + +/** + * Deflate#onData(chunk) -> Void + * - chunk (Uint8Array): output data. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ +Deflate$1.prototype.onData = function (chunk) { + this.chunks.push(chunk); +}; + + +/** + * Deflate#onEnd(status) -> Void + * - status (Number): deflate status. 0 (Z_OK) on success, + * other if not. + * + * Called once after you tell deflate that the input stream is + * complete (Z_FINISH). By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ +Deflate$1.prototype.onEnd = function (status) { + // On success - join + if (status === Z_OK$2) { + this.result = common.flattenChunks(this.chunks); + } + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; +}; + + +/** + * deflate(data[, options]) -> Uint8Array + * - data (Uint8Array|ArrayBuffer|String): input data to compress. + * - options (Object): zlib deflate options. + * + * Compress `data` with deflate algorithm and `options`. + * + * Supported options are: + * + * - level + * - windowBits + * - memLevel + * - strategy + * - dictionary + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * + * ##### Example: + * + * ```javascript + * const pako = require('pako') + * const data = new Uint8Array([1,2,3,4,5,6,7,8,9]); + * + * console.log(pako.deflate(data)); + * ``` + **/ +function deflate$1(input, options) { + const deflator = new Deflate$1(options); + + deflator.push(input, true); + + // That will never happens, if you don't cheat with options :) + if (deflator.err) { throw deflator.msg || messages[deflator.err]; } + + return deflator.result; +} +var deflate_2 = deflate$1; + +var deflate_1$1 = { + deflate: deflate_2}; + +const { deflate} = deflate_1$1; +var deflate_1 = deflate; + +const lut = { + b: { u: DataView.prototype.getInt8, p: DataView.prototype.setInt8, bytes: 1 }, + B: { + u: DataView.prototype.getUint8, + p: DataView.prototype.setUint8, + bytes: 1, + }, + h: { + u: DataView.prototype.getInt16, + p: DataView.prototype.setInt16, + bytes: 2, + }, + H: { + u: DataView.prototype.getUint16, + p: DataView.prototype.setUint16, + bytes: 2, + }, + i: { + u: DataView.prototype.getInt32, + p: DataView.prototype.setInt32, + bytes: 4, + }, + I: { + u: DataView.prototype.getUint32, + p: DataView.prototype.setUint32, + bytes: 4, + }, +}; +const pack = (format, ...data) => { + let pointer = 0; + if (format.replace(/[<>]/, "").length != data.length) { + throw "Pack format to Argument count mismatch"; + } + const bytes = []; + let littleEndian = true; + for (let i = 0; i < format.length; i++) { + if (format[i] == "<") { + littleEndian = true; + } + else if (format[i] == ">") { + littleEndian = false; + } + else { + pushBytes(format[i], data[pointer]); + pointer++; + } + } + function pushBytes(formatChar, value) { + if (!(formatChar in lut)) { + throw "Unhandled character '" + formatChar + "' in pack format"; + } + const dataSize = lut[formatChar].bytes; + const view = new DataView(new ArrayBuffer(dataSize)); + const dataViewFn = lut[formatChar].p.bind(view); + dataViewFn(0, value, littleEndian); + for (let i = 0; i < dataSize; i++) { + bytes.push(view.getUint8(i)); + } + } + return bytes; +}; +const unpack = (format, bytes) => { + let pointer = 0; + const data = []; + let littleEndian = true; + for (const c of format) { + if (c == "<") { + littleEndian = true; + } + else if (c == ">") { + littleEndian = false; + } + else { + pushData(c); + } + } + function pushData(formatChar) { + if (!(formatChar in lut)) { + throw "Unhandled character '" + formatChar + "' in unpack format"; + } + const dataSize = lut[formatChar].bytes; + const view = new DataView(new ArrayBuffer(dataSize)); + for (let i = 0; i < dataSize; i++) { + view.setUint8(i, bytes[pointer + i] & 0xff); + } + const dataViewFn = lut[formatChar].u.bind(view); + data.push(dataViewFn(0, littleEndian)); + pointer += dataSize; + } + return data; +}; + +/// +class ESPLoader extends EventTarget { + /** + * Check if device is using USB-JTAG or USB-OTG (not external serial chip) + * Returns undefined if not yet determined + */ + get isUsbJtagOrOtg() { + return this._parent ? this._parent._isUsbJtagOrOtg : this._isUsbJtagOrOtg; + } + constructor(port, logger, _parent) { + super(); + this.port = port; + this.logger = logger; + this._parent = _parent; + this.__chipName = null; + this.__chipRevision = null; + this.__chipVariant = null; + this._efuses = new Array(4).fill(0); + this._flashsize = 4 * 1024 * 1024; + this.debug = false; + this.IS_STUB = false; + this.connected = true; + this.flashSize = null; + this.currentBaudRate = ESP_ROM_BAUD; + this.SLIP_END = 0xc0; + this.SLIP_ESC = 0xdb; + this.SLIP_ESC_END = 0xdc; + this.SLIP_ESC_ESC = 0xdd; + this._isESP32S2NativeUSB = false; + this._initializationSucceeded = false; + this.__commandLock = Promise.resolve([0, []]); + this.__isReconfiguring = false; + this.__abandonCurrentOperation = false; + this._suppressDisconnect = false; + this.__consoleMode = false; + this._isUsbJtagOrOtg = undefined; + // Adaptive speed adjustment for flash read operations + this.__adaptiveBlockMultiplier = 1; + this.__adaptiveMaxInFlightMultiplier = 1; + this.__consecutiveSuccessfulChunks = 0; + this.__lastAdaptiveAdjustment = 0; + this.__isCDCDevice = false; + this.state_DTR = false; + this.state_RTS = false; + this.__writeChain = Promise.resolve(); + } + // Chip properties with parent delegation + // chipFamily accessed before initialization as designed + get chipFamily() { + return this._parent ? this._parent.chipFamily : this.__chipFamily; + } + set chipFamily(value) { + if (this._parent) { + this._parent.chipFamily = value; + } + else { + this.__chipFamily = value; + } + } + get chipName() { + return this._parent ? this._parent.chipName : this.__chipName; + } + set chipName(value) { + if (this._parent) { + this._parent.chipName = value; + } + else { + this.__chipName = value; + } + } + get chipRevision() { + return this._parent ? this._parent.chipRevision : this.__chipRevision; + } + set chipRevision(value) { + if (this._parent) { + this._parent.chipRevision = value; + } + else { + this.__chipRevision = value; + } + } + get chipVariant() { + return this._parent ? this._parent.chipVariant : this.__chipVariant; + } + set chipVariant(value) { + if (this._parent) { + this._parent.chipVariant = value; + } + else { + this.__chipVariant = value; + } + } + // Console mode with parent delegation + get _consoleMode() { + return this._parent ? this._parent._consoleMode : this.__consoleMode; + } + set _consoleMode(value) { + if (this._parent) { + this._parent._consoleMode = value; + } + else { + this.__consoleMode = value; + } + } + // Public setter for console mode (used by script.js) + setConsoleMode(value) { + this._consoleMode = value; + } + get _inputBuffer() { + if (this._parent) { + return this._parent._inputBuffer; + } + if (this.__inputBuffer === undefined) { + throw new Error("_inputBuffer accessed before initialization"); + } + return this.__inputBuffer; + } + get _inputBufferReadIndex() { + return this._parent + ? this._parent._inputBufferReadIndex + : this.__inputBufferReadIndex || 0; + } + set _inputBufferReadIndex(value) { + if (this._parent) { + this._parent._inputBufferReadIndex = value; + } + else { + this.__inputBufferReadIndex = value; + } + } + // Get available bytes in buffer (from read index to end) + get _inputBufferAvailable() { + return this._inputBuffer.length - this._inputBufferReadIndex; + } + // Read one byte from buffer (ring-buffer style with index pointer) + _readByte() { + if (this._inputBufferReadIndex >= this._inputBuffer.length) { + return undefined; + } + return this._inputBuffer[this._inputBufferReadIndex++]; + } + // Clear input buffer and reset read index + _clearInputBuffer() { + this._inputBuffer.length = 0; + this._inputBufferReadIndex = 0; + } + // Compact buffer when read index gets too large (prevent memory growth) + _compactInputBuffer() { + if (this._inputBufferReadIndex > 1000 && + this._inputBufferReadIndex > this._inputBuffer.length / 2) { + // Remove already-read bytes and reset index + this._inputBuffer.splice(0, this._inputBufferReadIndex); + this._inputBufferReadIndex = 0; + } + } + get _totalBytesRead() { + return this._parent + ? this._parent._totalBytesRead + : this.__totalBytesRead || 0; + } + set _totalBytesRead(value) { + if (this._parent) { + this._parent._totalBytesRead = value; + } + else { + this.__totalBytesRead = value; + } + } + get _commandLock() { + return this._parent ? this._parent._commandLock : this.__commandLock; + } + set _commandLock(value) { + if (this._parent) { + this._parent._commandLock = value; + } + else { + this.__commandLock = value; + } + } + get _isReconfiguring() { + return this._parent + ? this._parent._isReconfiguring + : this.__isReconfiguring; + } + set _isReconfiguring(value) { + if (this._parent) { + this._parent._isReconfiguring = value; + } + else { + this.__isReconfiguring = value; + } + } + get _abandonCurrentOperation() { + return this._parent + ? this._parent._abandonCurrentOperation + : this.__abandonCurrentOperation; + } + set _abandonCurrentOperation(value) { + if (this._parent) { + this._parent._abandonCurrentOperation = value; + } + else { + this.__abandonCurrentOperation = value; + } + } + get _adaptiveBlockMultiplier() { + return this._parent + ? this._parent._adaptiveBlockMultiplier + : this.__adaptiveBlockMultiplier; + } + set _adaptiveBlockMultiplier(value) { + if (this._parent) { + this._parent._adaptiveBlockMultiplier = value; + } + else { + this.__adaptiveBlockMultiplier = value; + } + } + get _adaptiveMaxInFlightMultiplier() { + return this._parent + ? this._parent._adaptiveMaxInFlightMultiplier + : this.__adaptiveMaxInFlightMultiplier; + } + set _adaptiveMaxInFlightMultiplier(value) { + if (this._parent) { + this._parent._adaptiveMaxInFlightMultiplier = value; + } + else { + this.__adaptiveMaxInFlightMultiplier = value; + } + } + get _consecutiveSuccessfulChunks() { + return this._parent + ? this._parent._consecutiveSuccessfulChunks + : this.__consecutiveSuccessfulChunks; + } + set _consecutiveSuccessfulChunks(value) { + if (this._parent) { + this._parent._consecutiveSuccessfulChunks = value; + } + else { + this.__consecutiveSuccessfulChunks = value; + } + } + get _lastAdaptiveAdjustment() { + return this._parent + ? this._parent._lastAdaptiveAdjustment + : this.__lastAdaptiveAdjustment; + } + set _lastAdaptiveAdjustment(value) { + if (this._parent) { + this._parent._lastAdaptiveAdjustment = value; + } + else { + this.__lastAdaptiveAdjustment = value; + } + } + get _isCDCDevice() { + return this._parent ? this._parent._isCDCDevice : this.__isCDCDevice; + } + set _isCDCDevice(value) { + if (this._parent) { + this._parent._isCDCDevice = value; + } + else { + this.__isCDCDevice = value; + } + } + detectUSBSerialChip(vendorId, productId) { + // Common USB-Serial chip vendors and their products + const chips = { + 0x1a86: { + // QinHeng Electronics + 0x7522: { name: "CH340", maxBaudrate: 460800 }, + 0x7523: { name: "CH340", maxBaudrate: 460800 }, + 0x7584: { name: "CH340", maxBaudrate: 460800 }, + 0x5523: { name: "CH341", maxBaudrate: 2000000 }, + 0x55d3: { name: "CH343", maxBaudrate: 6000000 }, + 0x55d4: { name: "CH9102", maxBaudrate: 6000000 }, + 0x55d8: { name: "CH9101", maxBaudrate: 3000000 }, + }, + 0x10c4: { + // Silicon Labs + 0xea60: { name: "CP2102(n)", maxBaudrate: 3000000 }, + 0xea70: { name: "CP2105", maxBaudrate: 2000000 }, + 0xea71: { name: "CP2108", maxBaudrate: 2000000 }, + }, + 0x0403: { + // FTDI + 0x6001: { name: "FT232R", maxBaudrate: 3000000 }, + 0x6010: { name: "FT2232", maxBaudrate: 3000000 }, + 0x6011: { name: "FT4232", maxBaudrate: 3000000 }, + 0x6014: { name: "FT232H", maxBaudrate: 12000000 }, + 0x6015: { name: "FT230X", maxBaudrate: 3000000 }, + }, + 0x303a: { + // Espressif (native USB) + 0x2: { name: "ESP32-S2 Native USB", maxBaudrate: 2000000 }, + 0x12: { name: "ESP32-P4 Native USB", maxBaudrate: 2000000 }, + 0x1001: { name: "ESP32 Native USB", maxBaudrate: 2000000 }, + }, + }; + const vendor = chips[vendorId]; + if (vendor && vendor[productId]) { + return vendor[productId]; + } + return { + name: `Unknown (VID: 0x${vendorId.toString(16)}, PID: 0x${productId.toString(16)})`, + }; + } + async initialize() { + if (!this._parent) { + this.__inputBuffer = []; + this.__inputBufferReadIndex = 0; + this.__totalBytesRead = 0; + // Detect and log USB-Serial chip info + const portInfo = this.port.getInfo(); + if (portInfo.usbVendorId && portInfo.usbProductId) { + const chipInfo = this.detectUSBSerialChip(portInfo.usbVendorId, portInfo.usbProductId); + this.logger.log(`USB-Serial: ${chipInfo.name} (VID: 0x${portInfo.usbVendorId.toString(16)}, PID: 0x${portInfo.usbProductId.toString(16)})`); + if (chipInfo.maxBaudrate) { + this._maxUSBSerialBaudrate = chipInfo.maxBaudrate; + this.logger.log(`Max baudrate: ${chipInfo.maxBaudrate}`); + } + // Detect ESP32-S2 Native USB + if (portInfo.usbVendorId === 0x303a && portInfo.usbProductId === 0x2) { + this._isESP32S2NativeUSB = true; + } + // Detect CDC devices for adaptive speed adjustment + // Espressif Native USB (VID: 0x303a) or CH343 (VID: 0x1a86, PID: 0x55d3) + if (portInfo.usbVendorId === 0x303a || + (portInfo.usbVendorId === 0x1a86 && portInfo.usbProductId === 0x55d3)) { + this._isCDCDevice = true; + } + } + // Don't await this promise so it doesn't block rest of method. + this.readLoop(); + } + // Try to connect with different reset strategies + await this.connectWithResetStrategies(); + // Detect chip type + await this.detectChip(); + // Power on flash for ESP32-P4 Rev 301 (must be done before loading stub) + if (this.chipFamily === CHIP_FAMILY_ESP32P4 && this.chipRevision === 301) { + await this.powerOnFlash(); + } + // Detect if device is using USB-JTAG/Serial or USB-OTG (not external serial chip) + // This is needed to determine the correct reset strategy for console mode + try { + this._isUsbJtagOrOtg = await this.detectUsbConnectionType(); + this.logger.debug(`USB connection type: ${this._isUsbJtagOrOtg ? "USB-JTAG/OTG" : "External Serial Chip"}`); + } + catch (err) { + this.logger.debug(`Could not detect USB connection type: ${err}`); + } + try { + const usbMode = await this.getUsbMode(); + this.logger.debug(`USB mode (register): ${usbMode.mode} (uartNo=${usbMode.uartNo})`); + } + catch (err) { + this.logger.debug(`Could not detect USB mode: ${err}`); + } + // Read the OTP data for this chip and store into this.efuses array + const FlAddr = getSpiFlashAddresses(this.getChipFamily()); + const AddrMAC = FlAddr.macFuse; + for (let i = 0; i < 4; i++) { + this._efuses[i] = await this.readRegister(AddrMAC + 4 * i); + } + const revisionInfo = this.chipRevision !== null && this.chipRevision !== undefined + ? ` (revision ${this.chipRevision})` + : ""; + this.logger.log(`Connected to ${this.chipName}${revisionInfo}`); + this.logger.debug(`Bootloader flash offset: 0x${FlAddr.flashOffs.toString(16)}`); + // Mark initialization as successful + this._initializationSucceeded = true; + } + /** + * Detect chip type using GET_SECURITY_INFO (for newer chips) or magic value (for older chips) + */ + async detectChip() { + try { + // Try GET_SECURITY_INFO command first (ESP32-C3 and later) + const securityInfo = await this.getSecurityInfo(); + const chipId = securityInfo.chipId; + const chipInfo = CHIP_ID_TO_INFO[chipId]; + if (chipInfo) { + this.chipName = chipInfo.name; + this.chipFamily = chipInfo.family; + this.chipRevision = await this.getChipRevision(); + this.logger.debug(`${this.chipName} revision: ${this.chipRevision}`); + if (this.chipFamily === CHIP_FAMILY_ESP32P4 && + this.chipRevision >= 300) { + this.chipVariant = "rev300"; + } + else if (this.chipFamily === CHIP_FAMILY_ESP32P4) { + this.chipVariant = "rev0"; + } + this.logger.debug(`Detected chip via IMAGE_CHIP_ID: ${chipId} (${this.chipName})`); + return; + } + this.logger.debug(`Unknown IMAGE_CHIP_ID: ${chipId}, falling back to magic value detection`); + } + catch (error) { + // GET_SECURITY_INFO not supported, fall back to magic value detection + this.logger.debug(`GET_SECURITY_INFO failed, using magic value detection: ${error}`); + // Drain input buffer for CP210x compatibility on Windows + // This ensures all error responses are cleared before continuing + await this.drainInputBuffer(200); + // Clear input buffer and re-sync to recover from failed command + this._clearInputBuffer(); + await sleep(SYNC_TIMEOUT); + // Re-sync with the chip to ensure clean communication + try { + await this.sync(); + } + catch (syncErr) { + this.logger.debug(`Re-sync after GET_SECURITY_INFO failure: ${syncErr}`); + } + } + // Fallback: Use magic value detection for ESP8266, ESP32, ESP32-S2 + const chipMagicValue = await this.readRegister(CHIP_DETECT_MAGIC_REG_ADDR); + const chip = CHIP_DETECT_MAGIC_VALUES[chipMagicValue >>> 0]; + if (chip === undefined) { + throw new Error(`Unknown Chip: Hex: ${toHex(chipMagicValue >>> 0, 8).toLowerCase()} Number: ${chipMagicValue}`); + } + this.chipName = chip.name; + this.chipFamily = chip.family; + this.chipRevision = await this.getChipRevision(); + this.logger.debug(`${this.chipName} revision: ${this.chipRevision}`); + if (this.chipFamily === CHIP_FAMILY_ESP32P4) { + this.chipVariant = this.chipRevision >= 300 ? "rev300" : "rev0"; + this.logger.debug(`ESP32-P4 variant: ${this.chipVariant}`); + } + this.logger.debug(`Detected chip via magic value: ${toHex(chipMagicValue >>> 0, 8)} (${this.chipName})`); + } + async getChipRevision() { + var _a; + let minor = 0; + let major = 0; + switch (this.chipFamily) { + case CHIP_FAMILY_ESP32: { + const efuse3 = await this.readRegister(ESP32_BASEFUSEADDR + 4 * 3); + const efuse5 = await this.readRegister(ESP32_BASEFUSEADDR + 4 * 5); + minor = (efuse5 >> 24) & 0x3; + const revBit0 = (efuse3 >> 15) & 0x1; + const revBit1 = (efuse5 >> 20) & 0x1; + const apb = await this.readRegister(ESP32_APB_CTL_DATE_ADDR); + const revBit2 = (apb >> 31) & 0x1; + const combined = (revBit2 << 2) | (revBit1 << 1) | revBit0; + major = + (_a = { 0: 0, 1: 1, 3: 2, 7: 3 }[combined]) !== null && _a !== void 0 ? _a : 0; + break; + } + case CHIP_FAMILY_ESP32S2: { + const w3 = await this.readRegister(ESP32S2_EFUSE_BLOCK1_ADDR + 4 * 3); + const w4 = await this.readRegister(ESP32S2_EFUSE_BLOCK1_ADDR + 4 * 4); + const hi = (w3 >> 20) & 0x01; + const lo = (w4 >> 4) & 0x07; + minor = (hi << 3) + lo; + major = (w3 >> 18) & 0x03; + break; + } + case CHIP_FAMILY_ESP32S3: { + const w3 = await this.readRegister(ESP32S3_EFUSE_BLOCK1_ADDR + 4 * 3); + const w5 = await this.readRegister(ESP32S3_EFUSE_BLOCK1_ADDR + 4 * 5); + const hi = (w5 >> 23) & 0x01; + const lo = (w3 >> 18) & 0x07; + minor = (hi << 3) + lo; + major = (w5 >> 24) & 0x03; + break; + } + case CHIP_FAMILY_ESP32C2: { + const w1 = await this.readRegister(ESP32C2_EFUSE_BLOCK2_ADDR + 4 * 1); + minor = (w1 >> 16) & 0x0f; + major = (w1 >> 20) & 0x03; + break; + } + case CHIP_FAMILY_ESP32C3: { + const w3 = await this.readRegister(ESP32C3_EFUSE_RD_MAC_SPI_SYS_3_REG); + const w5 = await this.readRegister(ESP32C3_EFUSE_RD_MAC_SPI_SYS_5_REG); + const hi = (w5 >> 23) & 0x01; + const lo = (w3 >> 18) & 0x07; + minor = (hi << 3) + lo; + major = (w5 >> 24) & 0x03; + break; + } + case CHIP_FAMILY_ESP32C5: { + const w2 = await this.readRegister(ESP32C5_EFUSE_BLOCK1_ADDR + 4 * 2); + minor = w2 & 0x0f; + major = (w2 >> 4) & 0x03; + break; + } + case CHIP_FAMILY_ESP32C6: { + const w3 = await this.readRegister(ESP32C6_EFUSE_BLOCK1_ADDR + 4 * 3); + minor = (w3 >> 18) & 0x0f; + major = (w3 >> 22) & 0x03; + break; + } + case CHIP_FAMILY_ESP32C61: { + const w2 = await this.readRegister(ESP32C61_EFUSE_BLOCK1_ADDR + 4 * 2); + minor = w2 & 0x0f; + major = (w2 >> 4) & 0x03; + break; + } + case CHIP_FAMILY_ESP32H2: { + const w3 = await this.readRegister(ESP32H2_EFUSE_BLOCK1_ADDR + 4 * 3); + minor = (w3 >> 18) & 0x07; + major = (w3 >> 21) & 0x03; + break; + } + case CHIP_FAMILY_ESP32H4: { + break; + } + case CHIP_FAMILY_ESP32H21: { + break; + } + case CHIP_FAMILY_ESP32P4: { + const w2 = await this.readRegister(ESP32P4_EFUSE_BLOCK1_ADDR + 4 * 2); + minor = w2 & 0x0f; + major = (((w2 >> 23) & 1) << 2) | ((w2 >> 4) & 0x03); + break; + } + case CHIP_FAMILY_ESP32S31: { + const w2 = await this.readRegister(ESP32S31_EFUSE_BLOCK1_ADDR + 4 * 2); + minor = w2 & 0x0f; + major = (w2 >> 4) & 0x03; + break; + } + } + return major * 100 + minor; + } + /** + * Power on the flash chip for ESP32-P4 Rev 301 (ECO6) + * The flash chip is powered off by default on ECO6, when the default flash + * voltage changed from 1.8V to 3.3V. This is to prevent damage to 1.8V flash chips. + */ + async powerOnFlash() { + if (this.chipFamily !== CHIP_FAMILY_ESP32P4) { + return; // Only needed for ESP32-P4 + } + if (this.chipRevision !== 301) { + return; // Only needed for Rev 301 (ECO6) + } + this.logger.debug("Powering on flash for ESP32-P4 Rev 301 (ECO6)"); + // Power up pad group + await this.writeRegister(ESP32P4_LP_SYSTEM_REG_ANA_XPD_PAD_GROUP_REG, 1); + await sleep(10); // 0.01 seconds + // Flash power up sequence + const pmuAnaReg = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG); + await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG, pmuAnaReg | ESP32P4_PMU_ANA_0P1A_EN_CUR_LIM_0); + const pmuReg = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG); + await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG, pmuReg | ESP32P4_PMU_0P1A_FORCE_TIEH_SEL_0); + const pmuDateReg = await this.readRegister(ESP32P4_PMU_DATE_REG); + await this.writeRegister(ESP32P4_PMU_DATE_REG, pmuDateReg | (3 << 0)); + await sleep(0.05); // 0.00005 seconds = 0.05 ms + const pmuAnaReg2 = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG); + await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_ANA_REG, pmuAnaReg2 & ~ESP32P4_PMU_ANA_0P1A_EN_CUR_LIM_0); + const pmuReg2 = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG); + await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG, pmuReg2 & -2139095041); + // Update eFuse voltage to PMU + const pmuReg3 = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG); + await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG, pmuReg3 | 0x80); + const pmuReg4 = await this.readRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG); + await this.writeRegister(ESP32P4_PMU_EXT_LDO_P0_0P1A_REG, pmuReg4 & ~ESP32P4_PMU_0P1A_FORCE_TIEH_SEL_0); + await sleep(2); // 0.0018 seconds = 1.8 ms, rounded to 2ms + this.logger.debug("Flash powered on successfully"); + } + /** + * Get security info including chip ID (ESP32-C3 and later) + */ + async getSecurityInfo() { + const [, responseData] = await this.checkCommand(ESP_GET_SECURITY_INFO, [], 0); + // Some chips/ROM versions return empty response or don't support this command + if (responseData.length === 0) { + throw new Error(`GET_SECURITY_INFO not supported or returned empty response`); + } + if (responseData.length < 12) { + throw new Error(`Invalid security info response length: ${responseData.length} (expected at least 12 bytes)`); + } + const flags = unpack("= 16 + ? unpack("= 20 + ? unpack(" b.toString(16).padStart(2, "0").toUpperCase()) + .join(":"); + } + /** + * @name readLoop + * Reads data from the input stream and places it in the inputBuffer + */ + async readLoop() { + if (this.debug) { + this.logger.debug("Starting read loop"); + } + this._reader = this.port.readable.getReader(); + try { + let keepReading = true; + while (keepReading) { + const { value, done } = await this._reader.read(); + if (done) { + this._reader.releaseLock(); + keepReading = false; + break; + } + if (!value || value.length === 0) { + continue; + } + // Always read from browser's serial buffer immediately + // to prevent browser buffer overflow. Don't apply back-pressure here. + const chunk = Array.from(value); + Array.prototype.push.apply(this._inputBuffer, chunk); + // Track total bytes read from serial port + this._totalBytesRead += value.length; + } + } + catch { + // this.logger.error("Read loop got disconnected"); + } + finally { + // Always reset reconfiguring flag when read loop ends + // This prevents "Cannot write during port reconfiguration" errors + // when the read loop dies unexpectedly + this._isReconfiguring = false; + // Release reader if still locked + if (this._reader) { + try { + this._reader.releaseLock(); + this.logger.debug("Reader released in readLoop cleanup"); + } + catch (err) { + this.logger.debug(`Reader release error in readLoop: ${err}`); + } + this._reader = undefined; + } + } + // Disconnected! + this.connected = false; + // Check if this is ESP32-S2 Native USB that needs port reselection + // Only trigger reconnect if initialization did NOT succeed (wrong port) + if (this._isESP32S2NativeUSB && !this._initializationSucceeded) { + this.logger.log("ESP32-S2 Native USB detected - requesting port reselection"); + this.dispatchEvent(new CustomEvent("esp32s2-usb-reconnect", { + detail: { message: "ESP32-S2 Native USB requires port reselection" }, + })); + } + // Only dispatch disconnect event if not suppressed + if (!this._suppressDisconnect) { + this.dispatchEvent(new Event("disconnect")); + } + this._suppressDisconnect = false; + this.logger.debug("Finished read loop"); + } + // ============================================================================ + // Web Serial (Desktop) - DTR/RTS Signal Handling & Reset Strategies + // ============================================================================ + async setRTS(state) { + await this.port.setSignals({ requestToSend: state }); + // Work-around for adapters on Windows using the usbser.sys driver: + // generate a dummy change to DTR so that the set-control-line-state + // request is sent with the updated RTS state and the same DTR state + // Referenced to esptool.py + await this.setDTR(this.state_DTR); + } + async setDTR(state) { + this.state_DTR = state; + await this.port.setSignals({ dataTerminalReady: state }); + } + async setDTRandRTS(dtr, rts) { + this.state_DTR = dtr; + this.state_RTS = rts; + await this.port.setSignals({ + dataTerminalReady: dtr, + requestToSend: rts, + }); + } + async runSignalSequence(steps) { + const webusb = this.port.isWebUSB === true; + for (const step of steps) { + if (step.dtr !== undefined && step.rts !== undefined) { + if (webusb) { + await this.setDTRandRTSWebUSB(step.dtr, step.rts); + } + else { + await this.setDTRandRTS(step.dtr, step.rts); + } + } + else { + if (step.dtr !== undefined) { + if (webusb) { + await this.setDTRWebUSB(step.dtr); + } + else { + await this.setDTR(step.dtr); + } + } + if (step.rts !== undefined) { + if (webusb) { + await this.setRTSWebUSB(step.rts); + } + else { + await this.setRTS(step.rts); + } + } + } + if (step.delayMs) + await sleep(step.delayMs); + } + } + /** + * @name hardResetUSBJTAGSerial + * USB-JTAG/Serial reset for Web Serial (Desktop) + */ + async hardResetUSBJTAGSerial() { + await this.runSignalSequence([ + { rts: false }, + { dtr: false, delayMs: 100 }, + { dtr: true, rts: false, delayMs: 100 }, + { rts: true }, + { dtr: false, rts: true, delayMs: 100 }, + { dtr: false, rts: false, delayMs: 200 }, + ]); + } + /** + * @name hardResetClassic + * Classic reset for Web Serial (Desktop) DTR = IO0, RTS = EN + */ + async hardResetClassic() { + await this.runSignalSequence([ + { dtr: false, rts: true, delayMs: 100 }, + { dtr: true, rts: false, delayMs: 50 }, + { dtr: false, delayMs: 200 }, + ]); + } + /** + * Reset to firmware mode (not bootloader) for Web Serial + * Keeps IO0=HIGH during reset so chip boots into firmware + */ + async hardResetToFirmware() { + await this.runSignalSequence([ + { dtr: false, rts: true, delayMs: 100 }, + { rts: false, delayMs: 50 }, + { delayMs: 200 }, + ]); + } + /** + * @name hardResetUnixTight + * Unix Tight reset for Web Serial (Desktop) - sets DTR and RTS simultaneously + */ + async hardResetUnixTight() { + await this.runSignalSequence([ + { dtr: true, rts: true }, + { dtr: false, rts: false }, + { dtr: false, rts: true, delayMs: 100 }, + { dtr: true, rts: false, delayMs: 50 }, + { dtr: false, rts: false }, + { dtr: false, delayMs: 200 }, + ]); + } + // ============================================================================ + // WebUSB (Android) - DTR/RTS Signal Handling & Reset Strategies + // ============================================================================ + async setRTSWebUSB(state) { + this.state_RTS = state; + // Always specify both signals to avoid flipping the other line + // The WebUSB setSignals() now preserves unspecified signals, but being explicit is safer + await this.port.setSignals({ + requestToSend: state, + dataTerminalReady: this.state_DTR, + }); + } + async setDTRWebUSB(state) { + this.state_DTR = state; + // Always specify both signals to avoid flipping the other line + await this.port.setSignals({ + dataTerminalReady: state, + requestToSend: this.state_RTS, // Explicitly preserve current RTS state + }); + } + async setDTRandRTSWebUSB(dtr, rts) { + this.state_DTR = dtr; + this.state_RTS = rts; + await this.port.setSignals({ + dataTerminalReady: dtr, + requestToSend: rts, + }); + } + /** + * @name hardResetUSBJTAGSerialInvertedDTRWebUSB + * USB-JTAG/Serial reset with inverted DTR for WebUSB (Android) + */ + async hardResetUSBJTAGSerialInvertedDTRWebUSB() { + await this.runSignalSequence([ + { rts: false, dtr: true, delayMs: 100 }, + { dtr: false, rts: false, delayMs: 100 }, + { rts: true, dtr: true, delayMs: 100 }, + { dtr: true, rts: false, delayMs: 200 }, + ]); + } + /** + * @name hardResetClassicLongDelayWebUSB + * Classic reset with longer delays for WebUSB (Android) + * Specifically for CP2102/CH340 which may need more time + */ + async hardResetClassicLongDelayWebUSB() { + await this.runSignalSequence([ + { dtr: false, rts: true, delayMs: 500 }, + { dtr: true, rts: false, delayMs: 200 }, + { dtr: false, delayMs: 500 }, + ]); + } + /** + * @name hardResetClassicShortDelayWebUSB + * Classic reset with shorter delays for WebUSB (Android) + */ + async hardResetClassicShortDelayWebUSB() { + await this.runSignalSequence([ + { dtr: false, rts: true, delayMs: 50 }, + { dtr: true, rts: false, delayMs: 25 }, + { dtr: false, delayMs: 100 }, + ]); + } + /** + * @name hardResetInvertedWebUSB + * Inverted reset sequence for WebUSB (Android) - both signals inverted + */ + async hardResetInvertedWebUSB() { + await this.runSignalSequence([ + { dtr: true, rts: false, delayMs: 100 }, + { dtr: false, rts: true, delayMs: 50 }, + { dtr: true, delayMs: 200 }, + ]); + } + /** + * @name hardResetInvertedDTRWebUSB + * Only DTR inverted for WebUSB (Android) + */ + async hardResetInvertedDTRWebUSB() { + await this.runSignalSequence([ + { dtr: true, rts: true, delayMs: 100 }, + { dtr: false, rts: false, delayMs: 50 }, + { dtr: true, delayMs: 200 }, + ]); + } + /** + * @name hardResetInvertedRTSWebUSB + * Only RTS inverted for WebUSB (Android) + */ + async hardResetInvertedRTSWebUSB() { + await this.runSignalSequence([ + { dtr: false, rts: false, delayMs: 100 }, + { dtr: true, rts: true, delayMs: 50 }, + { dtr: false, delayMs: 200 }, + ]); + } + /** + * Check if we're using WebUSB (Android) or Web Serial (Desktop) + */ + isWebUSB() { + // WebUSBSerial class has isWebUSB flag - this is the most reliable check + return this.port.isWebUSB === true; + } + /** + * @name connectWithResetStrategies + * Try different reset strategies to enter bootloader mode + * Similar to esptool.py's connect() method with multiple reset strategies + */ + async connectWithResetStrategies() { + const portInfo = this.port.getInfo(); + const isUSBJTAGSerial = portInfo.usbProductId === USB_JTAG_SERIAL_PID; + const isEspressifUSB = portInfo.usbVendorId === 0x303a; + // this.logger.log( + // `Detected USB: VID=0x${portInfo.usbVendorId?.toString(16) || "unknown"}, PID=0x${portInfo.usbProductId?.toString(16) || "unknown"}`, + // ); + // Define reset strategies to try in order + const resetStrategies = []; + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + // Detect if this is a USB-Serial chip (needs different sync approach) + const isUSBSerialChip = !isUSBJTAGSerial && !isEspressifUSB; + // WebUSB (Android) uses different reset methods than Web Serial (Desktop) + if (this.isWebUSB()) { + // For USB-Serial chips (CP2102, CH340, etc.), try inverted strategies first + // Detect specific chip types once + const isCP2102 = portInfo.usbVendorId === 0x10c4; + const isCH34x = portInfo.usbVendorId === 0x1a86; + // Check for ESP32-S2 Native USB (VID: 0x303a, PID: 0x0002) + const isESP32S2NativeUSB = portInfo.usbVendorId === 0x303a && portInfo.usbProductId === 0x0002; + // WebUSB Strategy 1: USB-JTAG/Serial reset (for Native USB only) + if (isUSBJTAGSerial || isEspressifUSB) { + if (isESP32S2NativeUSB) { + // ESP32-S2 Native USB: Try multiple strategies + // The device might be in JTAG mode OR CDC mode + // Strategy 1: USB-JTAG/Serial (works in CDC mode on Desktop) + resetStrategies.push({ + name: "USB-JTAG/Serial (WebUSB) - ESP32-S2", + fn: async () => { + return await self.hardResetUSBJTAGSerial(); + }, + }); + // Strategy 2: USB-JTAG/Serial Inverted DTR (works in JTAG mode) + resetStrategies.push({ + name: "USB-JTAG/Serial Inverted DTR (WebUSB) - ESP32-S2", + fn: async () => { + return await self.hardResetUSBJTAGSerialInvertedDTRWebUSB(); + }, + }); + // Strategy 3: UnixTight (CDC fallback) + resetStrategies.push({ + name: "UnixTight (WebUSB) - ESP32-S2 CDC", + fn: async () => { + return await self.hardResetUnixTight(); + }, + }); + // Strategy 4: Classic reset (CDC fallback) + resetStrategies.push({ + name: "Classic (WebUSB) - ESP32-S2 CDC", + fn: async () => { + return await self.hardResetClassic(); + }, + }); + } + else { + // Other USB-JTAG chips: Try Inverted DTR first - works best for ESP32-H2 and other JTAG chips + resetStrategies.push({ + name: "USB-JTAG/Serial Inverted DTR (WebUSB)", + fn: async () => { + return await self.hardResetUSBJTAGSerialInvertedDTRWebUSB(); + }, + }); + resetStrategies.push({ + name: "USB-JTAG/Serial (WebUSB)", + fn: async () => { + return await self.hardResetUSBJTAGSerial(); + }, + }); + resetStrategies.push({ + name: "Inverted DTR Classic (WebUSB)", + fn: async () => { + return await self.hardResetInvertedDTRWebUSB(); + }, + }); + } + } + // For USB-Serial chips, try inverted strategies first + if (isUSBSerialChip) { + if (isCH34x) { + // CH340/CH343: UnixTight works best (like CP2102) + resetStrategies.push({ + name: "UnixTight (WebUSB) - CH34x", + fn: async () => { + return await self.hardResetUnixTight(); + }, + }); + resetStrategies.push({ + name: "Classic (WebUSB) - CH34x", + fn: async () => { + return await self.hardResetClassic(); + }, + }); + resetStrategies.push({ + name: "Inverted Both (WebUSB) - CH34x", + fn: async () => { + return await self.hardResetInvertedWebUSB(); + }, + }); + resetStrategies.push({ + name: "Inverted RTS (WebUSB) - CH34x", + fn: async () => { + return await self.hardResetInvertedRTSWebUSB(); + }, + }); + resetStrategies.push({ + name: "Inverted DTR (WebUSB) - CH34x", + fn: async () => { + return await self.hardResetInvertedDTRWebUSB(); + }, + }); + } + else if (isCP2102) { + // CP2102: UnixTight works best (tested and confirmed) + // Try it first, then fallback to other strategies + resetStrategies.push({ + name: "UnixTight (WebUSB) - CP2102", + fn: async () => { + return await self.hardResetUnixTight(); + }, + }); + resetStrategies.push({ + name: "Classic (WebUSB) - CP2102", + fn: async () => { + return await self.hardResetClassic(); + }, + }); + resetStrategies.push({ + name: "Inverted Both (WebUSB) - CP2102", + fn: async () => { + return await self.hardResetInvertedWebUSB(); + }, + }); + resetStrategies.push({ + name: "Inverted RTS (WebUSB) - CP2102", + fn: async () => { + return await self.hardResetInvertedRTSWebUSB(); + }, + }); + resetStrategies.push({ + name: "Inverted DTR (WebUSB) - CP2102", + fn: async () => { + return await self.hardResetInvertedDTRWebUSB(); + }, + }); + } + else { + // For other USB-Serial chips, try UnixTight first, then multiple strategies + resetStrategies.push({ + name: "UnixTight (WebUSB)", + fn: async () => { + return await self.hardResetUnixTight(); + }, + }); + resetStrategies.push({ + name: "Classic (WebUSB)", + fn: async function () { + return await self.hardResetClassic(); + }, + }); + resetStrategies.push({ + name: "Inverted Both (WebUSB)", + fn: async function () { + return await self.hardResetInvertedWebUSB(); + }, + }); + resetStrategies.push({ + name: "Inverted RTS (WebUSB)", + fn: async function () { + return await self.hardResetInvertedRTSWebUSB(); + }, + }); + resetStrategies.push({ + name: "Inverted DTR (WebUSB)", + fn: async function () { + return await self.hardResetInvertedDTRWebUSB(); + }, + }); + } + } + // Add general fallback strategies only for Native USB chips (not USB-Serial) + // and only for chips not already handled by specific blocks above + if (!isUSBSerialChip && + !isCP2102 && + !isESP32S2NativeUSB && + !isUSBJTAGSerial) { + // Classic reset (for chips not handled above) + if (portInfo.usbVendorId !== 0x1a86) { + resetStrategies.push({ + name: "Classic (WebUSB)", + fn: async function () { + return await self.hardResetClassic(); + }, + }); + } + // UnixTight reset (sets DTR/RTS simultaneously) + resetStrategies.push({ + name: "UnixTight (WebUSB)", + fn: async function () { + return await self.hardResetUnixTight(); + }, + }); + // WebUSB Strategy: Classic with long delays + resetStrategies.push({ + name: "Classic Long Delay (WebUSB)", + fn: async function () { + return await self.hardResetClassicLongDelayWebUSB(); + }, + }); + // WebUSB Strategy: Classic with short delays + resetStrategies.push({ + name: "Classic Short Delay (WebUSB)", + fn: async function () { + return await self.hardResetClassicShortDelayWebUSB(); + }, + }); + // WebUSB Strategy: USB-JTAG/Serial fallback + if (!isEspressifUSB) { + resetStrategies.push({ + name: "USB-JTAG/Serial fallback (WebUSB)", + fn: async function () { + return await self.hardResetUSBJTAGSerial(); + }, + }); + } + } + } + else { + // Strategy: USB-JTAG/Serial reset + if (isUSBJTAGSerial || isEspressifUSB) { + resetStrategies.push({ + name: "USB-JTAG/Serial", + fn: async function () { + return await self.hardResetUSBJTAGSerial(); + }, + }); + } + // Strategy: UnixTight reset + resetStrategies.push({ + name: "UnixTight", + fn: async function () { + return await self.hardResetUnixTight(); + }, + }); + // Strategy: USB-JTAG/Serial fallback + if (!isUSBJTAGSerial && !isEspressifUSB) { + resetStrategies.push({ + name: "USB-JTAG/Serial (fallback)", + fn: async function () { + return await self.hardResetUSBJTAGSerial(); + }, + }); + } + } + let lastError = null; + // Try each reset strategy with timeout + for (const strategy of resetStrategies) { + try { + // Check if port is still open, if not, skip this strategy + if (!this.connected || !this.port.writable) { + this.logger.debug(`Port disconnected, skipping ${strategy.name} reset`); + continue; + } + // Clear abandon flag before starting new strategy + this._abandonCurrentOperation = false; + await strategy.fn(); + // Try to sync after reset + // USB-Serial / native USB chips needs different sync approaches + if (isUSBSerialChip) { + // USB-Serial chips: Use timeout strategy (2 seconds) + // this.logger.log(`USB-Serial chip detected, using sync with timeout.`); + const syncSuccess = await this.syncWithTimeout(2000); + if (syncSuccess) { + // Sync succeeded + this.logger.log(`Connected USB Serial successfully with ${strategy.name} reset.`); + return; + } + else { + throw new Error("Sync timeout or abandoned"); + } + } + else { + // Native USB chips + // Note: We use Promise.race with sync() directly instead of syncWithTimeout() + // because syncWithTimeout causes CDC/JTAG devices to hang for unknown reasons. + // The abandon flag in readPacket() prevents overlapping I/O. + // this.logger.log(`Native USB chip detected, using CDC/JTAG sync.`); + const syncPromise = this.sync(); + const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("Sync timeout")), 1000)); + try { + await Promise.race([syncPromise, timeoutPromise]); + // Sync succeeded + this.logger.debug(`Connected CDC/JTAG successfully with ${strategy.name} reset.`); + return; + } + catch (_error) { + throw new Error("Sync timeout or abandoned"); + } + } + } + catch (error) { + lastError = error; + // this.logger.debug( + // `${strategy.name} reset failed: ${(error as Error).message}`, + // ); + // Set abandon flag to stop any in-flight operations + this._abandonCurrentOperation = true; + // Wait a bit for in-flight operations to abort + await sleep(100); + // If port got disconnected, we can't try more strategies + if (!this.connected || !this.port.writable) { + this.logger.log(`Port disconnected during reset attempt`); + break; + } + // Clear buffers before trying next strategy + this._clearInputBuffer(); + await this.drainInputBuffer(200); + await this.flushSerialBuffers(); + } + } + // All strategies failed - reset abandon flag before throwing + this._abandonCurrentOperation = false; + throw new Error(`Couldn't sync to ESP. Try resetting manually. Last error: ${lastError === null || lastError === void 0 ? void 0 : lastError.message}`); + } + /** + * @name watchdogReset + * Watchdog reset for ESP32-S2/S3/C3 with USB-OTG or USB-JTAG/Serial + * Uses RTC watchdog timer to reset the chip - works when DTR/RTS signals are not available + * This is an alias for rtcWdtResetChipSpecific() for backwards compatibility + */ + async watchdogReset() { + await this.rtcWdtResetChipSpecific(); + } + /** + * RTC watchdog timer reset for ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C5, ESP32-C6, and ESP32-P4 + * Uses specific registers for each chip family + * Note: ESP32-H2 does NOT support WDT reset + */ + async rtcWdtResetChipSpecific() { + this.logger.debug("Hard resetting with watchdog timer..."); + let WDTWPROTECT_REG; + let WDTCONFIG0_REG; + let WDTCONFIG1_REG; + let WDT_WKEY; + if (this.chipFamily === CHIP_FAMILY_ESP32S2) { + WDTWPROTECT_REG = ESP32S2_RTC_CNTL_WDTWPROTECT_REG; + WDTCONFIG0_REG = ESP32S2_RTC_CNTL_WDTCONFIG0_REG; + WDTCONFIG1_REG = ESP32S2_RTC_CNTL_WDTCONFIG1_REG; + WDT_WKEY = ESP32S2_RTC_CNTL_WDT_WKEY; + } + else if (this.chipFamily === CHIP_FAMILY_ESP32S3) { + WDTWPROTECT_REG = ESP32S3_RTC_CNTL_WDTWPROTECT_REG; + WDTCONFIG0_REG = ESP32S3_RTC_CNTL_WDTCONFIG0_REG; + WDTCONFIG1_REG = ESP32S3_RTC_CNTL_WDTCONFIG1_REG; + WDT_WKEY = ESP32S3_RTC_CNTL_WDT_WKEY; + } + else if (this.chipFamily === CHIP_FAMILY_ESP32C3) { + WDTWPROTECT_REG = ESP32C3_RTC_CNTL_WDTWPROTECT_REG; + WDTCONFIG0_REG = ESP32C3_RTC_CNTL_WDTCONFIG0_REG; + WDTCONFIG1_REG = ESP32C3_RTC_CNTL_WDTCONFIG1_REG; + WDT_WKEY = ESP32C3_RTC_CNTL_WDT_WKEY; + } + else if (this.chipFamily === CHIP_FAMILY_ESP32C5 || + this.chipFamily === CHIP_FAMILY_ESP32C6) { + // C5 and C6 use LP_WDT (Low Power Watchdog Timer) + WDTWPROTECT_REG = ESP32C5_C6_RTC_CNTL_WDTWPROTECT_REG; + WDTCONFIG0_REG = ESP32C5_C6_RTC_CNTL_WDTCONFIG0_REG; + WDTCONFIG1_REG = ESP32C5_C6_RTC_CNTL_WDTCONFIG1_REG; + WDT_WKEY = ESP32C5_C6_RTC_CNTL_WDT_WKEY; + } + else if (this.chipFamily === CHIP_FAMILY_ESP32P4) { + // P4 uses LP_WDT (Low Power Watchdog Timer) + WDTWPROTECT_REG = ESP32P4_RTC_CNTL_WDTWPROTECT_REG; + WDTCONFIG0_REG = ESP32P4_RTC_CNTL_WDTCONFIG0_REG; + WDTCONFIG1_REG = ESP32P4_RTC_CNTL_WDTCONFIG1_REG; + WDT_WKEY = ESP32P4_RTC_CNTL_WDT_WKEY; + } + else { + throw new Error(`rtcWdtResetChipSpecific() is not supported for ${this.chipFamily}`); + } + // Unlock watchdog registers + await this.writeRegister(WDTWPROTECT_REG, WDT_WKEY, undefined, 0); + // Set WDT timeout to 2000ms (matches Python esptool) + await this.writeRegister(WDTCONFIG1_REG, 2000, undefined, 0); + // Enable WDT: bit 31 = enable, bits 28-30 = stage, bit 8 = sys reset, bits 0-2 = prescaler + const wdtConfig = (1 << 31) | (5 << 28) | (1 << 8) | 2; + await this.writeRegister(WDTCONFIG0_REG, wdtConfig, undefined, 0); + // Lock watchdog registers + await this.writeRegister(WDTWPROTECT_REG, 0, undefined, 0); + // Wait for reset to take effect + await sleep(500); + } + /** + * Reset device from bootloader mode to firmware mode + * Automatically selects the correct reset strategy based on USB connection type + * @param clearForceDownloadFlag - If true, clears the force download boot flag (USB-OTG only) + * @returns true if port will change (USB-OTG), false otherwise + */ + async resetToFirmwareMode(clearForceDownloadFlag = true) { + this.logger.debug("Resetting from bootloader to firmware mode..."); + try { + // Detect USB connection type + const isUsbJtagOrOtg = await this.detectUsbConnectionType(); + if (isUsbJtagOrOtg) { + // USB-JTAG/OTG devices need special handling + this.logger.debug("USB-JTAG/OTG detected - checking WDT reset support"); + // Get detailed USB mode information + let usbMode; + try { + usbMode = await this.getUsbMode(); + this.logger.debug(`USB mode: ${usbMode.mode} (uartNo=${usbMode.uartNo})`); + } + catch (err) { + this.logger.debug(`Could not get USB mode: ${err}`); + // Fall back to generic USB-JTAG/OTG handling + usbMode = { mode: "usb-jtag-serial", uartNo: 0 }; + } + // Check if chip supports WDT reset + // WDT reset is not needed for ESP32-C3 + // WDT reset is supported by: ESP32-S2, ESP32-S3, ESP32-P4 + // WDT reset is NOT supported by: ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 + const supportsWdtReset = this.chipFamily === CHIP_FAMILY_ESP32S2 || + this.chipFamily === CHIP_FAMILY_ESP32S3 || + this.chipFamily === CHIP_FAMILY_ESP32P4; + if (!supportsWdtReset) { + this.logger.debug(`${this.chipName} does not support WDT reset - using classic reset instead`); + // Use classic reset for chips without WDT support + await this.hardResetToFirmware(); + this.logger.debug("Classic reset to firmware complete"); + return false; // Port stays open + } + // WDT reset is supported - proceed with WDT reset logic + this.logger.debug(`${this.chipName} supports WDT reset - using WDT reset strategy`); + // CRITICAL: WDT register writes require ROM (not stub) and baudrate 115200 + // If on stub, need to return to ROM first + if (this.IS_STUB) { + this.logger.debug("On stub - returning to ROM before WDT reset"); + // Change baudrate back to ROM baudrate if needed + if (this.currentBaudRate !== ESP_ROM_BAUD) { + this.logger.debug(`Changing baudrate from ${this.currentBaudRate} to ${ESP_ROM_BAUD}`); + await this.reconfigurePort(ESP_ROM_BAUD); + this.currentBaudRate = ESP_ROM_BAUD; + this.logger.debug("Baudrate changed to 115200"); + } + // CRITICAL: Temporarily clear console mode flag so hardReset(true) works + const wasInConsoleMode = this._consoleMode; + this._consoleMode = false; + // Reset to bootloader (ROM) + await this.hardReset(true); + await sleep(200); + // Restore console mode flag + this._consoleMode = wasInConsoleMode; + // Sync with ROM + await this.sync(); + this.IS_STUB = false; + this.logger.debug("Now on ROM"); + } + else { + // Even if not on stub, ensure baudrate is 115200 for WDT register writes + if (this.currentBaudRate !== ESP_ROM_BAUD) { + this.logger.debug(`Not on stub, but baudrate is ${this.currentBaudRate} - changing to ${ESP_ROM_BAUD} for WDT reset`); + await this.reconfigurePort(ESP_ROM_BAUD); + this.currentBaudRate = ESP_ROM_BAUD; + this.logger.debug("Baudrate changed to 115200"); + } + } + // Clear force download boot flag if requested (USB-OTG only) + if (clearForceDownloadFlag && usbMode.mode === "usb-otg") { + const flagCleared = await this._clearForceDownloadBootIfNeeded(); + if (flagCleared) { + this.logger.debug("Force download boot flag cleared"); + } + } + // Perform WDT reset to boot into firmware + await this.rtcWdtResetChipSpecific(); + this.logger.debug("WDT reset performed - device will boot to firmware"); + // Check if port will change after WDT reset + // USB-OTG (ESP32-S2/P4): Port always changes + // USB-JTAG/Serial (ESP32-S3/C3/C5/C6/C61/H2/P4): Port may change depending on platform + const portWillChange = usbMode.mode === "usb-otg" || usbMode.mode === "usb-jtag-serial"; + if (portWillChange) { + this.logger.debug(`Port will change after WDT reset (${usbMode.mode}) - port reselection needed`); + return true; + } + return false; + } + else { + // External serial chip - use classic reset to firmware + this.logger.debug("External serial chip detected - using classic reset"); + await this.hardResetToFirmware(); + this.logger.debug("Classic reset to firmware complete"); + return false; + } + } + catch (err) { + this.logger.error(`Failed to reset to firmware mode: ${err}`); + throw err; + } + } + async hardReset(bootloader = false) { + // In console mode, only allow simple hardware reset (no bootloader entry) + if (this._consoleMode) { + if (bootloader) { + this.logger.debug("Skipping bootloader reset - device is in console mode"); + return; + } + // Simple hardware reset to restart firmware (IO0=HIGH) + this.logger.debug("Performing hardware reset (console mode)..."); + await this.resetInConsoleMode(); + this.logger.debug("Hardware reset complete"); + return; + } + if (bootloader) { + // Enter bootloader/flash mode + if (this.port.getInfo().usbProductId === USB_JTAG_SERIAL_PID) { + await this.hardResetUSBJTAGSerial(); + this.logger.debug("USB-JTAG/Serial reset to bootloader."); + } + else { + await this.hardResetClassic(); + this.logger.debug("Classic reset to bootloader."); + } + } + else { + // Reset to firmware mode (exit bootloader) + // Use intelligent reset strategy based on USB connection type + this.logger.debug("Resetting to firmware mode..."); + // Detect USB connection type to choose correct reset method + const isUsbJtagOrOtg = await this.detectUsbConnectionType(); + if (isUsbJtagOrOtg) { + // USB-JTAG/OTG devices: Use WDT reset + this.logger.debug("USB-JTAG/OTG detected - using WDT reset"); + // Get USB mode details + let usbMode; + try { + usbMode = await this.getUsbMode(); + this.logger.debug(`USB mode: ${usbMode.mode} (uartNo=${usbMode.uartNo})`); + } + catch (err) { + this.logger.debug(`Could not get USB mode: ${err}`); + usbMode = { mode: "usb-jtag-serial", uartNo: 0 }; + } + // Clear force download flag for USB-OTG devices + if (usbMode.mode === "usb-otg") { + try { + const flagCleared = await this._clearForceDownloadBootIfNeeded(); + if (flagCleared) { + this.logger.debug("Force download boot flag cleared"); + } + } + catch (err) { + this.logger.debug(`Could not clear force download flag: ${err}`); + } + } + // Perform WDT reset + await this.rtcWdtResetChipSpecific(); + this.logger.debug(`${this.chipName}: WDT reset to firmware complete`); + return; + } + else { + // External serial chip: Use classic reset + this.logger.debug("External serial chip detected - using classic reset"); + if (this.isWebUSB()) { + // WebUSB: Use longer delays for better compatibility + await this.setRTSWebUSB(true); // EN->LOW + await sleep(200); + await this.setRTSWebUSB(false); + await sleep(200); + this.logger.debug("Hard reset to firmware (WebUSB)."); + } + else { + // Web Serial: Standard reset + await this.setRTS(true); // EN->LOW + await sleep(100); + await this.setRTS(false); + this.logger.debug("Hard reset to firmware."); + } + } + } + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + /** + * @name macAddr + * The MAC address burned into the OTP memory of the ESP chip + */ + macAddr() { + const macAddr = new Array(6).fill(0); + const mac0 = this._efuses[0]; + const mac1 = this._efuses[1]; + const mac2 = this._efuses[2]; + const mac3 = this._efuses[3]; + let oui; + if (this.chipFamily == CHIP_FAMILY_ESP8266) { + if (mac3 != 0) { + oui = [(mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff]; + } + else if (((mac1 >> 16) & 0xff) == 0) { + oui = [0x18, 0xfe, 0x34]; + } + else if (((mac1 >> 16) & 0xff) == 1) { + oui = [0xac, 0xd0, 0x74]; + } + else { + throw new Error("Couldnt determine OUI"); + } + macAddr[0] = oui[0]; + macAddr[1] = oui[1]; + macAddr[2] = oui[2]; + macAddr[3] = (mac1 >> 8) & 0xff; + macAddr[4] = mac1 & 0xff; + macAddr[5] = (mac0 >> 24) & 0xff; + } + else if (this.chipFamily == CHIP_FAMILY_ESP32) { + macAddr[0] = (mac2 >> 8) & 0xff; + macAddr[1] = mac2 & 0xff; + macAddr[2] = (mac1 >> 24) & 0xff; + macAddr[3] = (mac1 >> 16) & 0xff; + macAddr[4] = (mac1 >> 8) & 0xff; + macAddr[5] = mac1 & 0xff; + } + else if (this.chipFamily == CHIP_FAMILY_ESP32S2 || + this.chipFamily == CHIP_FAMILY_ESP32S3 || + this.chipFamily == CHIP_FAMILY_ESP32C2 || + this.chipFamily == CHIP_FAMILY_ESP32C3 || + this.chipFamily == CHIP_FAMILY_ESP32C5 || + this.chipFamily == CHIP_FAMILY_ESP32C6 || + this.chipFamily == CHIP_FAMILY_ESP32C61 || + this.chipFamily == CHIP_FAMILY_ESP32H2 || + this.chipFamily == CHIP_FAMILY_ESP32H4 || + this.chipFamily == CHIP_FAMILY_ESP32H21 || + this.chipFamily == CHIP_FAMILY_ESP32P4 || + this.chipFamily == CHIP_FAMILY_ESP32S31) { + macAddr[0] = (mac1 >> 8) & 0xff; + macAddr[1] = mac1 & 0xff; + macAddr[2] = (mac0 >> 24) & 0xff; + macAddr[3] = (mac0 >> 16) & 0xff; + macAddr[4] = (mac0 >> 8) & 0xff; + macAddr[5] = mac0 & 0xff; + } + else { + throw new Error("Unknown chip family"); + } + return macAddr; + } + async readRegister(reg) { + if (this.debug) { + this.logger.debug("Reading from Register " + toHex(reg, 8)); + } + const packet = pack(" { + timeout = Math.min(timeout, MAX_TIMEOUT); + await this.sendCommand(opcode, buffer, checksum); + const [value, responseData] = await this.getResponse(opcode, timeout); + if (responseData === null) { + throw new Error("Didn't get enough status bytes"); + } + let data = responseData; + let statusLen = 0; + if (this.IS_STUB || this.chipFamily == CHIP_FAMILY_ESP8266) { + statusLen = 2; + } + else if ([ + CHIP_FAMILY_ESP32, + CHIP_FAMILY_ESP32S2, + CHIP_FAMILY_ESP32S3, + CHIP_FAMILY_ESP32C2, + CHIP_FAMILY_ESP32C3, + CHIP_FAMILY_ESP32C5, + CHIP_FAMILY_ESP32C6, + CHIP_FAMILY_ESP32C61, + CHIP_FAMILY_ESP32H2, + CHIP_FAMILY_ESP32H4, + CHIP_FAMILY_ESP32H21, + CHIP_FAMILY_ESP32P4, + CHIP_FAMILY_ESP32S31, + ].includes(this.chipFamily)) { + statusLen = 4; + } + else { + // When chipFamily is not yet set (e.g., during GET_SECURITY_INFO in detectChip), + // assume modern chips use 4-byte status + if (opcode === ESP_GET_SECURITY_INFO) { + statusLen = 4; + } + else if ([2, 4].includes(data.length)) { + statusLen = data.length; + } + else { + // Default to 2-byte status if we can't determine + // This prevents silent data corruption when statusLen would be 0 + statusLen = 2; + this.logger.debug(`Unknown chip family, defaulting to 2-byte status (opcode: ${toHex(opcode)}, data.length: ${data.length})`); + } + } + if (data.length < statusLen) { + throw new Error("Didn't get enough status bytes"); + } + const status = data.slice(-statusLen, data.length); + data = data.slice(0, -statusLen); + if (this.debug) { + this.logger.debug("status", status); + this.logger.debug("value", value); + this.logger.debug("data", data); + } + if (status[0] == 1) { + if (status[1] == ROM_INVALID_RECV_MSG) { + // Unsupported command can result in more than one error response + // Use drainInputBuffer for CP210x compatibility on Windows + await this.drainInputBuffer(200); + throw new Error("Invalid (unsupported) command " + toHex(opcode)); + } + else { + throw new Error("Command failure error code " + toHex(status[1])); + } + } + return [value, data]; + }; + // Chain command execution through the lock + // Use both .then() handlers to ensure lock continues even on error + this._commandLock = this._commandLock.then(executeCommand, executeCommand); + return this._commandLock; + } + /** + * @name sendCommand + * Send a slip-encoded, checksummed command over the UART, + * does not check response + */ + async sendCommand(opcode, buffer, checksum = 0) { + const packet = slipEncode([ + ...pack(" timeout) { + const waitingFor = partialPacket === null ? "header" : "content"; + throw new SlipReadError("Timed out waiting for packet " + waitingFor); + } + // If no data available, wait a bit + if (this._inputBufferAvailable === 0) { + await sleep(1); + continue; + } + // Process all available bytes without going back to outer loop + // This is critical for handling high-speed burst transfers + while (this._inputBufferAvailable > 0) { + // Periodic timeout check to prevent hang on slow data + if (Date.now() - startTime > timeout) { + const waitingFor = partialPacket === null ? "header" : "content"; + throw new SlipReadError("Timed out waiting for packet " + waitingFor); + } + const byte = this._readByte(); + if (partialPacket === null) { + // waiting for packet header + if (byte == this.SLIP_END) { + partialPacket = []; + } + else { + if (this.debug) { + this.logger.debug("Read invalid data: " + toHex(byte)); + this.logger.debug("Remaining data in serial buffer: " + + hexFormatter(this._inputBuffer)); + } + throw new SlipReadError("Invalid head of packet (" + toHex(byte) + ")"); + } + } + else if (inEscape) { + // part-way through escape sequence + inEscape = false; + if (byte == this.SLIP_ESC_END) { + partialPacket.push(this.SLIP_END); + } + else if (byte == this.SLIP_ESC_ESC) { + partialPacket.push(this.SLIP_ESC); + } + else { + if (this.debug) { + this.logger.debug("Read invalid data: " + toHex(byte)); + this.logger.debug("Remaining data in serial buffer: " + + hexFormatter(this._inputBuffer)); + } + throw new SlipReadError("Invalid SLIP escape (0xdb, " + toHex(byte) + ")"); + } + } + else if (byte == this.SLIP_ESC) { + // start of escape sequence + inEscape = true; + } + else if (byte == this.SLIP_END) { + // end of packet + if (this.debug) + this.logger.debug("Received full packet: " + hexFormatter(partialPacket)); + // Compact buffer periodically to prevent memory growth + this._compactInputBuffer(); + return partialPacket; + } + else { + // normal byte in packet + partialPacket.push(byte); + } + } + } + } + else { + // Byte-by-byte version: Stable for non CDC USB-Serial adapters (CH340, CP2102, etc.) + let readBytes = []; + while (true) { + // Check abandon flag (for reset strategy timeout) + if (this._abandonCurrentOperation) { + throw new SlipReadError("Operation abandoned (reset strategy timeout)"); + } + const stamp = Date.now(); + readBytes = []; + while (Date.now() - stamp < timeout) { + if (this._inputBufferAvailable > 0) { + readBytes.push(this._readByte()); + break; + } + else { + // Reduced sleep time for faster response during high-speed transfers + await sleep(1); + } + } + if (readBytes.length == 0) { + const waitingFor = partialPacket === null ? "header" : "content"; + throw new SlipReadError("Timed out waiting for packet " + waitingFor); + } + if (this.debug) + this.logger.debug("Read " + readBytes.length + " bytes: " + hexFormatter(readBytes)); + for (const byte of readBytes) { + if (partialPacket === null) { + // waiting for packet header + if (byte == this.SLIP_END) { + partialPacket = []; + } + else { + if (this.debug) { + this.logger.debug("Read invalid data: " + toHex(byte)); + this.logger.debug("Remaining data in serial buffer: " + + hexFormatter(this._inputBuffer)); + } + throw new SlipReadError("Invalid head of packet (" + toHex(byte) + ")"); + } + } + else if (inEscape) { + // part-way through escape sequence + inEscape = false; + if (byte == this.SLIP_ESC_END) { + partialPacket.push(this.SLIP_END); + } + else if (byte == this.SLIP_ESC_ESC) { + partialPacket.push(this.SLIP_ESC); + } + else { + if (this.debug) { + this.logger.debug("Read invalid data: " + toHex(byte)); + this.logger.debug("Remaining data in serial buffer: " + + hexFormatter(this._inputBuffer)); + } + throw new SlipReadError("Invalid SLIP escape (0xdb, " + toHex(byte) + ")"); + } + } + else if (byte == this.SLIP_ESC) { + // start of escape sequence + inEscape = true; + } + else if (byte == this.SLIP_END) { + // end of packet + if (this.debug) + this.logger.debug("Received full packet: " + hexFormatter(partialPacket)); + // Compact buffer periodically to prevent memory growth + this._compactInputBuffer(); + return partialPacket; + } + else { + // normal byte in packet + partialPacket.push(byte); + } + } + } + } + } + /** + * @name getResponse + * Read response data and decodes the slip packet, then parses + * out the value/data and returns as a tuple of (value, data) where + * each is a list of bytes + */ + async getResponse(opcode, timeout = DEFAULT_TIMEOUT) { + for (let i = 0; i < 100; i++) { + const packet = await this.readPacket(timeout); + if (packet.length < 8) { + continue; + } + const [resp, opRet, , val] = unpack(">> ESP32C5_PCR_SYSCLK_XTAL_FREQ_S); + } + async getC5CrystalFreqDetected() { + const UART_CLKDIV_MASK = 0xfffff; + const uartDiv = (await this.readRegister(ESP32C5_UART_CLKDIV_REG)) & UART_CLKDIV_MASK; + const estXtal = (ESP_ROM_BAUD * uartDiv) / 1e6; + if (estXtal > 45) + return 48; + if (estXtal > 33) + return 40; + return 26; + } + async setBaudrate(baud) { + const chipFamily = this._parent ? this._parent.chipFamily : this.chipFamily; + if (!this.IS_STUB && chipFamily === CHIP_FAMILY_ESP32C5) { + await this.setBaudrateC5Rom(baud); + } + else { + try { + const buffer = pack(" maxBaud) { + this.logger.log(`⚠️ WARNING: Baudrate ${baud} exceeds USB-Serial chip limit (${maxBaud})!`); + this.logger.log(`⚠️ This may cause data corruption or connection failures!`); + } + this.logger.debug(`Changed baud rate to ${baud}`); + } + async setBaudrateC5Rom(baud) { + const crystalFreqRomExpect = await this.getC5CrystalFreqRomExpect(); + const crystalFreqDetect = await this.getC5CrystalFreqDetected(); + this.logger.log(`ROM expects crystal freq: ${crystalFreqRomExpect} MHz, detected ${crystalFreqDetect} MHz.`); + let baudRate = baud; + if (crystalFreqDetect === 48 && crystalFreqRomExpect === 40) { + baudRate = Math.trunc((baud * 40) / 48); + } + else if (crystalFreqDetect === 40 && crystalFreqRomExpect === 48) { + baudRate = Math.trunc((baud * 48) / 40); + } + this.logger.log(`Changing baud rate to ${baudRate}...`); + try { + const buffer = pack(" timeoutMs) { + return false; + } + // Check abandon flag + if (this._abandonCurrentOperation) { + return false; + } + this._clearInputBuffer(); + try { + const response = await this._sync(); + if (response) { + await sleep(SYNC_TIMEOUT); + return true; + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } + catch (e) { + // Check abandon flag after error + if (this._abandonCurrentOperation) { + return false; + } + } + await sleep(SYNC_TIMEOUT); + } + return false; + } + /** + * @name sync + * Put into ROM bootload mode & attempt to synchronize with the + * ESP ROM bootloader, we will retry a few times + */ + async sync() { + for (let i = 0; i < 5; i++) { + this._clearInputBuffer(); + const response = await this._sync(); + if (response) { + await sleep(SYNC_TIMEOUT); + return true; + } + await sleep(SYNC_TIMEOUT); + } + throw new Error("Couldn't sync to ESP. Try resetting."); + } + /** + * @name _sync + * Perform a soft-sync using AT sync packets, does not perform + * any hardware resetting + */ + async _sync() { + await this.sendCommand(ESP_SYNC, SYNC_PACKET); + for (let i = 0; i < 8; i++) { + try { + const [, data] = await this.getResponse(ESP_SYNC, SYNC_TIMEOUT); + if (data.length > 1 && data[0] == 0 && data[1] == 0) { + return true; + } + } + catch (e) { + if (this.debug) { + this.logger.debug(`Sync attempt ${i + 1} failed: ${e}`); + } + } + } + return false; + } + /** + * @name getFlashWriteSize + * Get the Flash write size based on the chip + */ + getFlashWriteSize() { + if (this.IS_STUB) { + return STUB_FLASH_WRITE_SIZE; + } + return FLASH_WRITE_SIZE; + } + /** + * @name flashData + * Program a full, uncompressed binary file into SPI Flash at + * a given offset. If an ESP32 and md5 string is passed in, will also + * verify memory. ESP8266 does not have checksum memory verification in + * ROM + */ + async flashData(binaryData, updateProgress, offset = 0, compress = false) { + if (binaryData.byteLength >= 8) { + // unpack the (potential) image header + const header = Array.from(new Uint8Array(binaryData, 0, 4)); + const headerMagic = header[0]; + const headerFlashMode = header[2]; + const headerFlashSizeFreq = header[3]; + this.logger.log(`Image header, Magic=${toHex(headerMagic)}, FlashMode=${toHex(headerFlashMode)}, FlashSizeFreq=${toHex(headerFlashSizeFreq)}`); + } + const paddedData = padTo(new Uint8Array(binaryData), 4); + binaryData = paddedData.buffer; + const uncompressedFilesize = binaryData.byteLength; + let compressedFilesize = 0; + let dataToFlash; + let timeout = DEFAULT_TIMEOUT; + if (compress) { + dataToFlash = deflate_1(new Uint8Array(binaryData), { + level: 9, + }).buffer; + compressedFilesize = dataToFlash.byteLength; + this.logger.log(`Writing data with filesize: ${uncompressedFilesize}. Compressed Size: ${compressedFilesize}`); + timeout = await this.flashDeflBegin(uncompressedFilesize, compressedFilesize, offset); + } + else { + this.logger.log(`Writing data with filesize: ${uncompressedFilesize}`); + dataToFlash = binaryData; + await this.flashBegin(uncompressedFilesize, offset); + } + let block = []; + let seq = 0; + let written = 0; + let position = 0; + const stamp = Date.now(); + const flashWriteSize = this.getFlashWriteSize(); + const filesize = compress ? compressedFilesize : uncompressedFilesize; + while (filesize - position > 0) { + if (this.debug) { + this.logger.log(`Writing at ${toHex(offset + seq * flashWriteSize, 8)} `); + } + if (filesize - position >= flashWriteSize) { + block = Array.from(new Uint8Array(dataToFlash, position, flashWriteSize)); + } + else { + // Pad the last block only if we are sending uncompressed data. + block = Array.from(new Uint8Array(dataToFlash, position, filesize - position)); + if (!compress) { + block = block.concat(new Array(flashWriteSize - block.length).fill(0xff)); + } + } + if (compress) { + await this.flashDeflBlock(block, seq, timeout); + } + else { + await this.flashBlock(block, seq); + } + seq += 1; + // If using compression we update the progress with the proportional size of the block taking into account the compression ratio. + // This way we report progress on the uncompressed size + written += compress + ? Math.round((block.length * uncompressedFilesize) / compressedFilesize) + : block.length; + position += flashWriteSize; + updateProgress(Math.min(written, uncompressedFilesize), uncompressedFilesize); + } + this.logger.log("Took " + (Date.now() - stamp) + "ms to write " + filesize + " bytes"); + // Only send flashF finish if running the stub because ir causes the ROM to exit and run user code + if (this.IS_STUB) { + await this.flashBegin(0, 0); + if (compress) { + await this.flashDeflFinish(); + } + else { + await this.flashFinish(); + } + } + } + /** + * @name flashBlock + * Send one block of data to program into SPI Flash memory + */ + async flashBlock(data, seq, timeout = DEFAULT_TIMEOUT) { + await this.checkCommand(ESP_FLASH_DATA, pack(" 0) { + // add a dummy write to a date register as an excuse to have a delay + buffer = buffer.concat(pack(" 0) { + await this.writeRegister(SPI_MOSI_DLEN_REG, mosiBits - 1); + } + if (misoBits > 0) { + await this.writeRegister(SPI_MISO_DLEN_REG, misoBits - 1); + } + } + else { + const SPI_DATA_LEN_REG = spiAddresses.regBase + spiAddresses.usr1Offs; + const SPI_MOSI_BITLEN_S = 17; + const SPI_MISO_BITLEN_S = 8; + const mosiMask = mosiBits == 0 ? 0 : mosiBits - 1; + const misoMask = misoBits == 0 ? 0 : misoBits - 1; + const value = (misoMask << SPI_MISO_BITLEN_S) | (mosiMask << SPI_MOSI_BITLEN_S); + await this.writeRegister(SPI_DATA_LEN_REG, value); + } + } + async waitDone(spiCmdReg, spiCmdUsr) { + for (let i = 0; i < 10; i++) { + const cmdValue = await this.readRegister(spiCmdReg); + if ((cmdValue & spiCmdUsr) == 0) { + return; + } + } + throw Error("SPI command did not complete in time"); + } + async runSpiFlashCommand(spiflashCommand, data, readBits = 0) { + // Run an arbitrary SPI flash command. + // This function uses the "USR_COMMAND" functionality in the ESP + // SPI hardware, rather than the precanned commands supported by + // hardware. So the value of spiflash_command is an actual command + // byte, sent over the wire. + // After writing command byte, writes 'data' to MOSI and then + // reads back 'read_bits' of reply on MISO. Result is a number. + // SPI_USR register flags + const SPI_USR_COMMAND = 1 << 31; + const SPI_USR_MISO = 1 << 28; + const SPI_USR_MOSI = 1 << 27; + // SPI registers, base address differs + const spiAddresses = getSpiFlashAddresses(this.getChipFamily()); + const base = spiAddresses.regBase; + const SPI_CMD_REG = base; + const SPI_USR_REG = base + spiAddresses.usrOffs; + const SPI_USR2_REG = base + spiAddresses.usr2Offs; + const SPI_W0_REG = base + spiAddresses.w0Offs; + // SPI peripheral "command" bitmasks for SPI_CMD_REG + const SPI_CMD_USR = 1 << 18; + // shift values + const SPI_USR2_COMMAND_LEN_SHIFT = 28; + if (readBits > 32) { + throw new Error("Reading more than 32 bits back from a SPI flash operation is unsupported"); + } + if (data.length > 64) { + throw new Error("Writing more than 64 bytes of data with one SPI command is unsupported"); + } + const dataBits = data.length * 8; + const oldSpiUsr = await this.readRegister(SPI_USR_REG); + const oldSpiUsr2 = await this.readRegister(SPI_USR2_REG); + let flags = SPI_USR_COMMAND; + if (readBits > 0) { + flags |= SPI_USR_MISO; + } + if (dataBits > 0) { + flags |= SPI_USR_MOSI; + } + await this.setDataLengths(spiAddresses, dataBits, readBits); + await this.writeRegister(SPI_USR_REG, flags); + await this.writeRegister(SPI_USR2_REG, (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand); + if (dataBits == 0) { + await this.writeRegister(SPI_W0_REG, 0); // clear data register before we read it + } + else { + const padLen = (4 - (data.length % 4)) % 4; + data = data.concat(new Array(padLen).fill(0x00)); // pad to 32-bit multiple + const words = unpack("I".repeat(Math.floor(data.length / 4)), data); + let nextReg = SPI_W0_REG; + this.logger.debug(`Words Length: ${words.length}`); + for (const word of words) { + this.logger.debug(`Writing word ${toHex(word)} to register offset ${toHex(nextReg)}`); + await this.writeRegister(nextReg, word); + nextReg += 4; + } + } + await this.writeRegister(SPI_CMD_REG, SPI_CMD_USR); + await this.waitDone(SPI_CMD_REG, SPI_CMD_USR); + const status = await this.readRegister(SPI_W0_REG); + // restore some SPI controller registers + await this.writeRegister(SPI_USR_REG, oldSpiUsr); + await this.writeRegister(SPI_USR2_REG, oldSpiUsr2); + return status; + } + async detectFlashSize() { + this.logger.debug("Detecting Flash Size"); + const flashId = await this.flashId(); + const manufacturer = flashId & 0xff; + const flashIdLowbyte = (flashId >> 16) & 0xff; + const deviceTypeByte = (flashId >> 8) & 0xff; + const deviceId = (deviceTypeByte << 8) | flashIdLowbyte; + const jedecId = (manufacturer << 16) | deviceId; + const mfrName = FLASH_MANUFACTURERS[manufacturer]; + const deviceName = FLASH_DEVICES[jedecId]; + this.logger.log(`Flash Manufacturer: ${mfrName || "Unknown"} (0x${manufacturer.toString(16)})`); + this.logger.log(`Flash Device: ${deviceName || `Unknown (0x${deviceId.toString(16)})`}`); + this.flashSize = DETECTED_FLASH_SIZES[flashIdLowbyte]; + this.logger.log(`Auto-detected Flash size: ${this.flashSize}`); + } + /** + * @name getEraseSize + * Calculate an erase size given a specific size in bytes. + * Provides a workaround for the bootloader erase bug on ESP8266. + */ + getEraseSize(offset, size) { + const sectorsPerBlock = 16; + const sectorSize = FLASH_SECTOR_SIZE; + const numSectors = Math.floor((size + sectorSize - 1) / sectorSize); + const startSector = Math.floor(offset / sectorSize); + let headSectors = sectorsPerBlock - (startSector % sectorsPerBlock); + if (numSectors < headSectors) { + headSectors = numSectors; + } + if (numSectors < 2 * headSectors) { + return Math.floor(((numSectors + 1) / 2) * sectorSize); + } + return (numSectors - headSectors) * sectorSize; + } + /** + * @name memBegin (592) + * Start downloading an application image to RAM + */ + async memBegin(size, blocks, blocksize, offset) { + return await this.checkCommand(ESP_MEM_BEGIN, pack(" length) { + toOffs = length; + } + await this.memBlock(fieldData.slice(fromOffs, toOffs), seq); + } + } + await this.memFinish(stub.entry); + const p = await this.readPacket(500); + const pChar = String.fromCharCode(...p); + if (pChar != "OHAI") { + throw new Error("Failed to start stub. Unexpected response: " + pChar); + } + this.logger.debug("Stub is now running..."); + const espStubLoader = new EspStubLoader(this.port, this.logger, this); + // Try to autodetect the flash size. + if (!skipFlashDetection) { + await espStubLoader.detectFlashSize(); + } + return espStubLoader; + } + get _writer() { + return this._parent ? this._parent._writer : this.__writer; + } + set _writer(value) { + if (this._parent) { + this._parent._writer = value; + } + else { + this.__writer = value; + } + } + get _writeChain() { + return this._parent ? this._parent._writeChain : this.__writeChain; + } + set _writeChain(value) { + if (this._parent) { + this._parent._writeChain = value; + } + else { + this.__writeChain = value; + } + } + async writeToStream(data) { + if (!this.port.writable) { + this.logger.debug("Port writable stream not available, skipping write"); + return; + } + if (this._isReconfiguring) { + throw new Error("Cannot write during port reconfiguration"); + } + // Queue writes to prevent lock contention (critical for CP2102 on Windows) + this._writeChain = this._writeChain + .then(async () => { + // Check if port is still writable before attempting write + if (!this.port.writable) { + throw new Error("Port became unavailable during write"); + } + // Get or create persistent writer + if (!this._writer) { + try { + this._writer = this.port.writable.getWriter(); + } + catch (err) { + this.logger.error(`Failed to get writer: ${err}`); + throw err; + } + } + // Perform the write + await this._writer.write(new Uint8Array(data)); + }, async () => { + // Previous write failed, but still attempt this write + this.logger.debug("Previous write failed, attempting recovery for current write"); + if (!this.port.writable) { + throw new Error("Port became unavailable during write"); + } + // Writer was likely cleaned up by previous error, create new one + if (!this._writer) { + try { + this._writer = this.port.writable.getWriter(); + } + catch (err) { + this.logger.debug(`Failed to get writer in recovery: ${err}`); + throw new Error("Cannot acquire writer lock"); + } + } + await this._writer.write(new Uint8Array(data)); + }) + .catch((err) => { + this.logger.error(`Write error: ${err}`); + // Ensure writer is cleaned up on any error + if (this._writer) { + try { + this._writer.releaseLock(); + } + catch { + // Ignore release errors + } + this._writer = undefined; + } + // Re-throw to propagate error + throw err; + }); + // Always await the write chain to ensure errors are caught + await this._writeChain; + } + async disconnect() { + if (this._parent) { + await this._parent.disconnect(); + return; + } + if (!this.port.writable) { + // this.logger.debug("Port already closed, skipping disconnect"); + return; + } + // Wait for pending writes to complete + try { + await this._writeChain; + } + catch (_err) { + // this.logger.debug(`Pending write error during disconnect: ${err}`); + } + // Release persistent writer before closing + if (this._writer) { + try { + await this._writer.close(); + this._writer.releaseLock(); + } + catch (_err) { + // this.logger.debug(`Writer close/release error: ${err}`); + } + this._writer = undefined; + } + else { + // No persistent writer exists, close stream directly + // This path is taken when no writes have been queued + try { + const writer = this.port.writable.getWriter(); + await writer.close(); + writer.releaseLock(); + } + catch (_err) { + // this.logger.debug(`Direct writer close error: ${err}`); + } + } + await new Promise((resolve) => { + if (!this._reader) { + resolve(undefined); + return; + } + // Set a timeout to prevent hanging (important for node-usb) + const timeout = setTimeout(() => { + this.logger.debug("Disconnect timeout - forcing resolution"); + resolve(undefined); + }, 1000); + this.addEventListener("disconnect", () => { + clearTimeout(timeout); + resolve(undefined); + }, { once: true }); + // Only cancel if reader is still active + try { + this._reader.cancel(); + } + catch (_err) { + // Reader already released, resolve immediately + clearTimeout(timeout); + resolve(undefined); + } + }); + this.connected = false; + // Close the port (important for node-usb adapter) + try { + await this.port.close(); + this.logger.debug("Port closed successfully"); + } + catch (err) { + this.logger.debug(`Port close error: ${err}`); + } + } + /** + * @name releaseReaderWriter + * Release reader and writer locks without closing the port + * Used when switching to console mode + */ + async releaseReaderWriter() { + if (this._parent) { + await this._parent.releaseReaderWriter(); + return; + } + // Wait for pending writes to complete + try { + await this._writeChain; + } + catch (_err) { + // this.logger.debug(`Pending write error during release: ${err}`); + } + // Release writer + if (this._writer) { + try { + this._writer.releaseLock(); + this.logger.debug("Writer released"); + } + catch (err) { + this.logger.debug(`Writer release error: ${err}`); + } + this._writer = undefined; + } + // Cancel reader - let readLoop's finally block handle releaseLock() + if (this._reader) { + try { + // Suppress disconnect event during console mode switching + this._suppressDisconnect = true; + // Cancel will cause readLoop to exit and call releaseLock() in its finally block + await this._reader.cancel(); + this.logger.debug("Reader cancelled - waiting for readLoop to finish"); + // CRITICAL: Wait a bit for readLoop's finally block to complete + // The finally block needs time to call releaseLock() and set _reader = undefined + // This is much faster than waiting for browser to unlock (just waiting for JS execution) + await sleep(50); + this.logger.debug("ReadLoop cleanup should be complete"); + } + catch (err) { + this.logger.debug(`Reader cancel error: ${err}`); + } + // Don't call releaseLock() or set _reader to undefined here + // Let readLoop's finally block handle it to avoid race conditions + } + } + /** + * @name resetToFirmware + * Public method to reset device from bootloader to firmware for console mode + * Automatically detects USB-JTAG/Serial and USB-OTG devices and performs appropriate reset + * @returns true if reset was performed, false if not needed + */ + async resetToFirmware() { + return await this._resetToFirmwareIfNeeded(); + } + /** + * @name detectUsbConnectionType + * Detect if device is using USB-JTAG/Serial or USB-OTG (not external serial chip) + * Uses USB PID (Product ID) for reliable detection - does NOT require chipFamily + * @returns true if USB-JTAG or USB-OTG, false if external serial chip + */ + async detectUsbConnectionType() { + // Use PID-based detection + const portInfo = this.port.getInfo(); + const pid = portInfo.usbProductId; + const vid = portInfo.usbVendorId; + // Check if this is an Espressif device + const isEspressif = vid === 0x303a; + if (!isEspressif) { + this.logger.debug("Not Espressif VID - external serial chip"); + return false; + } + // ESP32-S2/S3/C3/C5/C6/C61/H2/P4 USB-JTAG/OTG PIDs + // According to official Espressif documentation: + // https://docs.espressif.com/projects/esp-iot-solution/en/latest/usb/usb_overview/usb_device_const_COM.html + // 0x0002 = ESP32-S2 USB-OTG, 0x0012 = ESP32-P4 USB-Serial-JTAG + // 0x1001 = ESP32-S3, C3, C5, C6, C61, H2 USB-Serial-JTAG + const usbJtagPids = [0x0002, 0x0012, 0x1001]; + const isUsbJtag = usbJtagPids.includes(pid || 0); + this.logger.debug(`USB-JTAG/OTG detection: ${isUsbJtag ? "YES" : "NO"} (PID=0x${pid === null || pid === void 0 ? void 0 : pid.toString(16)})`); + return isUsbJtag; + } + async getUsbMode() { + var _a, _b; + const family = this._parent ? this._parent.chipFamily : this.chipFamily; + const revision = this._parent + ? ((_a = this._parent.chipRevision) !== null && _a !== void 0 ? _a : 0) + : ((_b = this.chipRevision) !== null && _b !== void 0 ? _b : 0); + let bufNoAddr = null; + let jtagSerialVal = null; + let otgVal = null; + switch (family) { + case CHIP_FAMILY_ESP32S2: + bufNoAddr = ESP32S2_UARTDEV_BUF_NO; + otgVal = ESP32S2_UARTDEV_BUF_NO_USB_OTG; + break; + case CHIP_FAMILY_ESP32S3: + bufNoAddr = ESP32S3_UARTDEV_BUF_NO; + jtagSerialVal = ESP32S3_UARTDEV_BUF_NO_USB_JTAG_SERIAL; + otgVal = ESP32S3_UARTDEV_BUF_NO_USB_OTG; + break; + case CHIP_FAMILY_ESP32C3: { + const bssAddr = revision < 101 ? 0x3fcdf064 : 0x3fcdf060; + bufNoAddr = bssAddr + ESP32C3_BUF_UART_NO_OFFSET; + jtagSerialVal = ESP32C3_UARTDEV_BUF_NO_USB_JTAG_SERIAL; + break; + } + case CHIP_FAMILY_ESP32C5: + bufNoAddr = ESP32C5_UARTDEV_BUF_NO; + jtagSerialVal = ESP32C5_UARTDEV_BUF_NO_USB_JTAG_SERIAL; + break; + case CHIP_FAMILY_ESP32C6: + bufNoAddr = ESP32C6_UARTDEV_BUF_NO; + jtagSerialVal = ESP32C6_UARTDEV_BUF_NO_USB_JTAG_SERIAL; + break; + case CHIP_FAMILY_ESP32C61: + bufNoAddr = + revision <= 200 + ? ESP32C61_UARTDEV_BUF_NO_REV_LE2 + : ESP32C61_UARTDEV_BUF_NO_REV_GT2; + jtagSerialVal = + revision <= 200 + ? ESP32C61_UARTDEV_BUF_NO_USB_JTAG_SERIAL_REV_LE2 + : ESP32C61_UARTDEV_BUF_NO_USB_JTAG_SERIAL_REV_GT2; + break; + case CHIP_FAMILY_ESP32H2: + bufNoAddr = ESP32H2_UARTDEV_BUF_NO; + jtagSerialVal = ESP32H2_UARTDEV_BUF_NO_USB_JTAG_SERIAL; + break; + case CHIP_FAMILY_ESP32H4: + bufNoAddr = ESP32H4_UARTDEV_BUF_NO; + jtagSerialVal = ESP32H4_UARTDEV_BUF_NO_USB_JTAG_SERIAL; + break; + case CHIP_FAMILY_ESP32P4: + bufNoAddr = + revision < 300 + ? ESP32P4_UARTDEV_BUF_NO_REV0 + : ESP32P4_UARTDEV_BUF_NO_REV300; + jtagSerialVal = ESP32P4_UARTDEV_BUF_NO_USB_JTAG_SERIAL; + otgVal = ESP32P4_UARTDEV_BUF_NO_USB_OTG; + break; + } + if (bufNoAddr === null) { + return { mode: "uart", uartNo: 0 }; + } + const uartNo = (await this.readRegister(bufNoAddr)) & 0xff; + if (otgVal !== null && uartNo === otgVal) { + this.logger.debug(`USB mode: USB-OTG (uartNo=${uartNo})`); + return { mode: "usb-otg", uartNo }; + } + if (jtagSerialVal !== null && uartNo === jtagSerialVal) { + this.logger.debug(`USB mode: USB-JTAG/Serial (uartNo=${uartNo})`); + return { mode: "usb-jtag-serial", uartNo }; + } + this.logger.debug(`USB mode: UART (uartNo=${uartNo})`); + return { mode: "uart", uartNo }; + } + /** + * Check if the current chip supports USB-JTAG or USB-OTG + * @returns true if chip has native USB support (JTAG or OTG) + */ + supportsNativeUsb() { + const family = this._parent ? this._parent.chipFamily : this.chipFamily; + // Chips with USB-JTAG/Serial or USB-OTG support + const usbChips = [ + CHIP_FAMILY_ESP32S2, // USB-OTG + CHIP_FAMILY_ESP32S3, // USB-OTG + USB-JTAG/Serial + CHIP_FAMILY_ESP32C3, // USB-JTAG/Serial + CHIP_FAMILY_ESP32C5, // USB-JTAG/Serial + CHIP_FAMILY_ESP32C6, // USB-JTAG/Serial + CHIP_FAMILY_ESP32C61, // USB-JTAG/Serial + CHIP_FAMILY_ESP32H2, // USB-JTAG/Serial + CHIP_FAMILY_ESP32H4, // USB-JTAG/Serial + CHIP_FAMILY_ESP32P4, // USB-OTG + USB-JTAG/Serial + ]; + return usbChips.includes(family); + } + /** + * @name _ensureStreamsReady + * After a hardware reset, ensure port streams are available. + * On WebUSB, recreates streams since they break after reset. + * On Web Serial, waits for streams to become available. + */ + async _ensureStreamsReady() { + if (this.isWebUSB()) { + try { + await this.port.recreateStreams(); + this.logger.debug("WebUSB streams recreated"); + let retries = 30; + while (retries > 0 && !this.port.readable) { + await sleep(100); + retries--; + } + if (!this.port.readable) { + throw new Error("Readable stream not available after recreating streams"); + } + this.logger.debug("WebUSB streams are ready"); + } + catch (err) { + this.logger.error(`Failed to recreate WebUSB streams: ${err}`); + this._consoleMode = false; + throw err; + } + } + else { + let retries = 20; + while (retries > 0 && !this.port.readable) { + await sleep(100); + retries--; + } + if (!this.port.readable) { + this._consoleMode = false; + throw new Error("Readable stream not available after reset"); + } + this.logger.debug("Port streams are ready"); + } + } + /** + * @name enterConsoleMode + * Prepare device for console mode by resetting to firmware + * Handles both USB-JTAG/OTG devices (closes port) and external serial chips (keeps port open) + * @returns true if port was closed (USB-JTAG), false if port stays open (serial chip) + */ + async enterConsoleMode() { + // Check if port is open - if not, we need a new port selection + if (!this.port.writable || !this.port.readable) { + this.logger.debug("Port is not open - port selection needed"); + // Return true to signal that port selection is needed + // The caller should handle port selection and try again + return true; + } + // Re-detect USB connection type to ensure we have a definitive value + let isUsbJtag; + try { + isUsbJtag = await this.detectUsbConnectionType(); + this.logger.debug(`USB connection type detected: ${isUsbJtag ? "USB-JTAG/OTG" : "External Serial Chip"}`); + // CRITICAL: Set the cached value so _resetToFirmwareIfNeeded() can use it + this._isUsbJtagOrOtg = isUsbJtag; + } + catch (err) { + // If detection fails, fall back to cached value or fail-fast + if (this.isUsbJtagOrOtg === undefined) { + throw new Error(`Cannot enter console mode: USB connection type unknown and detection failed: ${err}`); + } + this.logger.debug(`USB detection failed, using cached value: ${this.isUsbJtagOrOtg}`); + isUsbJtag = this.isUsbJtagOrOtg; + } + // Set console mode flag BEFORE any operations + this._consoleMode = true; + if (isUsbJtag) { + // USB-JTAG/OTG devices: Use reset which may close port + const wasReset = await this._resetToFirmwareIfNeeded(); + if (wasReset) { + return true; // port closed, caller must reopen + } + // Port stayed open (e.g. C3/C5/C6/H2 classic reset) + await this._ensureStreamsReady(); + return false; + } + else { + // External serial chip devices: Release locks and do simple reset + try { + await this.releaseReaderWriter(); + await sleep(100); + } + catch (err) { + this.logger.debug(`Failed to release locks: ${err}`); + } + try { + await this.hardResetToFirmware(); + this.logger.debug("Device reset to firmware mode"); + } + catch (err) { + this.logger.debug(`Could not reset device: ${err}`); + } + await this._ensureStreamsReady(); + return false; + } + } + /** + * @name _clearForceDownloadBootIfNeeded + * Read and clear the force download boot flag if it is set + * This should ONLY be called when on ROM (not stub) and before WDT reset + * Clearing it on every connect causes issues with flash operations + * Returns true if the flag was cleared, false if it was already clear + */ + async _clearForceDownloadBootIfNeeded() { + try { + let regAddr; + let mask; + let chipName; + // Get register address and mask for this chip + if (this.chipFamily === CHIP_FAMILY_ESP32S2) { + regAddr = ESP32S2_RTC_CNTL_OPTION1_REG; + mask = ESP32S2_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK; + chipName = "ESP32-S2"; + } + else if (this.chipFamily === CHIP_FAMILY_ESP32S3) { + regAddr = ESP32S3_RTC_CNTL_OPTION1_REG; + mask = ESP32S3_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK; + chipName = "ESP32-S3"; + } + else if (this.chipFamily === CHIP_FAMILY_ESP32P4) { + regAddr = ESP32P4_RTC_CNTL_OPTION1_REG; + mask = ESP32P4_RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK; + chipName = "ESP32-P4"; + } + else { + // Not a chip that needs this + return false; + } + // Read current register value + const currentValue = await this.readRegister(regAddr); + this.logger.debug(`${chipName} force download boot register: 0x${currentValue.toString(16)} (mask: 0x${mask.toString(16)})`); + // Check if the flag is set + const isFlagSet = (currentValue & mask) !== 0; + if (isFlagSet) { + this.logger.debug(`${chipName} force download boot flag is SET - clearing it`); + // Clear the flag by writing 0 to the masked bits + await this.writeRegister(regAddr, 0, mask, 0); + this.logger.debug(`${chipName} force download boot flag cleared`); + return true; + } + else { + this.logger.debug(`${chipName} force download boot flag is already CLEAR - no action needed`); + return false; + } + } + catch (err) { + this.logger.debug(`Error checking/clearing force download flag: ${err}`); + return false; + } + } + /** + * @name _resetToFirmwareIfNeeded + * Reset device from bootloader to firmware when switching to console mode + * Detects USB-JTAG/Serial and USB-OTG devices and performs appropriate reset + * @returns true if reconnect was performed, false otherwise + */ + async _resetToFirmwareIfNeeded() { + // Detect if we need WDT reset (USB-JTAG/OTG) or classic reset + const isUsbJtagOrOtg = await this.detectUsbConnectionType(); + try { + // Check if port is open - if not, assume device is already in firmware mode + if (!this.port.writable || !this.port.readable) { + this.logger.debug("Port is not open - assuming device is already in firmware mode"); + return false; + } + if (isUsbJtagOrOtg) { + // USB-JTAG/OTG: DON'T release reader/writer before WDT reset + // The WDT reset needs active communication to send register write commands + // The port will close automatically after the WDT reset anyway + this.logger.debug("USB-JTAG/OTG: Keeping reader/writer active for WDT reset"); + } + else { + // External serial chip: Release reader/writer before classic reset + await this.releaseReaderWriter(); + this.logger.debug("External serial: Reader/writer released before reset"); + } + // Use the new resetToFirmwareMode method which handles all the logic + const portWillChange = await this.resetToFirmwareMode(true); + if (portWillChange) { + this.logger.debug(`${this.chipName}: Port will change after WDT reset - user must reselect port`); + // Dispatch event to signal port change + this.dispatchEvent(new CustomEvent("usb-otg-port-change", { + detail: { + chipName: this.chipName, + message: `${this.chipName} USB port changed after reset. Please select the new port.`, + reason: "wdt-reset-to-firmware", + }, + })); + return true; + } + else { + // Port stays the same - release reader/writer now if not already done + if (isUsbJtagOrOtg) { + await this.releaseReaderWriter(); + this.logger.debug("Reader/writer released after reset"); + } + return false; + } + } + catch (err) { + this.logger.error(`Reset to firmware mode failed: ${err}`); + // For USB-JTAG/OTG, the port is likely dead after a failed reset + // For external serial, the port is usually still fine + if (isUsbJtagOrOtg) { + this.logger.debug("Forcing port reselection due to USB-JTAG/OTG reset failure"); + return true; + } + this.logger.debug("External serial reset failed, but port should still be usable"); + return false; + } + } + /** + * @name reconnectAndResume + * Reconnect the serial port to flush browser buffers and reload stub + */ + async reconnect() { + if (this._parent) { + await this._parent.reconnect(); + return; + } + try { + this.logger.log("Reconnecting serial port..."); + const savedBaudRate = this.currentBaudRate; + this.connected = false; + this.__inputBuffer = []; + this.__inputBufferReadIndex = 0; + // Wait for pending writes to complete + try { + await this._writeChain; + } + catch (err) { + this.logger.debug(`Pending write error during reconnect: ${err}`); + } + // Block new writes during port close/open + this._isReconfiguring = true; + // Release persistent writer + if (this._writer) { + try { + this._writer.releaseLock(); + } + catch (err) { + this.logger.debug(`Writer release error during reconnect: ${err}`); + } + this._writer = undefined; + } + // Cancel reader + if (this._reader) { + try { + await this._reader.cancel(); + } + catch (err) { + this.logger.debug(`Reader cancel error: ${err}`); + } + this._reader = undefined; + } + // Close port + try { + await this.port.close(); + this.logger.debug("Port closed"); + } + catch (err) { + this.logger.debug(`Port close error: ${err}`); + } + // Open the port + this.logger.debug("Opening port..."); + try { + await this.port.open({ baudRate: ESP_ROM_BAUD }); + this.connected = true; + this.currentBaudRate = ESP_ROM_BAUD; + } + catch (err) { + throw new Error(`Failed to open port: ${err}`); + } + // Verify port streams are available + if (!this.port.readable || !this.port.writable) { + throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`); + } + // Port is now open and ready - allow writes for initialization + this._isReconfiguring = false; + // Save chip info and flash size (no need to detect again) + const savedChipFamily = this.chipFamily; + const savedChipName = this.chipName; + const savedChipRevision = this.chipRevision; + const savedChipVariant = this.chipVariant; + const savedFlashSize = this.flashSize; + // Reinitialize + await this.hardReset(true); + if (!this._parent) { + this.__inputBuffer = []; + this.__inputBufferReadIndex = 0; + this.__totalBytesRead = 0; + this.readLoop(); + } + await this.flushSerialBuffers(); + await this.sync(); + // Restore chip info + this.chipFamily = savedChipFamily; + this.chipName = savedChipName; + this.chipRevision = savedChipRevision; + this.chipVariant = savedChipVariant; + this.flashSize = savedFlashSize; + this.logger.debug(`Reconnect complete (chip: ${this.chipName})`); + // Verify port is ready + if (!this.port.writable || !this.port.readable) { + throw new Error("Port not ready after reconnect"); + } + // Power on flash for ESP32-P4 Rev 301 (must be done before loading stub) + if (this.chipFamily === CHIP_FAMILY_ESP32P4 && + this.chipRevision === 301) { + await this.powerOnFlash(); + } + // Load stub + const stubLoader = await this.runStub(true); + this.logger.debug("Stub loaded"); + // Restore baudrate if it was changed + if (savedBaudRate !== ESP_ROM_BAUD) { + await stubLoader.setBaudrate(savedBaudRate); + // Verify port is still ready after baudrate change + if (!this.port.writable || !this.port.readable) { + throw new Error(`Port not ready after baudrate change (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`); + } + } + // The stub is now running on the chip + // stubLoader has this instance as _parent, so all operations go through this + // We just need to mark this instance as running stub code + this.IS_STUB = true; + this.logger.debug("Reconnection successful"); + } + catch (err) { + // Ensure flag is reset on error + this._isReconfiguring = false; + throw err; + } + } + /** + * @name reconnectToBootloader + * Close and reopen the port, then reset ESP to bootloader mode + * This is needed after Improv or other operations that leave ESP in firmware mode + */ + async reconnectToBootloader() { + if (this._parent) { + await this._parent.reconnectToBootloader(); + return; + } + try { + this.logger.log("Reconnecting to bootloader mode..."); + // Clear console mode flag when reconnecting to bootloader + this._consoleMode = false; + this.connected = false; + this.__inputBuffer = []; + this.__inputBufferReadIndex = 0; + // Wait for pending writes to complete + try { + await this._writeChain; + } + catch (err) { + this.logger.debug(`Pending write error during reconnect: ${err}`); + } + // Block new writes during port close/open + this._isReconfiguring = true; + // Release persistent writer + if (this._writer) { + try { + this._writer.releaseLock(); + } + catch (err) { + this.logger.debug(`Writer release error during reconnect: ${err}`); + } + this._writer = undefined; + } + // Cancel reader + if (this._reader) { + try { + await this._reader.cancel(); + } + catch (err) { + this.logger.debug(`Reader cancel error: ${err}`); + } + this._reader = undefined; + } + // Close port + try { + await this.port.close(); + this.logger.debug("Port closed"); + } + catch (err) { + this.logger.debug(`Port close error: ${err}`); + } + // Open the port + this.logger.debug("Opening port..."); + try { + await this.port.open({ baudRate: ESP_ROM_BAUD }); + this.connected = true; + this.currentBaudRate = ESP_ROM_BAUD; + } + catch (err) { + throw new Error(`Failed to open port: ${err}`); + } + // Verify port streams are available + if (!this.port.readable || !this.port.writable) { + throw new Error(`Port streams not available after open (readable: ${!!this.port.readable}, writable: ${!!this.port.writable})`); + } + // Port is now open and ready - allow writes for initialization + this._isReconfiguring = false; + // Reset chip info and stub state + this.__chipFamily = undefined; + this.chipName = "Unknown Chip"; + this.chipRevision = null; + this.chipVariant = null; + this.IS_STUB = false; + // Start read loop + if (!this._parent) { + this.__inputBuffer = []; + this.__inputBufferReadIndex = 0; + this.__totalBytesRead = 0; + this.readLoop(); + } + // Wait for readLoop to start + await sleep(100); + // Reset to bootloader mode using multiple strategies + await this.connectWithResetStrategies(); + // Detect chip type + await this.detectChip(); + this.logger.debug(`Reconnected to bootloader: ${this.chipName}`); + } + catch (err) { + // Ensure flag is reset on error + this._isReconfiguring = false; + throw err; + } + } + /** + * @name exitConsoleMode + * Exit console mode and return to bootloader + * For ESP32-S2, uses reconnectToBootloader which will trigger port change + * @returns true if manual reconnection is needed (ESP32-S2), false otherwise + */ + async exitConsoleMode() { + if (this._parent) { + return await this._parent.exitConsoleMode(); + } + // Clear console mode flag + this._consoleMode = false; + // Check if this is a USB-OTG device (ESP32-S2 or ESP32-P4) + const isUsbOtgChip = this.chipFamily === CHIP_FAMILY_ESP32S2 || + this.chipFamily === CHIP_FAMILY_ESP32P4; + // For USB-OTG chips: if _isUsbJtagOrOtg is undefined, try to detect it + // If detection fails or is undefined, assume USB-JTAG/OTG (conservative/safe path) + let isUsbJtagOrOtg = this._isUsbJtagOrOtg; + if (isUsbOtgChip && isUsbJtagOrOtg === undefined) { + try { + isUsbJtagOrOtg = await this.detectUsbConnectionType(); + } + catch (err) { + this.logger.debug(`USB detection failed, assuming USB-JTAG/OTG for ${this.chipName}: ${err}`); + isUsbJtagOrOtg = true; // Conservative fallback + } + } + if (isUsbOtgChip && isUsbJtagOrOtg) { + // USB-OTG devices: Need to reset to bootloader, which will cause port change + this.logger.debug(`${this.chipName} USB: Resetting to bootloader mode`); + // Perform hardware reset to bootloader (GPIO0=LOW) + // This will cause the port to change from CDC (firmware) to JTAG (bootloader) + try { + await this.hardResetClassic(); + this.logger.debug("Reset to bootloader initiated"); + } + catch (err) { + this.logger.debug(`Reset error: ${err}`); + } + // Wait for reset to complete and port to change + await sleep(500); + this.logger.debug(`${this.chipName}: Port changed. Please select the bootloader port.`); + // Dispatch event to signal port change + this.dispatchEvent(new CustomEvent("usb-otg-port-change", { + detail: { + chipName: this.chipName, + message: `${this.chipName}: Port changed. Please select the bootloader port.`, + reason: "exit-console-to-bootloader", + }, + })); + // Port will change, so return true to indicate manual reconnection needed + return true; + } + // For other devices, use standard reconnectToBootloader + await this.reconnectToBootloader(); + return false; // No manual reconnection needed + } + /** + * @name isConsoleResetSupported + * Check if console reset is supported for this device + * ESP32-S2 USB-JTAG/CDC does not support reset in console mode + * because any reset causes USB port to be lost (hardware limitation) + */ + isConsoleResetSupported() { + if (this._parent) { + return this._parent.isConsoleResetSupported(); + } + // For ESP32-S2: if _isUsbJtagOrOtg is undefined, assume USB-JTAG/OTG (conservative) + // This means console reset is NOT supported (safer default) + const isS2UsbJtag = this.chipFamily === CHIP_FAMILY_ESP32S2 && + (this._isUsbJtagOrOtg === true || this._isUsbJtagOrOtg === undefined); + return !isS2UsbJtag; // Not supported for ESP32-S2 USB-JTAG/CDC + } + /** + * @name resetInConsoleMode + * Reset device while in console mode (firmware mode) + * + * NOTE: For ESP32-S2 USB-JTAG/CDC, ANY reset (hardware or software) causes + * the USB port to be lost because the device switches USB modes during reset. + * This is a hardware limitation - use isConsoleResetSupported() to check first. + */ + async resetInConsoleMode() { + if (this._parent) { + return await this._parent.resetInConsoleMode(); + } + if (!this.isConsoleResetSupported()) { + this.logger.debug("Simple Console reset not supported for ESP32-S2 USB-JTAG/CDC - using exitConsoleMode to enter bootloader"); + await this.exitConsoleMode(); + this.logger.debug("S2 now in bootloader mode - caller must do syncAndWdtReset on new port, then reconnect console"); + return; + } + // For other devices: Use standard firmware reset + try { + this.logger.debug("Resetting device in console mode"); + await this.hardResetToFirmware(); + this.logger.debug("Device reset complete"); + } + catch (err) { + this.logger.error(`Reset failed: ${err}`); + throw err; + } + } + /** + * @name syncAndWdtReset + * Open a new bootloader port, sync with ROM (no stub, no reset strategies), and fire WDT reset. + * This is used for ESP32-S2 USB-OTG devices which require WDT reset to switch modes. + * After WDT reset the port will re-enumerate again. + * The user must select the new port after this method is called. + * @param newPort - The bootloader port selected by the user + */ + async syncAndWdtReset(newPort) { + if (this._parent) { + await this._parent.syncAndWdtReset(newPort); + return; + } + this.port = newPort; + this.connected = false; + this.IS_STUB = false; + this.__inputBuffer = []; + this.__inputBufferReadIndex = 0; + this.__totalBytesRead = 0; + this.logger.debug("Opening bootloader port at 115200..."); + await this.port.open({ baudRate: ESP_ROM_BAUD }); + this.connected = true; + this.currentBaudRate = ESP_ROM_BAUD; + // Start read loop + this.readLoop(); + await sleep(100); + // Sync with ROM only - no reset strategies, device is already in bootloader + this.logger.debug("Syncing with bootloader ROM..."); + await this.sync(); + this.logger.debug("Bootloader sync OK, no stub"); + // Fire WDT reset → device boots into firmware + this.logger.debug("Firing WDT reset..."); + await this.rtcWdtResetChipSpecific(); + this.logger.debug("WDT reset fired - device will boot to firmware"); + } + /** + * @name drainInputBuffer + * Actively drain the input buffer by reading data for a specified time. + * Simple approach for some drivers (especially CP210x on Windows) that have + * issues with buffer flushing. + * + * Based on esptool.py fix: https://github.com/espressif/esptool/commit/5338ea054e5099ac7be235c54034802ac8a43162 + * + * @param bufferingTime - Time in milliseconds to wait for the buffer to fill + */ + async drainInputBuffer(bufferingTime = 200) { + // Wait for the buffer to fill + await sleep(bufferingTime); + // Unsupported command response is sent 8 times and has + // 14 bytes length including delimiter SLIP_END (0xC0) bytes. + // At least part of it is read as a command response, + // but to be safe, read it all. + const bytesToDrain = 14 * 8; + let drained = 0; + // Drain the buffer by reading available data + const drainStart = Date.now(); + const drainTimeout = 100; // Short timeout for draining + while (drained < bytesToDrain && Date.now() - drainStart < drainTimeout) { + if (this._inputBufferAvailable > 0) { + const byte = this._readByte(); + if (byte !== undefined) { + drained++; + } + } + else { + // Small sleep to avoid busy waiting + await sleep(1); + } + } + if (drained > 0) { + this.logger.debug(`Drained ${drained} bytes from input buffer`); + } + // Final clear of application buffer + if (!this._parent) { + this.__inputBuffer = []; + this.__inputBufferReadIndex = 0; + } + } + /** + * @name flushSerialBuffers + * Flush any pending data in the TX and RX serial port buffers + * This clears both the application RX buffer and waits for hardware buffers to drain + */ + async flushSerialBuffers() { + // Clear application buffer + if (!this._parent) { + this.__inputBuffer = []; + this.__inputBufferReadIndex = 0; + } + // Wait for any pending data + await sleep(SYNC_TIMEOUT); + // Final clear + if (!this._parent) { + this.__inputBuffer = []; + this.__inputBufferReadIndex = 0; + } + this.logger.debug("Serial buffers flushed"); + } + /** + * @name readFlash + * Read flash memory from the chip (only works with stub loader) + * @param addr - Address to read from + * @param size - Number of bytes to read + * @param onPacketReceived - Optional callback function called when packet is received + * @param options - Optional parameters for advanced control + * - chunkSize: Amount of data to request from ESP in one command (bytes) + * - blockSize: Size of each data block sent by ESP (bytes) + * - maxInFlight: Maximum unacknowledged bytes (bytes) + * @returns Uint8Array containing the flash data + */ + async readFlash(addr, size, onPacketReceived, options) { + if (!this.IS_STUB) { + throw new Error("Reading flash is only supported in stub mode. Please run runStub() first."); + } + // Flush serial buffers before flash read operation + await this.flushSerialBuffers(); + const readStartTime = Date.now(); + this.logger.log(`Reading ${size} bytes from flash at address 0x${addr.toString(16)}...`); + // Initialize adaptive speed multipliers for WebUSB devices + if (this.isWebUSB()) { + if (this._isCDCDevice) { + // CDC devices (CH343): Start with maximum, adaptive adjustment enabled + this._adaptiveBlockMultiplier = 8; // blockSize = 248 bytes + this._adaptiveMaxInFlightMultiplier = 8; // maxInFlight = 248 bytes + this._consecutiveSuccessfulChunks = 0; + this.logger.debug(`CDC device - Initialized: blockMultiplier=${this._adaptiveBlockMultiplier}, maxInFlightMultiplier=${this._adaptiveMaxInFlightMultiplier}`); + } + else { + // Non-CDC devices (CH340, CP2102): Fixed values, no adaptive adjustment + this._adaptiveBlockMultiplier = 1; // blockSize = 31 bytes (fixed) + this._adaptiveMaxInFlightMultiplier = 1; // maxInFlight = 31 bytes (fixed) + this._consecutiveSuccessfulChunks = 0; + this.logger.debug(`Non-CDC device - Fixed values: blockSize=31, maxInFlight=31`); + } + } + // Chunk size: Amount of data to request from ESP in one command + // For WebUSB (Android), use smaller chunks to avoid timeouts and buffer issues + // For Web Serial (Desktop), use larger chunks for better performance + let CHUNK_SIZE; + if ((options === null || options === void 0 ? void 0 : options.chunkSize) !== undefined) { + // Use user-provided chunkSize if in advanced mode + CHUNK_SIZE = options.chunkSize; + this.logger.log(`Using custom chunk size: 0x${CHUNK_SIZE.toString(16)} bytes`); + } + else if (this.isWebUSB()) { + // WebUSB: Use smaller chunks to avoid SLIP timeout issues + CHUNK_SIZE = 0x4 * 0x1000; // 4KB = 16384 bytes + } + else { + // Web Serial: Use larger chunks for better performance + CHUNK_SIZE = 0x40 * 0x1000; + } + let allData = new Uint8Array(0); + let currentAddr = addr; + let remainingSize = size; + while (remainingSize > 0) { + const chunkSize = Math.min(CHUNK_SIZE, remainingSize); + let chunkSuccess = false; + let retryCount = 0; + const MAX_RETRIES = 5; + let deepRecoveryAttempted = false; + // Retry loop for this chunk + while (!chunkSuccess && retryCount <= MAX_RETRIES) { + let resp = new Uint8Array(0); + let lastAckedLength = 0; // Track last acknowledged length + try { + // Only log on first attempt or retries + if (retryCount === 0) { + this.logger.debug(`Reading chunk at 0x${currentAddr.toString(16)}, size: 0x${chunkSize.toString(16)}`); + } + let blockSize; + let maxInFlight; + if ((options === null || options === void 0 ? void 0 : options.blockSize) !== undefined && + (options === null || options === void 0 ? void 0 : options.maxInFlight) !== undefined) { + // Use user-provided values if in advanced mode + blockSize = options.blockSize; + maxInFlight = options.maxInFlight; + if (retryCount === 0) { + this.logger.debug(`Using custom parameters: blockSize=${blockSize}, maxInFlight=${maxInFlight}`); + } + } + else if (this.isWebUSB()) { + // WebUSB (Android): All devices use adaptive speed + // All have maxTransferSize=64, baseBlockSize=31 + const maxTransferSize = this.port.maxTransferSize || 64; + const baseBlockSize = Math.floor((maxTransferSize - 2) / 2); // 31 bytes + // Use current adaptive multipliers (initialized at start of readFlash) + blockSize = baseBlockSize * this._adaptiveBlockMultiplier; + maxInFlight = baseBlockSize * this._adaptiveMaxInFlightMultiplier; + } + else { + // Web Serial (Desktop): Use multiples of 63 for consistency + const base = 63; + blockSize = base * 65; // 63 * 65 = 4095 (close to 0x1000) + maxInFlight = base * 130; // 63 * 130 = 8190 (close to blockSize * 2) + } + const pkt = pack("= chunkSize) { + break; + } + } + throw err; + } + if (packet && packet.length > 0) { + const packetData = new Uint8Array(packet); + // Append to response + const newResp = new Uint8Array(resp.length + packetData.length); + newResp.set(resp); + newResp.set(packetData, resp.length); + resp = newResp; + // Send acknowledgment when we've received maxInFlight bytes + // The stub sends packets until (num_sent - num_acked) >= max_in_flight + // We MUST wait for all packets before sending ACK + const shouldAck = resp.length >= chunkSize || // End of chunk + resp.length >= lastAckedLength + maxInFlight; // Received all packets + if (shouldAck) { + const ackData = pack("= 2) { + const maxTransferSize = this.port.maxTransferSize || 64; + const baseBlockSize = Math.floor((maxTransferSize - 2) / 2); // 31 bytes + // Maximum: blockSize=248 (8 * 31), maxInFlight=248 (8 * 31) + const MAX_BLOCK_MULTIPLIER = 8; // 248 bytes - tested stable + const MAX_INFLIGHT_MULTIPLIER = 8; // 248 bytes - tested stable + let adjusted = false; + // Increase blockSize first (up to 248), then maxInFlight + if (this._adaptiveBlockMultiplier < MAX_BLOCK_MULTIPLIER) { + this._adaptiveBlockMultiplier = Math.min(this._adaptiveBlockMultiplier * 2, MAX_BLOCK_MULTIPLIER); + adjusted = true; + } + // Once blockSize is at maximum, increase maxInFlight + else if (this._adaptiveMaxInFlightMultiplier < MAX_INFLIGHT_MULTIPLIER) { + this._adaptiveMaxInFlightMultiplier = Math.min(this._adaptiveMaxInFlightMultiplier * 2, MAX_INFLIGHT_MULTIPLIER); + adjusted = true; + } + if (adjusted) { + const newBlockSize = baseBlockSize * this._adaptiveBlockMultiplier; + const newMaxInFlight = baseBlockSize * this._adaptiveMaxInFlightMultiplier; + this.logger.debug(`Speed increased: blockSize=${newBlockSize}, maxInFlight=${newMaxInFlight}`); + this._lastAdaptiveAdjustment = Date.now(); + } + // Reset counter + this._consecutiveSuccessfulChunks = 0; + } + } + } + catch (err) { + retryCount++; + // ADAPTIVE SPEED ADJUSTMENT: Only for CDC devices + // Non-CDC devices stay at fixed values + if (this.isWebUSB() && this._isCDCDevice && retryCount === 1) { + // Only reduce if we're above minimum + if (this._adaptiveBlockMultiplier > 1 || + this._adaptiveMaxInFlightMultiplier > 1) { + // Reduce to minimum on error + this._adaptiveBlockMultiplier = 1; // 31 bytes (for CH343) + this._adaptiveMaxInFlightMultiplier = 1; // 31 bytes + this._consecutiveSuccessfulChunks = 0; // Reset success counter + const maxTransferSize = this.port.maxTransferSize || 64; + const baseBlockSize = Math.floor((maxTransferSize - 2) / 2); + const newBlockSize = baseBlockSize * this._adaptiveBlockMultiplier; + const newMaxInFlight = baseBlockSize * this._adaptiveMaxInFlightMultiplier; + this.logger.debug(`Error at higher speed - reduced to minimum: blockSize=${newBlockSize}, maxInFlight=${newMaxInFlight}`); + } + else { + // Already at minimum and still failing - this is a real error + this.logger.debug(`Error at minimum speed (blockSize=31, maxInFlight=31) - not a speed issue`); + } + } + // Check if it's a timeout error or SLIP error + if (err instanceof SlipReadError) { + if (retryCount <= MAX_RETRIES) { + this.logger.debug(`Cleared buffer and retrying (attempt ${retryCount}/${MAX_RETRIES})...`); + // Continue to retry the same chunk (will send NEW read command) + } + else { + // All retries exhausted - attempt recovery by reloading stub + // IMPORTANT: Do NOT close port to keep ESP32 in bootloader mode + if (!deepRecoveryAttempted) { + deepRecoveryAttempted = true; + this.logger.log(`All retries exhausted at 0x${currentAddr.toString(16)}. Attempting recovery (close and reopen port)...`); + try { + // Reconnect will close port, reopen, and reload stub + await this.reconnect(); + this.logger.log("Deep recovery successful. Resuming read from current position..."); + // Reset retry counter to give it another chance after recovery + retryCount = 0; + continue; + } + catch (recoveryErr) { + throw new Error(`Failed to read chunk at 0x${currentAddr.toString(16)} after ${MAX_RETRIES} retries and recovery failed: ${recoveryErr}`); + } + } + else { + // Recovery already attempted, give up + throw new Error(`Failed to read chunk at 0x${currentAddr.toString(16)} after ${MAX_RETRIES} retries and recovery attempt`); + } + } + } + else { + // Non-SLIP error, don't retry + throw err; + } + } + } + // Update progress (use empty array since we already appended to allData) + if (onPacketReceived) { + onPacketReceived(new Uint8Array(chunkSize), allData.length, size); + } + currentAddr += chunkSize; + remainingSize -= chunkSize; + this.logger.debug(`Total progress: 0x${allData.length.toString(16)} from 0x${size.toString(16)} bytes`); + } + const totalDuration = Date.now() - readStartTime; + const totalSpeedKBs = (allData.length / + 1024 / + (totalDuration / 1000)).toFixed(1); + this.logger.log(`Read complete: ${allData.length} bytes in ${(totalDuration / 1000).toFixed(1)} s (${totalSpeedKBs} KB/s)`); + return allData; + } +} +class EspStubLoader extends ESPLoader { + constructor() { + super(...arguments); + /* + The Stubloader has commands that run on the uploaded Stub Code in RAM + rather than built in commands. + */ + this.IS_STUB = true; + } + /** + * @name memBegin (592) + * Start downloading an application image to RAM + */ + async memBegin(size, _blocks, _blocksize, offset) { + const stub = await getStubCode(this.chipFamily, this.chipRevision); + // Stub may be null for chips without stub support + if (stub === null) { + return [0, []]; + } + const load_start = offset; + const load_end = offset + size; + this.logger.debug(`Load range: ${toHex(load_start, 8)}-${toHex(load_end, 8)}`); + this.logger.debug(`Stub data: ${toHex(stub.data_start, 8)}, len: ${stub.data.length}, text: ${toHex(stub.text_start, 8)}, len: ${stub.text.length}`); + for (const [start, end] of [ + [stub.data_start, stub.data_start + stub.data.length], + [stub.text_start, stub.text_start + stub.text.length], + ]) { + if (load_start < end && load_end > start) { + throw new Error("Software loader is resident at " + + toHex(start, 8) + + "-" + + toHex(end, 8) + + ". " + + "Can't load binary at overlapping address range " + + toHex(load_start, 8) + + "-" + + toHex(load_end, 8) + + ". " + + "Try changing the binary loading address."); + } + } + return [0, []]; + } + /** + * @name eraseFlash + * Erase entire flash chip + */ + async eraseFlash() { + await this.checkCommand(ESP_ERASE_FLASH, [], 0, CHIP_ERASE_TIMEOUT); + } + /** + * @name eraseRegion + * Erase a specific region of flash + */ + async eraseRegion(offset, size) { + // Validate inputs + if (offset < 0) { + throw new Error(`Invalid offset: ${offset} (must be non-negative)`); + } + if (size < 0) { + throw new Error(`Invalid size: ${size} (must be non-negative)`); + } + // No-op for zero size + if (size === 0) { + this.logger.log("eraseRegion: size is 0, skipping erase"); + return; + } + // Check for sector alignment + if (offset % FLASH_SECTOR_SIZE !== 0) { + throw new Error(`Offset ${offset} (0x${offset.toString(16)}) is not aligned to flash sector size ${FLASH_SECTOR_SIZE} (0x${FLASH_SECTOR_SIZE.toString(16)})`); + } + if (size % FLASH_SECTOR_SIZE !== 0) { + throw new Error(`Size ${size} (0x${size.toString(16)}) is not aligned to flash sector size ${FLASH_SECTOR_SIZE} (0x${FLASH_SECTOR_SIZE.toString(16)})`); + } + // Check for reasonable bounds (prevent wrapping in pack) + const maxValue = 0xffffffff; // 32-bit unsigned max + if (offset > maxValue) { + throw new Error(`Offset ${offset} exceeds maximum value ${maxValue}`); + } + if (size > maxValue) { + throw new Error(`Size ${size} exceeds maximum value ${maxValue}`); + } + // Check for wrap-around + if (offset + size > maxValue) { + throw new Error(`Region end (offset + size = ${offset + size}) exceeds maximum addressable range ${maxValue}`); + } + const timeout = timeoutPerMb(ERASE_REGION_TIMEOUT_PER_MB, size); + const buffer = pack(" data.length) + break; + const page = data.slice(pageOffset, pageOffset + pageSize); + const objId = page[0] | (page[1] << 8); + // Look for SPIFFS filename pattern: 0x01 followed by '/' and printable chars + for (let i = 0; i < page.length - 10; i++) { + if (page[i] === 0x01 && page[i + 1] === 0x2f) { // 0x01 followed by '/' + let validChars = 0; + for (let j = i + 1; j < Math.min(i + 20, page.length); j++) { + if (page[j] >= 0x20 && page[j] < 0x7f) { + validChars++; + } + else if (page[j] === 0x00) { + break; + } + } + if (validChars >= 4) { // At least "/xxx" + spiffsScore += 5; + break; + } + } + } + // Check for typical SPIFFS object ID patterns + if ((objId & 0x8000) !== 0) { + const idLow = objId & 0x7fff; + if (idLow > 0 && idLow < 0x1000) { + spiffsScore += 2; + } + } + } + return spiffsScore >= 10; +} +/** + * Scan ESP8266 flash for filesystem by detecting filesystem signatures + * Reads actual block_count from LittleFS superblock for accurate size detection + * + * @param flashData - Flash data starting at scanOffset + * @param scanOffset - The offset in flash where this data starts + * @param flashSize - Total flash size in bytes + * @returns Detected filesystem layout or null + */ +function scanESP8266Filesystem(flashData, scanOffset, flashSize) { + // Check for LittleFS signature + // LittleFS superblock has "littlefs" magic at offset 8 within block 0 + const blockSizes = ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES; // ESP8266 typically uses 8192 + for (const blockSize of blockSizes) { + // Check block 0 and block 1 (mirrored superblock) + for (let blockIndex = 0; blockIndex < 2; blockIndex++) { + const superblockOffset = blockIndex * blockSize; + const magicOffset = superblockOffset + 8; + if (magicOffset + 8 > flashData.length) { + continue; + } + const magicStr = String.fromCharCode(flashData[magicOffset], flashData[magicOffset + 1], flashData[magicOffset + 2], flashData[magicOffset + 3], flashData[magicOffset + 4], flashData[magicOffset + 5], flashData[magicOffset + 6], flashData[magicOffset + 7]); + if (magicStr === "littlefs") { + // Validate version (at offset 16 in superblock) + const versionOffset = superblockOffset + 16; + const version = flashData[versionOffset] | + (flashData[versionOffset + 1] << 8) | + (flashData[versionOffset + 2] << 16) | + (flashData[versionOffset + 3] << 24); + if (version !== 0 && (version >>> 0) !== 0xffffffff) { + // Found valid LittleFS! + // Try to read block_count from superblock (offset 24, 4 bytes little-endian) + const blockCountOffset = superblockOffset + 24; + if (blockCountOffset + 4 <= flashData.length) { + const blockCount = flashData[blockCountOffset] | + (flashData[blockCountOffset + 1] << 8) | + (flashData[blockCountOffset + 2] << 16) | + (flashData[blockCountOffset + 3] << 24); + // Validate block_count (should be reasonable: > 0 and < 100000) + if (blockCount > 0 && blockCount < 100000) { + const detectedSize = blockCount * blockSize; + // Verify size is reasonable (not larger than remaining flash) + if (detectedSize > 0 && scanOffset + detectedSize <= flashSize) { + return { + start: scanOffset, + end: scanOffset + detectedSize, + size: detectedSize, + page: ESP8266_LITTLEFS_PAGE_SIZE, + block: blockSize, + }; + } + } + } + // Fallback to known layout patterns if block_count read failed + return getLayoutForDetectedFilesystem(scanOffset, flashSize, blockSize); + } + } + } + } + // Check for SPIFFS filesystem using pattern detection + if (detectSPIFFSPatterns(flashData)) { + // SPIFFS does not store size in the image itself + // Size must come from linker script or partition table + return getLayoutForDetectedFilesystem(scanOffset, flashSize, ESP8266_SPIFFS_BLOCK_SIZE); + } + // Also check for SPIFFS magic 0x20140529 (some implementations have it) + if (flashData.length >= 4) { + const spiffsMagic = flashData[0] | + (flashData[1] << 8) | + (flashData[2] << 16) | + (flashData[3] << 24); + if (spiffsMagic === 0x20140529) { + // Found SPIFFS magic! + // Additional validation: Check if header looks valid + let validHeader = true; + // Check if next bytes are not all 0xFF + if (flashData.length >= 16) { + let allFF = true; + for (let i = 4; i < 16; i++) { + if (flashData[i] !== 0xff) { + allFF = false; + break; + } + } + if (allFF) { + validHeader = false; + } + } + if (validHeader) { + return getLayoutForDetectedFilesystem(scanOffset, flashSize, ESP8266_SPIFFS_BLOCK_SIZE); + } + } + } + // Check for FAT filesystem + // FAT can start at offset 0 or 0x1000 (4096 bytes) in ESP8266 + const fatOffsets = [0, 0x1000]; + for (const fatOffset of fatOffsets) { + if (flashData.length < fatOffset + 512) { + continue; + } + const bootSig = flashData[fatOffset + 510] | (flashData[fatOffset + 511] << 8); + if (bootSig === 0xaa55) { + // Read bytes per sector + const bytesPerSector = flashData[fatOffset + 0x0b] | (flashData[fatOffset + 0x0c] << 8); + // Validate bytes per sector (must be 512, 1024, 2048, or 4096) + if (![512, 1024, 2048, 4096].includes(bytesPerSector)) { + continue; + } + // Read total sectors (try 16-bit first, then 32-bit) + let totalSectors = flashData[fatOffset + 0x13] | (flashData[fatOffset + 0x14] << 8); + if (totalSectors === 0) { + // Use 32-bit total sectors + totalSectors = + flashData[fatOffset + 0x20] | + (flashData[fatOffset + 0x21] << 8) | + (flashData[fatOffset + 0x22] << 16) | + (flashData[fatOffset + 0x23] << 24); + } + // Validate values + if (bytesPerSector > 0 && totalSectors > 0 && totalSectors < 100000000) { + const detectedSize = totalSectors * bytesPerSector; + // Verify size is reasonable (not larger than remaining flash) + // Account for the FAT offset in the actual flash position + const actualStart = scanOffset + fatOffset; + if (detectedSize > 0 && actualStart + detectedSize <= flashSize) { + return { + start: actualStart, + end: actualStart + detectedSize, + size: detectedSize, + page: bytesPerSector, + block: bytesPerSector, // FAT uses sector size as block size + }; + } + } + } + } + return null; +} +/** + * Get filesystem layout based on detected offset and flash size + * Uses known ESP8266 linker script patterns from Arduino/PlatformIO + */ +function getLayoutForDetectedFilesystem(offset, flashSize, blockSize) { + const flashSizeMB = flashSize / (1024 * 1024); + // 16MB Flash layouts + if (flashSizeMB >= 16) { + if (offset === 0x100000) { + return { start: 0x100000, end: 0xffa000, size: 0xefa000, page: 256, block: blockSize }; // 15MB + } + else if (offset === 0x200000) { + return { start: 0x200000, end: 0xffa000, size: 0xdfa000, page: 256, block: blockSize }; // 14MB + } + } + // 8MB Flash layouts + if (flashSizeMB >= 8) { + if (offset === 0x100000) { + return { start: 0x100000, end: 0x7fa000, size: 0x6fa000, page: 256, block: blockSize }; // 7MB + } + else if (offset === 0x200000) { + return { start: 0x200000, end: 0x7fa000, size: 0x5fa000, page: 256, block: blockSize }; // 6MB + } + } + // 4MB Flash layouts + if (flashSizeMB >= 4) { + if (offset === 0x100000) { + return { start: 0x100000, end: 0x3fa000, size: 0x2fa000, page: 256, block: blockSize }; // 3MB + } + else if (offset === 0x200000) { + return { start: 0x200000, end: 0x3fa000, size: 0x1fa000, page: 256, block: blockSize }; // 2MB + } + else if (offset === 0x300000) { + return { start: 0x300000, end: 0x3fa000, size: 0x0fa000, page: 256, block: blockSize }; // 1MB + } + } + // 2MB Flash layouts + if (flashSizeMB >= 2) { + if (offset === 0x100000) { + return { start: 0x100000, end: 0x1fa000, size: 0x0fa000, page: 256, block: blockSize }; // 1MB + } + else if (offset === 0x180000) { + return { start: 0x180000, end: 0x1fa000, size: 0x07a000, page: 256, block: blockSize }; // 512KB + } + else if (offset === 0x1c0000) { + return { start: 0x1c0000, end: 0x1fb000, size: 0x03b000, page: 256, block: blockSize }; // 256KB + } + else if (offset === 0x1e0000) { + return { start: 0x1e0000, end: 0x1fb000, size: 0x01b000, page: 256, block: blockSize }; // 128KB + } + else if (offset === 0x1f0000) { + return { start: 0x1f0000, end: 0x1fb000, size: 0x00b000, page: 256, block: blockSize }; // 64KB + } + } + // 1MB Flash layouts + if (flashSizeMB >= 1) { + if (offset === 0x07b000) { + return { start: 0x07b000, end: 0x0fb000, size: 0x080000, page: 256, block: blockSize }; // 512KB + } + else if (offset === 0x0bb000) { + return { start: 0x0bb000, end: 0x0fb000, size: 0x040000, page: 256, block: blockSize }; // 256KB + } + else if (offset === 0x0cb000) { + return { start: 0x0cb000, end: 0x0fb000, size: 0x030000, page: 256, block: blockSize }; // 192KB + } + else if (offset === 0x0d3000) { + return { start: 0x0d3000, end: 0x0fb000, size: 0x028000, page: 256, block: blockSize }; // 160KB + } + else if (offset === 0x0d7000) { + return { start: 0x0d7000, end: 0x0fb000, size: 0x024000, page: 256, block: blockSize }; // 144KB + } + else if (offset === 0x0db000) { + return { start: 0x0db000, end: 0x0fb000, size: 0x020000, page: 256, block: blockSize }; // 128KB + } + else if (offset === 0x0eb000) { + return { start: 0x0eb000, end: 0x0fb000, size: 0x010000, page: 256, block: blockSize }; // 64KB + } + } + // 512KB Flash layouts + if (flashSizeMB >= 0.5) { + if (offset === 0x05b000) { + return { start: 0x05b000, end: 0x07b000, size: 0x020000, page: 256, block: blockSize }; // 128KB + } + else if (offset === 0x06b000) { + return { start: 0x06b000, end: 0x07b000, size: 0x010000, page: 256, block: blockSize }; // 64KB + } + else if (offset === 0x073000) { + return { start: 0x073000, end: 0x07b000, size: 0x008000, page: 256, block: blockSize }; // 32KB + } + } + // Fallback: use remaining flash space + const size = flashSize - offset; + return { + start: offset, + end: flashSize, + size: size, + page: 256, + block: blockSize, + }; +} +/** + * Get common ESP8266 filesystem layouts as fallback + * Used when we can't scan the actual flash + * + * @param flashSizeMB - Flash size in megabytes + * @returns Array of possible filesystem layouts (most common first) + */ +function getESP8266FilesystemLayout(flashSizeMB) { + // Based on common ESP8266 linker script configurations + if (flashSizeMB >= 16) { + // 16MB flash + return [ + { start: 0x100000, end: 0xffa000, size: 0xefa000, page: 256, block: 8192 }, // 15MB + { start: 0x200000, end: 0xffa000, size: 0xdfa000, page: 256, block: 8192 }, // 14MB + ]; + } + else if (flashSizeMB >= 8) { + // 8MB flash + return [ + { start: 0x100000, end: 0x7fa000, size: 0x6fa000, page: 256, block: 8192 }, // 7MB + { start: 0x200000, end: 0x7fa000, size: 0x5fa000, page: 256, block: 8192 }, // 6MB + ]; + } + else if (flashSizeMB >= 4) { + // 4MB flash: Multiple possible configurations + return [ + { start: 0x200000, end: 0x3fa000, size: 0x1fa000, page: 256, block: 8192 }, // 2MB (most common) + { start: 0x100000, end: 0x3fa000, size: 0x2fa000, page: 256, block: 8192 }, // 3MB + { start: 0x300000, end: 0x3fa000, size: 0x0fa000, page: 256, block: 8192 }, // 1MB + ]; + } + else if (flashSizeMB >= 2) { + // 2MB flash + return [ + { start: 0x100000, end: 0x1fa000, size: 0x0fa000, page: 256, block: 8192 }, // 1MB + { start: 0x180000, end: 0x1fa000, size: 0x07a000, page: 256, block: 8192 }, // 512KB + { start: 0x1c0000, end: 0x1fb000, size: 0x03b000, page: 256, block: 8192 }, // 256KB + { start: 0x1e0000, end: 0x1fb000, size: 0x01b000, page: 256, block: 8192 }, // 128KB + { start: 0x1f0000, end: 0x1fb000, size: 0x00b000, page: 256, block: 8192 }, // 64KB + ]; + } + else if (flashSizeMB >= 1) { + // 1MB flash + return [ + { start: 0x0db000, end: 0x0fb000, size: 0x020000, page: 256, block: 8192 }, // 128KB (most common) + { start: 0x07b000, end: 0x0fb000, size: 0x080000, page: 256, block: 8192 }, // 512KB + { start: 0x0bb000, end: 0x0fb000, size: 0x040000, page: 256, block: 8192 }, // 256KB + { start: 0x0cb000, end: 0x0fb000, size: 0x030000, page: 256, block: 8192 }, // 192KB + { start: 0x0d3000, end: 0x0fb000, size: 0x028000, page: 256, block: 8192 }, // 160KB + { start: 0x0d7000, end: 0x0fb000, size: 0x024000, page: 256, block: 8192 }, // 144KB + { start: 0x0eb000, end: 0x0fb000, size: 0x010000, page: 256, block: 8192 }, // 64KB + ]; + } + else if (flashSizeMB >= 0.5) { + // 512KB flash + return [ + { start: 0x05b000, end: 0x07b000, size: 0x020000, page: 256, block: 8192 }, // 128KB + { start: 0x06b000, end: 0x07b000, size: 0x010000, page: 256, block: 8192 }, // 64KB + { start: 0x073000, end: 0x07b000, size: 0x008000, page: 256, block: 8192 }, // 32KB + ]; + } + return []; +} +/** + * Filesystem types based on partition subtype + */ +var FilesystemType; +(function (FilesystemType) { + FilesystemType["UNKNOWN"] = "unknown"; + FilesystemType["LITTLEFS"] = "littlefs"; + FilesystemType["FATFS"] = "fatfs"; + FilesystemType["SPIFFS"] = "spiffs"; +})(FilesystemType || (FilesystemType = {})); +/** + * Detect filesystem type from partition information + * Note: This only provides a hint. LittleFS is often stored in SPIFFS partitions (0x82). + * Use detectFilesystemFromImage() for accurate detection. + */ +function detectFilesystemType(partition) { + if (partition.type !== 0x01) { + return FilesystemType.UNKNOWN; + } + switch (partition.subtype) { + case 0x81: + return FilesystemType.FATFS; + case 0x82: + return FilesystemType.UNKNOWN; + default: + return FilesystemType.UNKNOWN; + } +} +/** + * Detect filesystem type from image data + * Properly validates LittleFS superblock structure at correct offsets + * + * @param imageData - Binary filesystem image data + * @param chipName - Optional chip name for ESP8266-specific detection (e.g. "ESP8266") + */ +function detectFilesystemFromImage(imageData, chipName) { + if (imageData.length < 512) { + return FilesystemType.UNKNOWN; + } + // Check for LittleFS superblock at proper offsets + // LittleFS superblock structure: + // - Offset 0-3: version (4 bytes, little-endian) + // - Offset 4-7: CRC/flags (4 bytes) + // - Offset 8-15: "littlefs" magic string (8 bytes ASCII) + // - Offset 16+: additional metadata + // The superblock is at block 0 and mirrored at block 1 + // Block size is determined by the distance between mirrored superblocks + // Use chip-specific block sizes + const isESP8266 = chipName === null || chipName === void 0 ? void 0 : chipName.toUpperCase().includes("ESP8266"); + const blockSizes = isESP8266 + ? ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES + : LITTLEFS_BLOCK_SIZE_CANDIDATES; + for (const blockSize of blockSizes) { + // Check first two blocks (superblock is mirrored) + for (let blockIndex = 0; blockIndex < 2; blockIndex++) { + const superblockOffset = blockIndex * blockSize; + if (superblockOffset + 20 > imageData.length) { + continue; + } + // Check for "littlefs" magic at offset 8 of superblock + const magicOffset = superblockOffset + 8; + if (magicOffset + 8 <= imageData.length) { + const magicStr = String.fromCharCode(imageData[magicOffset], imageData[magicOffset + 1], imageData[magicOffset + 2], imageData[magicOffset + 3], imageData[magicOffset + 4], imageData[magicOffset + 5], imageData[magicOffset + 6], imageData[magicOffset + 7]); + if (magicStr === "littlefs") { + // Found valid LittleFS superblock with magic string + // Validate version field to avoid false positives (at offset 16) + const versionOffset = superblockOffset + 16; + const version = imageData[versionOffset] | + (imageData[versionOffset + 1] << 8) | + (imageData[versionOffset + 2] << 16) | + (imageData[versionOffset + 3] << 24); + // Version must be non-zero and not erased flash (0xFFFFFFFF) + // Use unsigned comparison + if (version !== 0 && (version >>> 0) !== 0xFFFFFFFF) { + return FilesystemType.LITTLEFS; + } + } + } + } + } + // Check for FAT filesystem signatures + // FAT can start at offset 0 or 0x1000 (4096 bytes) in ESP8266 + const fatOffsets = [0, 0x1000]; + for (const fatOffset of fatOffsets) { + if (imageData.length < fatOffset + 512) { + continue; + } + const bootSig = imageData[fatOffset + 510] | (imageData[fatOffset + 511] << 8); + if (bootSig === 0xaa55) { + const fat16Sig = imageData.length >= fatOffset + 62 + ? String.fromCharCode(imageData[fatOffset + 54], imageData[fatOffset + 55], imageData[fatOffset + 56], imageData[fatOffset + 57], imageData[fatOffset + 58]) + : ""; + const fat32Sig = imageData.length >= fatOffset + 90 + ? String.fromCharCode(imageData[fatOffset + 82], imageData[fatOffset + 83], imageData[fatOffset + 84], imageData[fatOffset + 85], imageData[fatOffset + 86]) + : ""; + if (fat16Sig.startsWith("FAT") || fat32Sig.startsWith("FAT")) { + return FilesystemType.FATFS; + } + } + } + // Check for SPIFFS magic (0x20140529) + if (imageData.length >= 4) { + const spiffsMagic = imageData[0] | + (imageData[1] << 8) | + (imageData[2] << 16) | + (imageData[3] << 24); + if (spiffsMagic === 0x20140529) { + return FilesystemType.SPIFFS; + } + } + // Check for SPIFFS filesystem using pattern detection + if (detectSPIFFSPatterns(imageData)) { + return FilesystemType.SPIFFS; + } + return FilesystemType.UNKNOWN; +} +/** + * Get appropriate block size for filesystem type and chip + */ +function getDefaultBlockSize(fsType, chipName) { + const isESP8266 = chipName === null || chipName === void 0 ? void 0 : chipName.toUpperCase().includes("ESP8266"); + switch (fsType) { + case FilesystemType.FATFS: + return FATFS_DEFAULT_BLOCK_SIZE; + case FilesystemType.LITTLEFS: + return isESP8266 + ? ESP8266_LITTLEFS_BLOCK_SIZE + : LITTLEFS_DEFAULT_BLOCK_SIZE; + default: + return isESP8266 ? ESP8266_LITTLEFS_BLOCK_SIZE : 4096; + } +} +/** + * Get block size candidates for filesystem type and chip + */ +function getBlockSizeCandidates(fsType, chipName) { + const isESP8266 = chipName === null || chipName === void 0 ? void 0 : chipName.toUpperCase().includes("ESP8266"); + switch (fsType) { + case FilesystemType.FATFS: + return FATFS_BLOCK_SIZE_CANDIDATES; + case FilesystemType.LITTLEFS: + return isESP8266 + ? ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES + : LITTLEFS_BLOCK_SIZE_CANDIDATES; + default: + return isESP8266 + ? ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES + : [4096, 2048, 1024, 512]; + } +} + +/** + * ESP32 Partition Table Parser + * Based on ESP-IDF partition table format + */ +// Partition types +const PARTITION_TYPES = { + 0x00: "app", + 0x01: "data", +}; +// App subtypes +const APP_SUBTYPES = { + 0x00: "factory", + 0x10: "ota_0", + 0x11: "ota_1", + 0x12: "ota_2", + 0x13: "ota_3", + 0x14: "ota_4", + 0x15: "ota_5", + 0x16: "ota_6", + 0x17: "ota_7", + 0x18: "ota_8", + 0x19: "ota_9", + 0x1a: "ota_10", + 0x1b: "ota_11", + 0x1c: "ota_12", + 0x1d: "ota_13", + 0x1e: "ota_14", + 0x1f: "ota_15", + 0x20: "test", +}; +// Data subtypes +const DATA_SUBTYPES = { + 0x00: "ota", + 0x01: "phy", + 0x02: "nvs", + 0x03: "coredump", + 0x04: "nvs_keys", + 0x05: "efuse", + 0x80: "esphttpd", + 0x81: "fat", + 0x82: "spiffs", + 0x83: "littlefs", +}; +const PARTITION_ENTRY_SIZE = 32; +const PARTITION_MAGIC = 0x50aa; +/** + * Parse a single partition entry from binary data + */ +function parsePartitionEntry(data) { + if (data.length < PARTITION_ENTRY_SIZE) { + return null; + } + // Check magic bytes + const magic = (data[0] | (data[1] << 8)) & 0xffff; + if (magic !== PARTITION_MAGIC) { + return null; + } + const type = data[2]; + const subtype = data[3]; + const offset = data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24); + const size = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24); + // Name is at offset 12, max 16 bytes, null-terminated + let name = ""; + for (let i = 12; i < 28; i++) { + if (data[i] === 0) + break; + name += String.fromCharCode(data[i]); + } + const flags = data[28] | (data[29] << 8) | (data[30] << 16) | (data[31] << 24); + // Get type and subtype names + const typeName = PARTITION_TYPES[type] || `unknown(0x${type.toString(16)})`; + let subtypeName = ""; + if (type === 0x00) { + subtypeName = APP_SUBTYPES[subtype] || `unknown(0x${subtype.toString(16)})`; + } + else if (type === 0x01) { + subtypeName = + DATA_SUBTYPES[subtype] || `unknown(0x${subtype.toString(16)})`; + } + else { + subtypeName = `0x${subtype.toString(16)}`; + } + return { + name, + type, + subtype, + offset, + size, + flags, + typeName, + subtypeName, + }; +} +/** + * Parse the entire partition table + */ +function parsePartitionTable(data) { + const partitions = []; + for (let i = 0; i < data.length; i += PARTITION_ENTRY_SIZE) { + const entryData = data.slice(i, i + PARTITION_ENTRY_SIZE); + const partition = parsePartitionEntry(entryData); + if (partition === null) { + // End of partition table or invalid entry + break; + } + partitions.push(partition); + } + return partitions; +} +/** + * Format size in human-readable format + */ +function formatSize(bytes) { + if (bytes < 1024) { + return `${bytes} B`; + } + else if (bytes < 1024 * 1024) { + return `${(bytes / 1024).toFixed(2)} KB`; + } + else { + return `${(bytes / (1024 * 1024)).toFixed(2)} MB`; + } +} + +/** + * SPIFFS Build Configuration + * Based on ESP-IDF spiffsgen.py + */ +const SPIFFS_PH_FLAG_USED_FINAL_INDEX = 0xf8; +const SPIFFS_PH_FLAG_USED_FINAL = 0xfc; +const SPIFFS_PH_FLAG_LEN = 1; +const SPIFFS_PH_IX_SIZE_LEN = 4; +const SPIFFS_PH_IX_OBJ_TYPE_LEN = 1; +const SPIFFS_TYPE_FILE = 1; +// Based on typedefs under spiffs_config.h +const SPIFFS_OBJ_ID_LEN = 2; // spiffs_obj_id +const SPIFFS_SPAN_IX_LEN = 2; // spiffs_span_ix +const SPIFFS_PAGE_IX_LEN = 2; // spiffs_page_ix +const SPIFFS_BLOCK_IX_LEN = 2; // spiffs_block_ix +class SpiffsBuildConfig { + constructor(options) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m; + if (options.blockSize % options.pageSize !== 0) { + throw new Error("block size should be a multiple of page size"); + } + this.pageSize = options.pageSize; + this.blockSize = options.blockSize; + this.objIdLen = (_a = options.objIdLen) !== null && _a !== void 0 ? _a : SPIFFS_OBJ_ID_LEN; + this.spanIxLen = (_b = options.spanIxLen) !== null && _b !== void 0 ? _b : SPIFFS_SPAN_IX_LEN; + this.packed = (_c = options.packed) !== null && _c !== void 0 ? _c : true; + this.aligned = (_d = options.aligned) !== null && _d !== void 0 ? _d : true; + this.objNameLen = (_e = options.objNameLen) !== null && _e !== void 0 ? _e : 32; + this.metaLen = (_f = options.metaLen) !== null && _f !== void 0 ? _f : 4; + this.pageIxLen = (_g = options.pageIxLen) !== null && _g !== void 0 ? _g : SPIFFS_PAGE_IX_LEN; + this.blockIxLen = (_h = options.blockIxLen) !== null && _h !== void 0 ? _h : SPIFFS_BLOCK_IX_LEN; + this.endianness = (_j = options.endianness) !== null && _j !== void 0 ? _j : "little"; + this.useMagic = (_k = options.useMagic) !== null && _k !== void 0 ? _k : true; + this.useMagicLen = (_l = options.useMagicLen) !== null && _l !== void 0 ? _l : true; + this.alignedObjIxTables = (_m = options.alignedObjIxTables) !== null && _m !== void 0 ? _m : false; + this.PAGES_PER_BLOCK = Math.floor(this.blockSize / this.pageSize); + this.OBJ_LU_PAGES_PER_BLOCK = Math.ceil(((this.blockSize / this.pageSize) * this.objIdLen) / this.pageSize); + this.OBJ_USABLE_PAGES_PER_BLOCK = + this.PAGES_PER_BLOCK - this.OBJ_LU_PAGES_PER_BLOCK; + this.OBJ_LU_PAGES_OBJ_IDS_LIM = Math.floor(this.pageSize / this.objIdLen); + this.OBJ_DATA_PAGE_HEADER_LEN = + this.objIdLen + this.spanIxLen + SPIFFS_PH_FLAG_LEN; + const pad = 4 - + (this.OBJ_DATA_PAGE_HEADER_LEN % 4 === 0 + ? 4 + : this.OBJ_DATA_PAGE_HEADER_LEN % 4); + this.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED = this.OBJ_DATA_PAGE_HEADER_LEN + pad; + this.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD = pad; + this.OBJ_DATA_PAGE_CONTENT_LEN = + this.pageSize - this.OBJ_DATA_PAGE_HEADER_LEN; + this.OBJ_INDEX_PAGES_HEADER_LEN = + this.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED + + SPIFFS_PH_IX_SIZE_LEN + + SPIFFS_PH_IX_OBJ_TYPE_LEN + + this.objNameLen + + this.metaLen; + if (this.alignedObjIxTables) { + this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = + (this.OBJ_INDEX_PAGES_HEADER_LEN + SPIFFS_PAGE_IX_LEN - 1) & + -2; + this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = + this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED - + this.OBJ_INDEX_PAGES_HEADER_LEN; + } + else { + this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = this.OBJ_INDEX_PAGES_HEADER_LEN; + this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = 0; + } + this.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM = Math.floor((this.pageSize - this.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED) / + this.blockIxLen); + this.OBJ_INDEX_PAGES_OBJ_IDS_LIM = Math.floor((this.pageSize - this.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED) / this.blockIxLen); + } +} +class SpiffsFullError extends Error { + constructor(message = "SPIFFS is full") { + super(message); + this.name = "SpiffsFullError"; + } +} + +/** + * SPIFFS Page Classes + * Based on ESP-IDF spiffsgen.py + */ +class SpiffsPage { + constructor(bix, buildConfig) { + this.buildConfig = buildConfig; + this.bix = bix; + } + pack(format, ...values) { + const buffer = new ArrayBuffer(this.calcSize(format)); + const view = new DataView(buffer); + let offset = 0; + for (let i = 0; i < format.length; i++) { + const type = format[i]; + const value = values[i]; + switch (type) { + case "B": // unsigned char (1 byte) + view.setUint8(offset, value); + offset += 1; + break; + case "H": // unsigned short (2 bytes) + if (this.buildConfig.endianness === "little") { + view.setUint16(offset, value, true); + } + else { + view.setUint16(offset, value, false); + } + offset += 2; + break; + case "I": // unsigned int (4 bytes) + if (this.buildConfig.endianness === "little") { + view.setUint32(offset, value, true); + } + else { + view.setUint32(offset, value, false); + } + offset += 4; + break; + } + } + return new Uint8Array(buffer); + } + unpack(format, data, offset = 0) { + const view = new DataView(data.buffer, data.byteOffset + offset); + const results = []; + let pos = 0; + for (const type of format) { + switch (type) { + case "B": + results.push(view.getUint8(pos)); + pos += 1; + break; + case "H": + results.push(this.buildConfig.endianness === "little" + ? view.getUint16(pos, true) + : view.getUint16(pos, false)); + pos += 2; + break; + case "I": + results.push(this.buildConfig.endianness === "little" + ? view.getUint32(pos, true) + : view.getUint32(pos, false)); + pos += 4; + break; + } + } + return results; + } + calcSize(format) { + let size = 0; + for (const type of format) { + switch (type) { + case "B": + size += 1; + break; + case "H": + size += 2; + break; + case "I": + size += 4; + break; + } + } + return size; + } +} +class SpiffsObjPageWithIdx extends SpiffsPage { + constructor(objId, buildConfig) { + super(0, buildConfig); + this.objId = objId; + } + getObjId() { + return this.objId; + } +} +class SpiffsObjLuPage extends SpiffsPage { + constructor(bix, buildConfig) { + super(bix, buildConfig); + this.objIdsLimit = this.buildConfig.OBJ_LU_PAGES_OBJ_IDS_LIM; + this.objIds = []; + } + calcMagic(blocksLim) { + let magic = 0x20140529 ^ this.buildConfig.pageSize; + if (this.buildConfig.useMagicLen) { + magic = magic ^ (blocksLim - this.bix); + } + const mask = (1 << (8 * this.buildConfig.objIdLen)) - 1; + return magic & mask; + } + registerPage(page) { + if (this.objIdsLimit <= 0) { + throw new SpiffsFullError(); + } + const pageType = page instanceof SpiffsObjIndexPage ? "index" : "data"; + this.objIds.push([page.getObjId(), pageType]); + this.objIdsLimit--; + } + toBinary() { + const img = new Uint8Array(this.buildConfig.pageSize); + img.fill(0xff); + let offset = 0; + for (const [objId, pageType] of this.objIds) { + let id = objId; + if (pageType === "index") { + id ^= 1 << (this.buildConfig.objIdLen * 8 - 1); + } + const packed = this.pack(this.buildConfig.objIdLen === 1 + ? "B" + : this.buildConfig.objIdLen === 2 + ? "H" + : "I", id); + img.set(packed, offset); + offset += packed.length; + } + return img; + } + magicfy(blocksLim) { + const remaining = this.objIdsLimit; + const emptyObjId = (1 << (this.buildConfig.objIdLen * 8)) - 1; + if (remaining >= 2) { + for (let i = 0; i < remaining; i++) { + if (i === remaining - 2) { + this.objIds.push([this.calcMagic(blocksLim), "data"]); + break; + } + else { + this.objIds.push([emptyObjId, "data"]); + } + this.objIdsLimit--; + } + } + } +} +class SpiffsObjIndexPage extends SpiffsObjPageWithIdx { + constructor(objId, spanIx, size, name, buildConfig) { + super(objId, buildConfig); + this.spanIx = spanIx; + this.name = name; + this.size = size; + if (this.spanIx === 0) { + this.pagesLim = this.buildConfig.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM; + } + else { + this.pagesLim = this.buildConfig.OBJ_INDEX_PAGES_OBJ_IDS_LIM; + } + this.pages = []; + } + registerPage(page) { + if (this.pagesLim <= 0) { + throw new SpiffsFullError(); + } + this.pages.push(page.offset); + this.pagesLim--; + } + toBinary() { + const img = new Uint8Array(this.buildConfig.pageSize); + img.fill(0xff); + const objId = this.objId ^ (1 << (this.buildConfig.objIdLen * 8 - 1)); + const format = (this.buildConfig.objIdLen === 1 + ? "B" + : this.buildConfig.objIdLen === 2 + ? "H" + : "I") + + (this.buildConfig.spanIxLen === 1 + ? "B" + : this.buildConfig.spanIxLen === 2 + ? "H" + : "I") + + "B"; + let offset = 0; + const header = this.pack(format, objId, this.spanIx, SPIFFS_PH_FLAG_USED_FINAL_INDEX); + img.set(header, offset); + offset += header.length; + // Add padding + offset += this.buildConfig.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD; + // If first index page, add filename, type and size + if (this.spanIx === 0) { + const sizeType = this.pack("IB", this.size, SPIFFS_TYPE_FILE); + img.set(sizeType, offset); + offset += sizeType.length; + // Write filename with proper null-termination + const nameBytes = new TextEncoder().encode(this.name); + // Ensure we don't exceed objNameLen + const bytesToWrite = Math.min(nameBytes.length, this.buildConfig.objNameLen); + img.set(nameBytes.slice(0, bytesToWrite), offset); + // The rest is already 0xFF from img.fill(0xff), but SPIFFS expects 0x00 for unused name bytes + // Fill remaining name bytes with 0x00 + for (let i = bytesToWrite; i < this.buildConfig.objNameLen; i++) { + img[offset + i] = 0x00; + } + offset += + this.buildConfig.objNameLen + + this.buildConfig.metaLen + + this.buildConfig.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD; + } + // Add page indices + for (const page of this.pages) { + // Calculate page index by dividing page offset by page size + // pageSize is always a power of 2, so integer division is safe + const pageIx = Math.floor(page / this.buildConfig.pageSize); + const pageIxPacked = this.pack(this.buildConfig.pageIxLen === 1 + ? "B" + : this.buildConfig.pageIxLen === 2 + ? "H" + : "I", pageIx); + img.set(pageIxPacked, offset); + offset += pageIxPacked.length; + } + return img; + } +} +class SpiffsObjDataPage extends SpiffsObjPageWithIdx { + constructor(offset, objId, spanIx, contents, buildConfig) { + super(objId, buildConfig); + this.offset = offset; + this.spanIx = spanIx; + this.contents = contents; + } + toBinary() { + const img = new Uint8Array(this.buildConfig.pageSize); + img.fill(0xff); + const format = (this.buildConfig.objIdLen === 1 + ? "B" + : this.buildConfig.objIdLen === 2 + ? "H" + : "I") + + (this.buildConfig.spanIxLen === 1 + ? "B" + : this.buildConfig.spanIxLen === 2 + ? "H" + : "I") + + "B"; + const header = this.pack(format, this.objId, this.spanIx, SPIFFS_PH_FLAG_USED_FINAL); + img.set(header, 0); + img.set(this.contents, header.length); + return img; + } +} + +/** + * SPIFFS Block Class + * Based on ESP-IDF spiffsgen.py + */ +class SpiffsBlock { + constructor(bix, buildConfig) { + this.buildConfig = buildConfig; + this.offset = bix * this.buildConfig.blockSize; + this.remainingPages = this.buildConfig.OBJ_USABLE_PAGES_PER_BLOCK; + this.pages = []; + this.bix = bix; + this.luPages = []; + for (let i = 0; i < this.buildConfig.OBJ_LU_PAGES_PER_BLOCK; i++) { + const page = new SpiffsObjLuPage(this.bix, this.buildConfig); + this.luPages.push(page); + } + this.pages.push(...this.luPages); + this.luPageIter = this.luPages[Symbol.iterator](); + this.luPage = this.luPageIter.next().value || null; + this.curObjIndexSpanIx = 0; + this.curObjDataSpanIx = 0; + this.curObjId = 0; + this.curObjIdxPage = null; + } + reset() { + this.curObjIndexSpanIx = 0; + this.curObjDataSpanIx = 0; + this.curObjId = 0; + this.curObjIdxPage = null; + } + registerPage(page) { + if (page instanceof SpiffsObjDataPage) { + if (!this.curObjIdxPage) { + throw new Error("No current object index page"); + } + this.curObjIdxPage.registerPage(page); + } + try { + if (!this.luPage) { + throw new SpiffsFullError(); + } + this.luPage.registerPage(page); + } + catch (e) { + if (e instanceof SpiffsFullError) { + const next = this.luPageIter.next(); + if (next.done) { + throw new Error("Invalid attempt to add page to a block when there is no more space in lookup"); + } + this.luPage = next.value; + this.luPage.registerPage(page); + } + else { + throw e; + } + } + this.pages.push(page); + } + beginObj(objId, size, name, objIndexSpanIx = 0, objDataSpanIx = 0) { + if (this.remainingPages <= 0) { + throw new SpiffsFullError(); + } + this.reset(); + this.curObjId = objId; + this.curObjIndexSpanIx = objIndexSpanIx; + this.curObjDataSpanIx = objDataSpanIx; + const page = new SpiffsObjIndexPage(objId, this.curObjIndexSpanIx, size, name, this.buildConfig); + this.registerPage(page); + this.curObjIdxPage = page; + this.remainingPages--; + this.curObjIndexSpanIx++; + } + updateObj(contents) { + if (this.remainingPages <= 0) { + throw new SpiffsFullError(); + } + const page = new SpiffsObjDataPage(this.offset + this.pages.length * this.buildConfig.pageSize, this.curObjId, this.curObjDataSpanIx, contents, this.buildConfig); + this.registerPage(page); + this.curObjDataSpanIx++; + this.remainingPages--; + } + endObj() { + this.reset(); + } + isFull() { + return this.remainingPages <= 0; + } + toBinary(blocksLim) { + const img = new Uint8Array(this.buildConfig.blockSize); + img.fill(0xff); + let offset = 0; + if (this.buildConfig.useMagic) { + for (let idx = 0; idx < this.pages.length; idx++) { + const page = this.pages[idx]; + if (idx === this.buildConfig.OBJ_LU_PAGES_PER_BLOCK - 1) { + if (page instanceof SpiffsObjLuPage) { + page.magicfy(blocksLim); + } + } + const pageBinary = page.toBinary(); + img.set(pageBinary, offset); + offset += pageBinary.length; + } + } + else { + for (const page of this.pages) { + const pageBinary = page.toBinary(); + img.set(pageBinary, offset); + offset += pageBinary.length; + } + } + return img; + } + get currentObjIndexSpanIx() { + return this.curObjIndexSpanIx; + } + get currentObjDataSpanIx() { + return this.curObjDataSpanIx; + } + get currentObjId() { + return this.curObjId; + } + get currentObjIdxPage() { + return this.curObjIdxPage; + } + set currentObjId(value) { + this.curObjId = value; + } + set currentObjIdxPage(value) { + this.curObjIdxPage = value; + } + set currentObjDataSpanIx(value) { + this.curObjDataSpanIx = value; + } + set currentObjIndexSpanIx(value) { + this.curObjIndexSpanIx = value; + } +} + +/** + * SPIFFS Filesystem Implementation + * Based on ESP-IDF spiffsgen.py + */ +class SpiffsFS { + constructor(imgSize, buildConfig) { + if (imgSize % buildConfig.blockSize !== 0) { + throw new Error("image size should be a multiple of block size"); + } + this.imgSize = imgSize; + this.buildConfig = buildConfig; + this.blocks = []; + this.blocksLim = Math.floor(this.imgSize / this.buildConfig.blockSize); + this.remainingBlocks = this.blocksLim; + this.curObjId = 1; // starting object id + } + createBlock() { + if (this.isFull()) { + throw new SpiffsFullError("the image size has been exceeded"); + } + const block = new SpiffsBlock(this.blocks.length, this.buildConfig); + this.blocks.push(block); + this.remainingBlocks--; + return block; + } + isFull() { + return this.remainingBlocks <= 0; + } + createFile(imgPath, contents) { + if (imgPath.length > this.buildConfig.objNameLen) { + throw new Error(`object name '${imgPath}' too long`); + } + const name = imgPath; + let offset = 0; + try { + const block = this.blocks[this.blocks.length - 1]; + block.beginObj(this.curObjId, contents.length, name); + } + catch { + const block = this.createBlock(); + block.beginObj(this.curObjId, contents.length, name); + } + while (offset < contents.length) { + const chunkSize = Math.min(this.buildConfig.OBJ_DATA_PAGE_CONTENT_LEN, contents.length - offset); + const contentsChunk = contents.slice(offset, offset + chunkSize); + try { + const block = this.blocks[this.blocks.length - 1]; + try { + block.updateObj(contentsChunk); + } + catch (e) { + if (e instanceof SpiffsFullError) { + if (block.isFull()) { + throw e; + } + // Object index exhausted, write another object index page + block.beginObj(this.curObjId, contents.length, name, block.currentObjIndexSpanIx, block.currentObjDataSpanIx); + continue; + } + throw e; + } + } + catch (e) { + if (e instanceof SpiffsFullError) { + // All pages in block exhausted, create new block + const prevBlock = this.blocks[this.blocks.length - 1]; + const block = this.createBlock(); + block.currentObjId = prevBlock.currentObjId; + block.currentObjIdxPage = prevBlock.currentObjIdxPage; + block.currentObjDataSpanIx = prevBlock.currentObjDataSpanIx; + block.currentObjIndexSpanIx = prevBlock.currentObjIndexSpanIx; + continue; + } + throw e; + } + offset += chunkSize; + } + const block = this.blocks[this.blocks.length - 1]; + block.endObj(); + this.curObjId++; + } + toBinary() { + const allBlocks = []; + for (const block of this.blocks) { + allBlocks.push(block.toBinary(this.blocksLim)); + } + let bix = this.blocks.length; + let remaining = this.remainingBlocks; + if (this.buildConfig.useMagic) { + // Create empty blocks with magic numbers + while (remaining > 0) { + const block = new SpiffsBlock(bix, this.buildConfig); + allBlocks.push(block.toBinary(this.blocksLim)); + remaining--; + bix++; + } + } + else { + // Fill remaining space with 0xFF + const remainingSize = this.imgSize - allBlocks.length * this.buildConfig.blockSize; + if (remainingSize > 0) { + const padding = new Uint8Array(remainingSize); + padding.fill(0xff); + allBlocks.push(padding); + } + } + // Concatenate all blocks + const totalSize = allBlocks.reduce((sum, block) => sum + block.length, 0); + const img = new Uint8Array(totalSize); + let offset = 0; + for (const block of allBlocks) { + img.set(block, offset); + offset += block.length; + } + return img; + } + listFiles() { + // This would require parsing the blocks - implement in fromBinary + throw new Error("listFiles requires fromBinary to be called first"); + } + readFile() { + // This would require parsing the blocks - implement in fromBinary + throw new Error("readFile requires fromBinary to be called first"); + } + deleteFile() { + // SPIFFS doesn't support in-place deletion + // Need to recreate filesystem without the file + throw new Error("deleteFile not yet implemented - requires filesystem recreation"); + } +} + +/** + * SPIFFS Reader - Parse and extract files from SPIFFS images + * Based on ESP-IDF spiffsgen.py extract_files() method + */ +class SpiffsReader { + constructor(imageData, buildConfig) { + this.imageData = imageData; + this.buildConfig = buildConfig; + this.filesMap = new Map(); + } + unpack(format, data, offset = 0) { + const view = new DataView(data.buffer, data.byteOffset + offset); + const results = []; + let pos = 0; + for (const type of format) { + switch (type) { + case "B": + results.push(view.getUint8(pos)); + pos += 1; + break; + case "H": + results.push(this.buildConfig.endianness === "little" + ? view.getUint16(pos, true) + : view.getUint16(pos, false)); + pos += 2; + break; + case "I": + results.push(this.buildConfig.endianness === "little" + ? view.getUint32(pos, true) + : view.getUint32(pos, false)); + pos += 4; + break; + } + } + return results; + } + parse() { + const blocksCount = Math.floor(this.imageData.length / this.buildConfig.blockSize); + for (let bix = 0; bix < blocksCount; bix++) { + const blockOffset = bix * this.buildConfig.blockSize; + const blockData = this.imageData.slice(blockOffset, blockOffset + this.buildConfig.blockSize); + this.parseBlock(blockData); + } + } + parseBlock(blockData) { + // Parse lookup pages to find valid objects + for (let pageIdx = 0; pageIdx < this.buildConfig.OBJ_LU_PAGES_PER_BLOCK; pageIdx++) { + const luPageOffset = pageIdx * this.buildConfig.pageSize; + const luPageData = blockData.slice(luPageOffset, luPageOffset + this.buildConfig.pageSize); + // Parse object IDs from lookup page + for (let i = 0; i < luPageData.length; i += this.buildConfig.objIdLen) { + if (i + this.buildConfig.objIdLen > luPageData.length) + break; + const objIdBytes = luPageData.slice(i, i + this.buildConfig.objIdLen); + const [objId] = this.unpack(this.buildConfig.objIdLen === 1 + ? "B" + : this.buildConfig.objIdLen === 2 + ? "H" + : "I", objIdBytes); + // Check if it's a valid object (not erased/empty) + const emptyValue = (1 << (this.buildConfig.objIdLen * 8)) - 1; + if (objId === emptyValue) + continue; + // Check if it's an index page (MSB set) + const isIndex = (objId & (1 << (this.buildConfig.objIdLen * 8 - 1))) !== 0; + const realObjId = objId & ~(1 << (this.buildConfig.objIdLen * 8 - 1)); + if (isIndex && !this.filesMap.has(realObjId)) { + this.filesMap.set(realObjId, { + name: null, + size: 0, + dataPages: [], + }); + } + } + } + // Parse actual pages to get file metadata and content + for (let pageIdx = this.buildConfig.OBJ_LU_PAGES_PER_BLOCK; pageIdx < this.buildConfig.PAGES_PER_BLOCK; pageIdx++) { + const pageOffset = pageIdx * this.buildConfig.pageSize; + const pageData = blockData.slice(pageOffset, pageOffset + this.buildConfig.pageSize); + this.parsePage(pageData); + } + } + parsePage(pageData) { + // Parse page header + const headerFormat = (this.buildConfig.objIdLen === 1 + ? "B" + : this.buildConfig.objIdLen === 2 + ? "H" + : "I") + + (this.buildConfig.spanIxLen === 1 + ? "B" + : this.buildConfig.spanIxLen === 2 + ? "H" + : "I") + + "B"; + const headerSize = this.buildConfig.objIdLen + + this.buildConfig.spanIxLen + + SPIFFS_PH_FLAG_LEN; + if (pageData.length < headerSize) + return; + const [objId, spanIx, flags] = this.unpack(headerFormat, pageData); + // Check for valid page + const emptyId = (1 << (this.buildConfig.objIdLen * 8)) - 1; + if (objId === emptyId) + return; + const isIndex = (objId & (1 << (this.buildConfig.objIdLen * 8 - 1))) !== 0; + const realObjId = objId & ~(1 << (this.buildConfig.objIdLen * 8 - 1)); + if (isIndex && flags === SPIFFS_PH_FLAG_USED_FINAL_INDEX) { + // Index page - contains file metadata + if (!this.filesMap.has(realObjId)) { + this.filesMap.set(realObjId, { + name: null, + size: 0, + dataPages: [], + }); + } + // Only first index page (span_ix == 0) has filename and size + if (spanIx === 0) { + this.parseIndexPage(pageData, headerSize, realObjId); + } + } + else if (!isIndex && flags === SPIFFS_PH_FLAG_USED_FINAL) { + // Data page - contains file content + if (this.filesMap.has(realObjId)) { + const contentStart = headerSize; + const content = pageData.slice(contentStart, contentStart + this.buildConfig.OBJ_DATA_PAGE_CONTENT_LEN); + this.filesMap.get(realObjId).dataPages.push([spanIx, content]); + } + } + } + parseIndexPage(pageData, headerSize, objId) { + // Skip to size and type fields + let offset = headerSize + this.buildConfig.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD; + const sizeTypeFormat = "IB"; + const sizeTypeSize = SPIFFS_PH_IX_SIZE_LEN + SPIFFS_PH_IX_OBJ_TYPE_LEN; + if (offset + sizeTypeSize <= pageData.length) { + const [fileSize] = this.unpack(sizeTypeFormat, pageData, offset); + offset += sizeTypeSize; + // Read filename + const nameEnd = offset + this.buildConfig.objNameLen; + if (nameEnd <= pageData.length) { + const nameBytes = pageData.slice(offset, nameEnd); + // Find null terminator + const nullPos = nameBytes.indexOf(0); + const actualNameBytes = nullPos !== -1 ? nameBytes.slice(0, nullPos) : nameBytes; + const filename = new TextDecoder().decode(actualNameBytes); + const fileInfo = this.filesMap.get(objId); + fileInfo.name = filename; + fileInfo.size = fileSize; + } + } + } + listFiles() { + const files = []; + for (const [, fileInfo] of this.filesMap) { + if (fileInfo.name === null) + continue; + // Sort data pages by span index + fileInfo.dataPages.sort((a, b) => a[0] - b[0]); + // Reconstruct file content + const chunks = []; + let totalWritten = 0; + for (const [, content] of fileInfo.dataPages) { + const remaining = fileInfo.size - totalWritten; + if (remaining <= 0) + break; + const toWrite = Math.min(content.length, remaining); + chunks.push(content.slice(0, toWrite)); + totalWritten += toWrite; + } + // Concatenate chunks + const data = new Uint8Array(totalWritten); + let offset = 0; + for (const chunk of chunks) { + data.set(chunk, offset); + offset += chunk.length; + } + files.push({ + name: fileInfo.name, + size: fileInfo.size, + data, + }); + } + return files; + } + readFile(path) { + const files = this.listFiles(); + const file = files.find((f) => f.name === path || f.name === "/" + path); + return file ? file.data : null; + } +} + +/** + * SPIFFS Module Entry Point + */ +// Default ESP32 SPIFFS configuration +const DEFAULT_SPIFFS_CONFIG = { + pageSize: 256, + blockSize: 4096, + objNameLen: 32, + metaLen: 4, + useMagic: true, + useMagicLen: true, + alignedObjIxTables: false, +}; + +/// +const connect = async (logger) => { + // - Request a port and open a connection. + // Try to use requestSerialPort if available (supports WebUSB for Android) + let port; + const customRequestPort = globalThis.requestSerialPort; + if (typeof customRequestPort === "function") { + port = await customRequestPort(); + } + else { + // Check if Web Serial API is available + if (!navigator.serial) { + throw new Error("Web Serial API is not supported in this browser. " + + "Please use Chrome, Edge, or Opera on desktop, or Chrome on Android. " + + "Note: The page must be served over HTTPS or localhost."); + } + port = await navigator.serial.requestPort(); + } + // Only open if not already open (requestSerialPort may return an opened port) + if (!port.readable || !port.writable) { + await port.open({ baudRate: ESP_ROM_BAUD }); + } + return new ESPLoader(port, logger); +}; +const connectWithPort = async (port, logger) => { + // Connect using an already opened port (useful for WebUSB wrapper) + if (!port) { + throw new Error("Port is required"); + } + // Check if port is already open, if not open it + if (!port.readable || !port.writable) { + await port.open({ baudRate: ESP_ROM_BAUD }); + } + return new ESPLoader(port, logger); +}; + +export { CHIP_ERASE_TIMEOUT, CHIP_FAMILY_ESP32, CHIP_FAMILY_ESP32C2, CHIP_FAMILY_ESP32C3, CHIP_FAMILY_ESP32C5, CHIP_FAMILY_ESP32C6, CHIP_FAMILY_ESP32C61, CHIP_FAMILY_ESP32H2, CHIP_FAMILY_ESP32H21, CHIP_FAMILY_ESP32H4, CHIP_FAMILY_ESP32P4, CHIP_FAMILY_ESP32S2, CHIP_FAMILY_ESP32S3, CHIP_FAMILY_ESP32S31, CHIP_FAMILY_ESP8266, DEFAULT_SPIFFS_CONFIG, DEFAULT_TIMEOUT, ERASE_REGION_TIMEOUT_PER_MB, ESP8266_LITTLEFS_BLOCK_SIZE, ESP8266_LITTLEFS_BLOCK_SIZE_CANDIDATES, ESP8266_LITTLEFS_PAGE_SIZE, ESP8266_SPIFFS_BLOCK_SIZE, ESP8266_SPIFFS_PAGE_SIZE, ESPLoader, ESP_CHANGE_BAUDRATE, ESP_CHECKSUM_MAGIC, ESP_ERASE_FLASH, ESP_ERASE_REGION, ESP_FLASH_BEGIN, ESP_FLASH_DATA, ESP_FLASH_DEFL_BEGIN, ESP_FLASH_DEFL_DATA, ESP_FLASH_DEFL_END, ESP_FLASH_END, ESP_GET_SECURITY_INFO, ESP_MEM_BEGIN, ESP_MEM_DATA, ESP_MEM_END, ESP_RAM_BLOCK, ESP_READ_FLASH, ESP_READ_REG, ESP_SPI_ATTACH, ESP_SPI_FLASH_MD5, ESP_SPI_SET_PARAMS, ESP_SYNC, ESP_WRITE_REG, FATFS_BLOCK_SIZE_CANDIDATES, FATFS_DEFAULT_BLOCK_SIZE, FLASH_READ_TIMEOUT, FilesystemType, LITTLEFS_BLOCK_SIZE_CANDIDATES, LITTLEFS_DEFAULT_BLOCK_SIZE, MAX_TIMEOUT, MEM_END_ROM_TIMEOUT, ROM_INVALID_RECV_MSG, SYNC_TIMEOUT, SpiffsBuildConfig, SpiffsFS, SpiffsReader, USB_RAM_BLOCK, connect, connectWithPort, detectFilesystemFromImage, detectFilesystemType, formatMacAddr, formatSize, getBlockSizeCandidates, getDefaultBlockSize, getESP8266FilesystemLayout, hexFormatter, parsePartitionTable, scanESP8266Filesystem, sleep, toHex }; From 488e5ac25ae262ad72579ef9a8c9d873630e0e04 Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Tue, 7 Apr 2026 16:48:58 +0200 Subject: [PATCH 5/5] clean up env before build --- js/console.js | 3 ++- package.json | 2 +- tsconfig.util.json | 9 ++------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/js/console.js b/js/console.js index 7eb3d335..eb393726 100644 --- a/js/console.js +++ b/js/console.js @@ -17,7 +17,8 @@ export class ESP32ToolConsole { this.allowInput = allowInput; this.console = null; this.cancelConnection = null; - // Command history buffer + // Command history buffer — keep in sync with src/console.ts + // (history logic is duplicated there; update both files together) this.commandHistory = []; this.historyIndex = -1; this.currentInput = ""; diff --git a/package.json b/package.json index b8f0eed8..7ff09c5f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "node": ">=25.4.0" }, "scripts": { - "prebuild": "node -e \"const fs=require('fs'); fs.rmSync('dist',{recursive:true,force:true}); fs.rmSync('js/modules',{recursive:true,force:true}); fs.mkdirSync('js/modules',{recursive:true});\"", + "prebuild": "node -e \"const fs=require('fs'); fs.rmSync('dist',{recursive:true,force:true}); fs.rmSync('js/modules',{recursive:true,force:true}); fs.rmSync('js/util',{recursive:true,force:true}); fs.mkdirSync('js/modules',{recursive:true}); fs.mkdirSync('js/util',{recursive:true});\"", "build": "npm run prebuild && node update-sw-version.cjs && tsc --skipLibCheck && tsc -p tsconfig.util.json && rollup -c && node -e \"const fs=require('fs'); fs.readdirSync('dist/web').filter(f=>f.endsWith('.js')).forEach(f=>fs.copyFileSync('dist/web/'+f,'js/modules/'+f)); fs.renameSync('js/modules/index.js','js/modules/esptool.js');\" && node fix-cli-imports.cjs", "build:binary": "node build-single-binary.cjs", "build:cli-electron": "node build-electron-cli.cjs", diff --git a/tsconfig.util.json b/tsconfig.util.json index 31813857..17172be9 100644 --- a/tsconfig.util.json +++ b/tsconfig.util.json @@ -1,14 +1,9 @@ { + "extends": "./tsconfig.json", "compilerOptions": { - "lib": ["es2019", "dom"], - "target": "es2019", - "module": "es2020", - "moduleResolution": "node", "outDir": "js/util", "declaration": false, - "strict": true, - "skipLibCheck": true, "removeComments": false }, - "include": ["src/util/*.ts"] + "include": ["src/util/**/*.ts"] }