From b1c5c4aa26c20d0fda76b926f20f78eca90e9bf7 Mon Sep 17 00:00:00 2001 From: kerms Date: Mon, 8 Apr 2024 12:27:19 +0800 Subject: [PATCH] initial commit --- esp-flasher/EspFlasher.vue | 469 +++++++ esp-flasher/lib_esptools-js/error.d.ts | 11 + esp-flasher/lib_esptools-js/error.js | 11 + esp-flasher/lib_esptools-js/esploader.d.ts | 495 +++++++ esp-flasher/lib_esptools-js/esploader.js | 1249 +++++++++++++++++ esp-flasher/lib_esptools-js/index.d.ts | 4 + esp-flasher/lib_esptools-js/index.js | 4 + esp-flasher/lib_esptools-js/reset.d.ts | 94 ++ esp-flasher/lib_esptools-js/reset.js | 174 +++ .../lib_esptools-js/targets/esp32.d.ts | 37 + esp-flasher/lib_esptools-js/targets/esp32.js | 191 +++ .../lib_esptools-js/targets/esp32c2.d.ts | 42 + .../lib_esptools-js/targets/esp32c2.js | 120 ++ .../lib_esptools-js/targets/esp32c3.d.ts | 40 + .../lib_esptools-js/targets/esp32c3.js | 101 ++ .../lib_esptools-js/targets/esp32c6.d.ts | 40 + .../lib_esptools-js/targets/esp32c6.js | 101 ++ .../lib_esptools-js/targets/esp32h2.d.ts | 42 + .../lib_esptools-js/targets/esp32h2.js | 86 ++ .../lib_esptools-js/targets/esp32s2.d.ts | 39 + .../lib_esptools-js/targets/esp32s2.js | 106 ++ .../lib_esptools-js/targets/esp32s3.d.ts | 42 + .../lib_esptools-js/targets/esp32s3.js | 85 ++ .../lib_esptools-js/targets/esp8266.d.ts | 43 + .../lib_esptools-js/targets/esp8266.js | 124 ++ esp-flasher/lib_esptools-js/targets/rom.d.ts | 88 ++ esp-flasher/lib_esptools-js/targets/rom.js | 14 + .../targets/stub_flasher/stub_flasher_32.json | 7 + .../stub_flasher/stub_flasher_32c2.json | 8 + .../stub_flasher/stub_flasher_32c3.json | 7 + .../stub_flasher/stub_flasher_32c6.json | 7 + .../stub_flasher/stub_flasher_32h2.json | 7 + .../stub_flasher/stub_flasher_32s2.json | 7 + .../stub_flasher/stub_flasher_32s3.json | 7 + .../stub_flasher/stub_flasher_8266.json | 7 + esp-flasher/lib_esptools-js/webserial.d.ts | 148 ++ esp-flasher/lib_esptools-js/webserial.js | 347 +++++ 37 files changed, 4404 insertions(+) create mode 100644 esp-flasher/EspFlasher.vue create mode 100644 esp-flasher/lib_esptools-js/error.d.ts create mode 100644 esp-flasher/lib_esptools-js/error.js create mode 100644 esp-flasher/lib_esptools-js/esploader.d.ts create mode 100644 esp-flasher/lib_esptools-js/esploader.js create mode 100644 esp-flasher/lib_esptools-js/index.d.ts create mode 100644 esp-flasher/lib_esptools-js/index.js create mode 100644 esp-flasher/lib_esptools-js/reset.d.ts create mode 100644 esp-flasher/lib_esptools-js/reset.js create mode 100644 esp-flasher/lib_esptools-js/targets/esp32.d.ts create mode 100644 esp-flasher/lib_esptools-js/targets/esp32.js create mode 100644 esp-flasher/lib_esptools-js/targets/esp32c2.d.ts create mode 100644 esp-flasher/lib_esptools-js/targets/esp32c2.js create mode 100644 esp-flasher/lib_esptools-js/targets/esp32c3.d.ts create mode 100644 esp-flasher/lib_esptools-js/targets/esp32c3.js create mode 100644 esp-flasher/lib_esptools-js/targets/esp32c6.d.ts create mode 100644 esp-flasher/lib_esptools-js/targets/esp32c6.js create mode 100644 esp-flasher/lib_esptools-js/targets/esp32h2.d.ts create mode 100644 esp-flasher/lib_esptools-js/targets/esp32h2.js create mode 100644 esp-flasher/lib_esptools-js/targets/esp32s2.d.ts create mode 100644 esp-flasher/lib_esptools-js/targets/esp32s2.js create mode 100644 esp-flasher/lib_esptools-js/targets/esp32s3.d.ts create mode 100644 esp-flasher/lib_esptools-js/targets/esp32s3.js create mode 100644 esp-flasher/lib_esptools-js/targets/esp8266.d.ts create mode 100644 esp-flasher/lib_esptools-js/targets/esp8266.js create mode 100644 esp-flasher/lib_esptools-js/targets/rom.d.ts create mode 100644 esp-flasher/lib_esptools-js/targets/rom.js create mode 100644 esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32.json create mode 100644 esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c2.json create mode 100644 esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c3.json create mode 100644 esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c6.json create mode 100644 esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32h2.json create mode 100644 esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32s2.json create mode 100644 esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32s3.json create mode 100644 esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_8266.json create mode 100644 esp-flasher/lib_esptools-js/webserial.d.ts create mode 100644 esp-flasher/lib_esptools-js/webserial.js diff --git a/esp-flasher/EspFlasher.vue b/esp-flasher/EspFlasher.vue new file mode 100644 index 0000000..fe99e3e --- /dev/null +++ b/esp-flasher/EspFlasher.vue @@ -0,0 +1,469 @@ + + + + + + + + + diff --git a/esp-flasher/lib_esptools-js/error.d.ts b/esp-flasher/lib_esptools-js/error.d.ts new file mode 100644 index 0000000..0a61f83 --- /dev/null +++ b/esp-flasher/lib_esptools-js/error.d.ts @@ -0,0 +1,11 @@ +/** + * Represents a Espressif chip error. + */ +declare class ESPError extends Error { +} +/** + * Represents a Espressif timeout chip error. + */ +declare class TimeoutError extends ESPError { +} +export { ESPError, TimeoutError }; diff --git a/esp-flasher/lib_esptools-js/error.js b/esp-flasher/lib_esptools-js/error.js new file mode 100644 index 0000000..6150dea --- /dev/null +++ b/esp-flasher/lib_esptools-js/error.js @@ -0,0 +1,11 @@ +/** + * Represents a Espressif chip error. + */ +class ESPError extends Error { +} +/** + * Represents a Espressif timeout chip error. + */ +class TimeoutError extends ESPError { +} +export { ESPError, TimeoutError }; diff --git a/esp-flasher/lib_esptools-js/esploader.d.ts b/esp-flasher/lib_esptools-js/esploader.d.ts new file mode 100644 index 0000000..b0da13d --- /dev/null +++ b/esp-flasher/lib_esptools-js/esploader.d.ts @@ -0,0 +1,495 @@ +/// +import { Transport, SerialOptions } from "./webserial"; +import { ROM } from "./targets/rom"; +/** + * Options for flashing a device with firmware. + * @interface FlashOptions + */ +export interface FlashOptions { + /** + * An array of file objects representing the data to be flashed. + * @type {Array<{ data: string; address: number }>} + */ + fileArray: { + data: string; + address: number; + }[]; + /** + * The size of the flash memory to be used. + * @type {string} + */ + flashSize: string; + /** + * The flash mode to be used (e.g., QIO, QOUT, DIO, DOUT). + * @type {string} + */ + flashMode: string; + /** + * The flash frequency to be used (e.g., 40MHz, 80MHz). + * @type {string} + */ + flashFreq: string; + /** + * Flag indicating whether to erase all existing data in the flash memory before flashing. + * @type {boolean} + */ + eraseAll: boolean; + /** + * Flag indicating whether to compress the data before flashing. + * @type {boolean} + */ + compress: boolean; + /** + * A function to report the progress of the flashing operation (optional). + * @type {(fileIndex: number, written: number, total: number) => void} + */ + reportProgress?: (fileIndex: number, written: number, total: number) => void; + /** + * A function to calculate the MD5 hash of the firmware image (optional). + * @type {(image: string) => string} + */ + calculateMD5Hash?: (image: string) => string; +} +/** + * Options to configure ESPLoader. + * @interface LoaderOptions + */ +export interface LoaderOptions { + /** + * The transport mechanism to communicate with the device. + * @type {Transport} + */ + transport: Transport; + /** + * The port to initialize the transport class. + * @type {SerialPort} + */ + port?: SerialPort; + /** + * Set of options for SerialPort class. + * @type {Transport} + */ + serialOptions?: SerialOptions; + /** + * The baud rate to be used for communication with the device. + * @type {number} + */ + baudrate: number; + /** + * An optional terminal interface to interact with the loader during the process. + * @type {IEspLoaderTerminal} + */ + terminal?: IEspLoaderTerminal; + /** + * The baud rate to be used during the initial ROM communication with the device. + * @type {number} + */ + romBaudrate: number; + /** + * Flag indicating whether to enable debug logging for the loader (optional). + * @type {boolean} + */ + debugLogging?: boolean; + enableTracing?: boolean; +} +declare type FlashReadCallback = ((packet: Uint8Array, progress: number, totalSize: number) => void) | null; +/** + * A wrapper around your implementation of a terminal by + * implementing the clean, write and writeLine methods + * which are called by the ESPLoader class. + * @interface IEspLoaderTerminal + */ +export interface IEspLoaderTerminal { + /** + * Execute a terminal clean command. + */ + clean: () => void; + /** + * Write a string of data that include a line terminator. + * @param {string} data - The string to write with line terminator. + */ + writeLine: (data: string) => void; + /** + * Write a string of data. + * @param {string} data - The string to write. + */ + write: (data: string) => void; +} +export declare class ESPLoader { + ESP_RAM_BLOCK: number; + ESP_FLASH_BEGIN: number; + ESP_FLASH_DATA: number; + ESP_FLASH_END: number; + ESP_MEM_BEGIN: number; + ESP_MEM_END: number; + ESP_MEM_DATA: number; + ESP_WRITE_REG: number; + ESP_READ_REG: number; + ESP_SPI_ATTACH: number; + ESP_CHANGE_BAUDRATE: number; + ESP_FLASH_DEFL_BEGIN: number; + ESP_FLASH_DEFL_DATA: number; + ESP_FLASH_DEFL_END: number; + ESP_SPI_FLASH_MD5: number; + ESP_ERASE_FLASH: number; + ESP_ERASE_REGION: number; + ESP_READ_FLASH: number; + ESP_RUN_USER_CODE: number; + ESP_IMAGE_MAGIC: number; + ESP_CHECKSUM_MAGIC: number; + ROM_INVALID_RECV_MSG: number; + ERASE_REGION_TIMEOUT_PER_MB: number; + ERASE_WRITE_TIMEOUT_PER_MB: number; + MD5_TIMEOUT_PER_MB: number; + CHIP_ERASE_TIMEOUT: number; + FLASH_READ_TIMEOUT: number; + MAX_TIMEOUT: number; + CHIP_DETECT_MAGIC_REG_ADDR: number; + DETECTED_FLASH_SIZES: { + [key: number]: string; + }; + DETECTED_FLASH_SIZES_NUM: { + [key: number]: number; + }; + USB_JTAG_SERIAL_PID: number; + chip: ROM; + IS_STUB: boolean; + FLASH_WRITE_SIZE: number; + transport: Transport; + private baudrate; + private serialOptions?; + private terminal?; + private romBaudrate; + private debugLogging; + /** + * Create a new ESPLoader to perform serial communication + * such as read/write flash memory and registers using a LoaderOptions object. + * @param {LoaderOptions} options - LoaderOptions object argument for ESPLoader. + * ``` + * const myLoader = new ESPLoader({ transport: Transport, baudrate: number, terminal?: IEspLoaderTerminal }); + * ``` + */ + constructor(options: LoaderOptions); + _sleep(ms: number): Promise; + /** + * Write to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ + write(str: string, withNewline?: boolean): void; + /** + * Write error message to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ + error(str: string, withNewline?: boolean): void; + /** + * Write information message to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ + info(str: string, withNewline?: boolean): void; + /** + * Write debug message to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ + debug(str: string, withNewline?: boolean): void; + /** + * Convert short integer to byte array + * @param {number} i - Number to convert. + * @returns {Uint8Array} Byte array. + */ + _shortToBytearray(i: number): Uint8Array; + /** + * Convert an integer to byte array + * @param {number} i - Number to convert. + * @returns {ROM} The chip ROM class related to given magic hex number. + */ + _intToByteArray(i: number): Uint8Array; + /** + * Convert a byte array to short integer. + * @param {number} i - Number to convert. + * @param {number} j - Number to convert. + * @returns {number} Return a short integer number. + */ + _byteArrayToShort(i: number, j: number): number; + /** + * Convert a byte array to integer. + * @param {number} i - Number to convert. + * @param {number} j - Number to convert. + * @param {number} k - Number to convert. + * @param {number} l - Number to convert. + * @returns {number} Return a integer number. + */ + _byteArrayToInt(i: number, j: number, k: number, l: number): number; + /** + * Append a buffer array after another buffer array + * @param {ArrayBuffer} buffer1 - First array buffer. + * @param {ArrayBuffer} buffer2 - magic hex number to select ROM. + * @returns {ArrayBufferLike} Return an array buffer. + */ + _appendBuffer(buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBufferLike; + /** + * Append a buffer array after another buffer array + * @param {Uint8Array} arr1 - First array buffer. + * @param {Uint8Array} arr2 - magic hex number to select ROM. + * @returns {Uint8Array} Return a 8 bit unsigned array. + */ + _appendArray(arr1: Uint8Array, arr2: Uint8Array): Uint8Array; + /** + * Convert a unsigned 8 bit integer array to byte string. + * @param {Uint8Array} u8Array - magic hex number to select ROM. + * @returns {string} Return the equivalent string. + */ + ui8ToBstr(u8Array: Uint8Array): string; + /** + * Convert a byte string to unsigned 8 bit integer array. + * @param {string} bStr - binary string input + * @returns {Uint8Array} Return a 8 bit unsigned integer array. + */ + bstrToUi8(bStr: string): Uint8Array; + /** + * Flush the serial input by raw read with 200 ms timeout. + */ + flushInput(): Promise; + /** + * Use the device serial port read function with given timeout to create a valid packet. + * @param {number} op Operation number + * @param {number} timeout timeout number in milliseconds + * @returns {[number, Uint8Array]} valid response packet. + */ + readPacket(op?: number | null, timeout?: number): Promise<[number, Uint8Array]>; + /** + * Write a serial command to the chip + * @param {number} op - Operation number + * @param {Uint8Array} data - Unsigned 8 bit array + * @param {number} chk - channel number + * @param {boolean} waitResponse - wait for response ? + * @param {number} timeout - timeout number in milliseconds + * @returns {Promise<[number, Uint8Array]>} Return a number and a 8 bit unsigned integer array. + */ + command(op?: number | null, data?: Uint8Array, chk?: number, waitResponse?: boolean, timeout?: number): Promise<[number, Uint8Array]>; + /** + * Read a register from chip. + * @param {number} addr - Register address number + * @param {number} timeout - Timeout in milliseconds (Default: 3000ms) + * @returns {number} - Command number value + */ + readReg(addr: number, timeout?: number): Promise; + /** + * Write a number value to register address in chip. + * @param {number} addr - Register address number + * @param {number} value - Number value to write in register + * @param {number} mask - Hex number for mask + * @param {number} delayUs Delay number + * @param {number} delayAfterUs Delay after previous delay + */ + writeReg(addr: number, value: number, mask?: number, delayUs?: number, delayAfterUs?: number): Promise; + /** + * Sync chip by sending sync command. + * @returns {[number, Uint8Array]} Command result + */ + sync(): Promise<[number, Uint8Array]>; + /** + * Attempt to connect to the chip by sending a reset sequence and later a sync command. + * @param {string} mode - Reset mode to use + * @param {boolean} esp32r0Delay - Enable delay for ESP32 R0 + * @returns {string} - Returns 'success' or 'error' message. + */ + _connectAttempt(mode?: string, esp32r0Delay?: boolean): Promise<"error" | "success">; + /** + * Perform a connection to chip. + * @param {string} mode - Reset mode to use. Example: 'default_reset' | 'no_reset' + * @param {number} attempts - Number of connection attempts + * @param {boolean} detecting - Detect the connected chip + */ + connect(mode?: string, attempts?: number, detecting?: boolean): Promise; + /** + * Connect and detect the existing chip. + * @param {string} mode Reset mode to use for connection. + */ + detectChip(mode?: string): Promise; + /** + * Execute the command and check the command response. + * @param {string} opDescription Command operation description. + * @param {number} op Command operation number + * @param {Uint8Array} data Command value + * @param {number} chk Checksum to use + * @param {number} timeout TImeout number in milliseconds (ms) + * @returns {number} Command result + */ + checkCommand(opDescription?: string, op?: number | null, data?: Uint8Array, chk?: number, timeout?: number): Promise; + /** + * Start downloading an application image to RAM + * @param {number} size Image size number + * @param {number} blocks Number of data blocks + * @param {number} blocksize Size of each data block + * @param {number} offset Image offset number + */ + memBegin(size: number, blocks: number, blocksize: number, offset: number): Promise; + /** + * Get the checksum for given unsigned 8-bit array + * @param {Uint8Array} data Unsigned 8-bit integer array + * @returns {number} - Array checksum + */ + checksum: (data: Uint8Array) => number; + /** + * Send a block of image to RAM + * @param {Uint8Array} buffer Unsigned 8-bit array + * @param {number} seq Sequence number + */ + memBlock(buffer: Uint8Array, seq: number): Promise; + /** + * Leave RAM download mode and run application + * @param {number} entrypoint - Entrypoint number + */ + memFinish(entrypoint: number): Promise; + /** + * Configure SPI flash pins + * @param {number} hspiArg - Argument for SPI attachment + */ + flashSpiAttach(hspiArg: number): Promise; + /** + * Scale timeouts which are size-specific. + * @param {number} secondsPerMb Seconds per megabytes as number + * @param {number} sizeBytes Size bytes number + * @returns {number} - Scaled timeout for specified size. + */ + timeoutPerMb: (secondsPerMb: number, sizeBytes: number) => number; + /** + * Start downloading to Flash (performs an erase) + * @param {number} size Size to erase + * @param {number} offset Offset to erase + * @returns {number} Number of blocks (of size self.FLASH_WRITE_SIZE) to write. + */ + flashBegin(size: number, offset: number): Promise; + /** + * Start downloading compressed data to Flash (performs an erase) + * @param {number} size Write size + * @param {number} compsize Compressed size + * @param {number} offset Offset for write + * @returns {number} Returns number of blocks (size self.FLASH_WRITE_SIZE) to write. + */ + flashDeflBegin(size: number, compsize: number, offset: number): Promise; + /** + * Write block to flash, retry if fail + * @param {Uint8Array} data Unsigned 8-bit array data. + * @param {number} seq Sequence number + * @param {number} timeout Timeout in milliseconds (ms) + */ + flashBlock(data: Uint8Array, seq: number, timeout: number): Promise; + /** + * Write block to flash, send compressed, retry if fail + * @param {Uint8Array} data Unsigned int 8-bit array data to write + * @param {number} seq Sequence number + * @param {number} timeout Timeout in milliseconds (ms) + */ + flashDeflBlock(data: Uint8Array, seq: number, timeout: number): Promise; + /** + * Leave flash mode and run/reboot + * @param {boolean} reboot Reboot after leaving flash mode ? + */ + flashFinish(reboot?: boolean): Promise; + /** + * Leave compressed flash mode and run/reboot + * @param {boolean} reboot Reboot after leaving flash mode ? + */ + flashDeflFinish(reboot?: boolean): Promise; + /** + * 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 spiflashCommand is an actual command + * byte, sent over the wire. + * + * After writing command byte, writes 'data' to MOSI and then + * reads back 'readBits' of reply on MISO. Result is a number. + * @param {number} spiflashCommand Command to execute in SPI + * @param {Uint8Array} data Data to send + * @param {number} readBits Number of bits to read + * @returns {number} Register SPI_W0_REG value + */ + runSpiflashCommand(spiflashCommand: number, data: Uint8Array, readBits: number): Promise; + /** + * Read flash id by executing the SPIFLASH_RDID flash command. + * @returns {Promise} Register SPI_W0_REG value + */ + readFlashId(): Promise; + /** + * Execute the erase flash command + * @returns {Promise} Erase flash command result + */ + eraseFlash(): Promise; + /** + * Convert a number or unsigned 8-bit array to hex string + * @param {number | Uint8Array } buffer Data to convert to hex string. + * @returns {string} A hex string + */ + toHex(buffer: number | Uint8Array): string; + /** + * Calculate the MD5 Checksum command + * @param {number} addr Address number + * @param {number} size Package size + * @returns {string} MD5 Checksum string + */ + flashMd5sum(addr: number, size: number): Promise; + readFlash(addr: number, size: number, onPacketReceived?: FlashReadCallback): Promise; + /** + * Upload the flasher ROM bootloader (flasher stub) to the chip. + * @returns {ROM} The Chip ROM + */ + runStub(): Promise; + /** + * Change the chip baudrate. + */ + changeBaud(): Promise; + /** + * Execute the main function of ESPLoader. + * @param {string} mode Reset mode to use + * @returns {string} chip ROM + */ + main(mode?: string): Promise; + /** + * Get flash size bytes from flash size string. + * @param {string} flashSize Flash Size string + * @returns {number} Flash size bytes + */ + flashSizeBytes: (flashSize: string) => number; + /** + * Parse a given flash size string to a number + * @param {string} flsz Flash size to request + * @returns {number} Flash size number + */ + parseFlashSizeArg(flsz: string): number; + /** + * Update the image flash parameters with given arguments. + * @param {string} image binary image as string + * @param {number} address flash address number + * @param {string} flashSize Flash size string + * @param {string} flashMode Flash mode string + * @param {string} flashFreq Flash frequency string + * @returns {string} modified image string + */ + _updateImageFlashParams(image: string, address: number, flashSize: string, flashMode: string, flashFreq: string): string; + /** + * Write set of file images into given address based on given FlashOptions object. + * @param {FlashOptions} options FlashOptions to configure how and what to write into flash. + */ + writeFlash(options: FlashOptions): Promise; + /** + * Read SPI flash manufacturer and device id. + */ + flashId(): Promise; + getFlashSize(): Promise; + /** + * Perform a chip hard reset by setting RTS to LOW and then HIGH. + */ + hardReset(): Promise; + /** + * Soft reset the device chip. Soft reset with run user code is the closest. + */ + softReset(): Promise; +} +export {}; diff --git a/esp-flasher/lib_esptools-js/esploader.js b/esp-flasher/lib_esptools-js/esploader.js new file mode 100644 index 0000000..bce3bfc --- /dev/null +++ b/esp-flasher/lib_esptools-js/esploader.js @@ -0,0 +1,1249 @@ +import { ESPError } from "./error.js"; +import { deflate, Inflate } from "pako"; +import { Transport } from "./webserial.js"; +import { customReset, usbJTAGSerialReset } from "./reset.js"; +import atob from "atob-lite"; +/** + * Return the chip ROM based on the given magic number + * @param {number} magic - magic hex number to select ROM. + * @returns {ROM} The chip ROM class related to given magic hex number. + */ +async function magic2Chip(magic) { + switch (magic) { + case 0x00f01d83: { + const { ESP32ROM } = await import("./targets/esp32.js"); + return new ESP32ROM(); + } + case 0x6f51306f: + case 0x7c41a06f: { + const { ESP32C2ROM } = await import("./targets/esp32c2.js"); + return new ESP32C2ROM(); + } + case 0x6921506f: + case 0x1b31506f: + case 0x4881606f: + case 0x4361606f: { + const { ESP32C3ROM } = await import("./targets/esp32c3.js"); + return new ESP32C3ROM(); + } + case 0x2ce0806f: { + const { ESP32C6ROM } = await import("./targets/esp32c6.js"); + return new ESP32C6ROM(); + } + case 0xd7b73e80: { + const { ESP32H2ROM } = await import("./targets/esp32h2.js"); + return new ESP32H2ROM(); + } + case 0x09: { + const { ESP32S3ROM } = await import("./targets/esp32s3.js"); + return new ESP32S3ROM(); + } + case 0x000007c6: { + const { ESP32S2ROM } = await import("./targets/esp32s2.js"); + return new ESP32S2ROM(); + } + case 0xfff0c101: { + const { ESP8266ROM } = await import("./targets/esp8266.js"); + return new ESP8266ROM(); + } + default: + return null; + } +} +export class ESPLoader { + /** + * Create a new ESPLoader to perform serial communication + * such as read/write flash memory and registers using a LoaderOptions object. + * @param {LoaderOptions} options - LoaderOptions object argument for ESPLoader. + * ``` + * const myLoader = new ESPLoader({ transport: Transport, baudrate: number, terminal?: IEspLoaderTerminal }); + * ``` + */ + constructor(options) { + this.ESP_RAM_BLOCK = 0x1800; + this.ESP_FLASH_BEGIN = 0x02; + this.ESP_FLASH_DATA = 0x03; + this.ESP_FLASH_END = 0x04; + this.ESP_MEM_BEGIN = 0x05; + this.ESP_MEM_END = 0x06; + this.ESP_MEM_DATA = 0x07; + this.ESP_WRITE_REG = 0x09; + this.ESP_READ_REG = 0x0a; + this.ESP_SPI_ATTACH = 0x0d; + this.ESP_CHANGE_BAUDRATE = 0x0f; + this.ESP_FLASH_DEFL_BEGIN = 0x10; + this.ESP_FLASH_DEFL_DATA = 0x11; + this.ESP_FLASH_DEFL_END = 0x12; + this.ESP_SPI_FLASH_MD5 = 0x13; + // Only Stub supported commands + this.ESP_ERASE_FLASH = 0xd0; + this.ESP_ERASE_REGION = 0xd1; + this.ESP_READ_FLASH = 0xd2; + this.ESP_RUN_USER_CODE = 0xd3; + this.ESP_IMAGE_MAGIC = 0xe9; + this.ESP_CHECKSUM_MAGIC = 0xef; + // Response code(s) sent by ROM + this.ROM_INVALID_RECV_MSG = 0x05; // response if an invalid message is received + this.ERASE_REGION_TIMEOUT_PER_MB = 30000; + this.ERASE_WRITE_TIMEOUT_PER_MB = 40000; + this.MD5_TIMEOUT_PER_MB = 8000; + this.CHIP_ERASE_TIMEOUT = 120000; + this.FLASH_READ_TIMEOUT = 100000; + this.MAX_TIMEOUT = this.CHIP_ERASE_TIMEOUT * 2; + this.CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000; + this.DETECTED_FLASH_SIZES = { + 0x12: "256KB", + 0x13: "512KB", + 0x14: "1MB", + 0x15: "2MB", + 0x16: "4MB", + 0x17: "8MB", + 0x18: "16MB", + }; + this.DETECTED_FLASH_SIZES_NUM = { + 0x12: 256, + 0x13: 512, + 0x14: 1024, + 0x15: 2048, + 0x16: 4096, + 0x17: 8192, + 0x18: 16384, + }; + this.USB_JTAG_SERIAL_PID = 0x1001; + this.romBaudrate = 115200; + this.debugLogging = false; + /** + * Get the checksum for given unsigned 8-bit array + * @param {Uint8Array} data Unsigned 8-bit integer array + * @returns {number} - Array checksum + */ + this.checksum = function (data) { + let i; + let chk = 0xef; + for (i = 0; i < data.length; i++) { + chk ^= data[i]; + } + return chk; + }; + /** + * Scale timeouts which are size-specific. + * @param {number} secondsPerMb Seconds per megabytes as number + * @param {number} sizeBytes Size bytes number + * @returns {number} - Scaled timeout for specified size. + */ + this.timeoutPerMb = function (secondsPerMb, sizeBytes) { + const result = secondsPerMb * (sizeBytes / 1000000); + if (result < 3000) { + return 3000; + } + else { + return result; + } + }; + /** + * Get flash size bytes from flash size string. + * @param {string} flashSize Flash Size string + * @returns {number} Flash size bytes + */ + this.flashSizeBytes = function (flashSize) { + let flashSizeB = -1; + if (flashSize.indexOf("KB") !== -1) { + flashSizeB = parseInt(flashSize.slice(0, flashSize.indexOf("KB"))) * 1024; + } + else if (flashSize.indexOf("MB") !== -1) { + flashSizeB = parseInt(flashSize.slice(0, flashSize.indexOf("MB"))) * 1024 * 1024; + } + return flashSizeB; + }; + this.IS_STUB = false; + this.FLASH_WRITE_SIZE = 0x4000; + this.transport = options.transport; + this.baudrate = options.baudrate; + if (options.serialOptions) { + this.serialOptions = options.serialOptions; + } + if (options.romBaudrate) { + this.romBaudrate = options.romBaudrate; + } + if (options.terminal) { + this.terminal = options.terminal; + this.terminal.clean(); + } + if (typeof options.debugLogging !== "undefined") { + this.debugLogging = options.debugLogging; + } + if (options.port) { + this.transport = new Transport(options.port); + } + if (typeof options.enableTracing !== "undefined") { + this.transport.tracing = options.enableTracing; + } + this.info("esptool.js"); + this.info("Serial port " + this.transport.getInfo()); + } + _sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + /** + * Write to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ + write(str, withNewline = true) { + if (this.terminal) { + if (withNewline) { + this.terminal.writeLine(str); + } + else { + this.terminal.write(str); + } + } + else { + // eslint-disable-next-line no-console + console.log(str); + } + } + /** + * Write error message to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ + error(str, withNewline = true) { + this.write(`Error: ${str}`, withNewline); + } + /** + * Write information message to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ + info(str, withNewline = true) { + this.write(str, withNewline); + } + /** + * Write debug message to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ + debug(str, withNewline = true) { + if (this.debugLogging) { + this.write(`Debug: ${str}`, withNewline); + } + } + /** + * Convert short integer to byte array + * @param {number} i - Number to convert. + * @returns {Uint8Array} Byte array. + */ + _shortToBytearray(i) { + return new Uint8Array([i & 0xff, (i >> 8) & 0xff]); + } + /** + * Convert an integer to byte array + * @param {number} i - Number to convert. + * @returns {ROM} The chip ROM class related to given magic hex number. + */ + _intToByteArray(i) { + return new Uint8Array([i & 0xff, (i >> 8) & 0xff, (i >> 16) & 0xff, (i >> 24) & 0xff]); + } + /** + * Convert a byte array to short integer. + * @param {number} i - Number to convert. + * @param {number} j - Number to convert. + * @returns {number} Return a short integer number. + */ + _byteArrayToShort(i, j) { + return i | (j >> 8); + } + /** + * Convert a byte array to integer. + * @param {number} i - Number to convert. + * @param {number} j - Number to convert. + * @param {number} k - Number to convert. + * @param {number} l - Number to convert. + * @returns {number} Return a integer number. + */ + _byteArrayToInt(i, j, k, l) { + return i | (j << 8) | (k << 16) | (l << 24); + } + /** + * Append a buffer array after another buffer array + * @param {ArrayBuffer} buffer1 - First array buffer. + * @param {ArrayBuffer} buffer2 - magic hex number to select ROM. + * @returns {ArrayBufferLike} Return an array buffer. + */ + _appendBuffer(buffer1, buffer2) { + const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); + tmp.set(new Uint8Array(buffer1), 0); + tmp.set(new Uint8Array(buffer2), buffer1.byteLength); + return tmp.buffer; + } + /** + * Append a buffer array after another buffer array + * @param {Uint8Array} arr1 - First array buffer. + * @param {Uint8Array} arr2 - magic hex number to select ROM. + * @returns {Uint8Array} Return a 8 bit unsigned array. + */ + _appendArray(arr1, arr2) { + const c = new Uint8Array(arr1.length + arr2.length); + c.set(arr1, 0); + c.set(arr2, arr1.length); + return c; + } + /** + * Convert a unsigned 8 bit integer array to byte string. + * @param {Uint8Array} u8Array - magic hex number to select ROM. + * @returns {string} Return the equivalent string. + */ + ui8ToBstr(u8Array) { + let bStr = ""; + for (let i = 0; i < u8Array.length; i++) { + bStr += String.fromCharCode(u8Array[i]); + } + return bStr; + } + /** + * Convert a byte string to unsigned 8 bit integer array. + * @param {string} bStr - binary string input + * @returns {Uint8Array} Return a 8 bit unsigned integer array. + */ + bstrToUi8(bStr) { + const u8Array = new Uint8Array(bStr.length); + for (let i = 0; i < bStr.length; i++) { + u8Array[i] = bStr.charCodeAt(i); + } + return u8Array; + } + /** + * Flush the serial input by raw read with 200 ms timeout. + */ + async flushInput() { + try { + await this.transport.rawRead(200); + } + catch (e) { + this.error(e.message); + } + } + /** + * Use the device serial port read function with given timeout to create a valid packet. + * @param {number} op Operation number + * @param {number} timeout timeout number in milliseconds + * @returns {[number, Uint8Array]} valid response packet. + */ + async readPacket(op = null, timeout = 3000) { + // Check up-to next 100 packets for valid response packet + for (let i = 0; i < 100; i++) { + const p = await this.transport.read(timeout); + const resp = p[0]; + const opRet = p[1]; + const val = this._byteArrayToInt(p[4], p[5], p[6], p[7]); + const data = p.slice(8); + if (resp == 1) { + if (op == null || opRet == op) { + return [val, data]; + } + else if (data[0] != 0 && data[1] == this.ROM_INVALID_RECV_MSG) { + await this.flushInput(); + throw new ESPError("unsupported command error"); + } + } + } + throw new ESPError("invalid response"); + } + /** + * Write a serial command to the chip + * @param {number} op - Operation number + * @param {Uint8Array} data - Unsigned 8 bit array + * @param {number} chk - channel number + * @param {boolean} waitResponse - wait for response ? + * @param {number} timeout - timeout number in milliseconds + * @returns {Promise<[number, Uint8Array]>} Return a number and a 8 bit unsigned integer array. + */ + async command(op = null, data = new Uint8Array(0), chk = 0, waitResponse = true, timeout = 3000) { + if (op != null) { + if (this.transport.tracing) { + this.transport.trace(`command op:0x${op.toString(16).padStart(2, "0")} data len=${data.length} wait_response=${waitResponse ? 1 : 0} timeout=${(timeout / 1000).toFixed(3)} data=${this.transport.hexConvert(data)}`); + } + const pkt = new Uint8Array(8 + data.length); + pkt[0] = 0x00; + pkt[1] = op; + pkt[2] = this._shortToBytearray(data.length)[0]; + pkt[3] = this._shortToBytearray(data.length)[1]; + pkt[4] = this._intToByteArray(chk)[0]; + pkt[5] = this._intToByteArray(chk)[1]; + pkt[6] = this._intToByteArray(chk)[2]; + pkt[7] = this._intToByteArray(chk)[3]; + let i; + for (i = 0; i < data.length; i++) { + pkt[8 + i] = data[i]; + } + await this.transport.write(pkt); + } + if (!waitResponse) { + return [0, new Uint8Array(0)]; + } + return this.readPacket(op, timeout); + } + /** + * Read a register from chip. + * @param {number} addr - Register address number + * @param {number} timeout - Timeout in milliseconds (Default: 3000ms) + * @returns {number} - Command number value + */ + async readReg(addr, timeout = 3000) { + const pkt = this._intToByteArray(addr); + const val = await this.command(this.ESP_READ_REG, pkt, undefined, undefined, timeout); + return val[0]; + } + /** + * Write a number value to register address in chip. + * @param {number} addr - Register address number + * @param {number} value - Number value to write in register + * @param {number} mask - Hex number for mask + * @param {number} delayUs Delay number + * @param {number} delayAfterUs Delay after previous delay + */ + async writeReg(addr, value, mask = 0xffffffff, delayUs = 0, delayAfterUs = 0) { + let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(value)); + pkt = this._appendArray(pkt, this._intToByteArray(mask)); + pkt = this._appendArray(pkt, this._intToByteArray(delayUs)); + if (delayAfterUs > 0) { + pkt = this._appendArray(pkt, this._intToByteArray(this.chip.UART_DATE_REG_ADDR)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(delayAfterUs)); + } + await this.checkCommand("write target memory", this.ESP_WRITE_REG, pkt); + } + /** + * Sync chip by sending sync command. + * @returns {[number, Uint8Array]} Command result + */ + async sync() { + this.debug("Sync"); + const cmd = new Uint8Array(36); + let i; + cmd[0] = 0x07; + cmd[1] = 0x07; + cmd[2] = 0x12; + cmd[3] = 0x20; + for (i = 0; i < 32; i++) { + cmd[4 + i] = 0x55; + } + try { + const resp = await this.command(0x08, cmd, undefined, undefined, 100); + return resp; + } + catch (e) { + this.debug("Sync err " + e); + throw e; + } + } + /** + * Attempt to connect to the chip by sending a reset sequence and later a sync command. + * @param {string} mode - Reset mode to use + * @param {boolean} esp32r0Delay - Enable delay for ESP32 R0 + * @returns {string} - Returns 'success' or 'error' message. + */ + async _connectAttempt(mode = "default_reset", esp32r0Delay = false) { + this.debug("_connect_attempt " + mode + " " + esp32r0Delay); + if (mode !== "no_reset") { + if (this.transport.getPid() === this.USB_JTAG_SERIAL_PID) { + // Custom reset sequence, which is required when the device + // is connecting via its USB-JTAG-Serial peripheral + await usbJTAGSerialReset(this.transport); + } + else { + const strSequence = esp32r0Delay ? "D0|R1|W100|W2000|D1|R0|W50|D0" : "D0|R1|W100|D1|R0|W50|D0"; + await customReset(this.transport, strSequence); + } + } + let i = 0; + let keepReading = true; + while (keepReading) { + try { + const res = await this.transport.read(1000); + i += res.length; + } + catch (e) { + this.debug(e.message); + if (e instanceof Error) { + keepReading = false; + break; + } + } + await this._sleep(50); + } + this.transport.slipReaderEnabled = true; + i = 7; + while (i--) { + try { + const resp = await this.sync(); + this.debug(resp[0].toString()); + return "success"; + } + catch (error) { + if (error instanceof Error) { + if (esp32r0Delay) { + this.info("_", false); + } + else { + this.info(".", false); + } + } + } + await this._sleep(50); + } + return "error"; + } + /** + * Perform a connection to chip. + * @param {string} mode - Reset mode to use. Example: 'default_reset' | 'no_reset' + * @param {number} attempts - Number of connection attempts + * @param {boolean} detecting - Detect the connected chip + */ + async connect(mode = "default_reset", attempts = 7, detecting = false) { + let i; + let resp; + this.info("Connecting...", false); + await this.transport.connect(this.romBaudrate, this.serialOptions); + for (i = 0; i < attempts; i++) { + resp = await this._connectAttempt(mode, false); + if (resp === "success") { + break; + } + resp = await this._connectAttempt(mode, true); + if (resp === "success") { + break; + } + } + if (resp !== "success") { + throw new ESPError("Failed to connect with the device"); + } + this.info("\n\r", false); + if (!detecting) { + const chipMagicValue = (await this.readReg(0x40001000)) >>> 0; + this.debug("Chip Magic " + chipMagicValue.toString(16)); + const chip = await magic2Chip(chipMagicValue); + if (this.chip === null) { + throw new ESPError(`Unexpected CHIP magic value ${chipMagicValue}. Failed to autodetect chip type.`); + } + else { + this.chip = chip; + } + } + } + /** + * Connect and detect the existing chip. + * @param {string} mode Reset mode to use for connection. + */ + async detectChip(mode = "default_reset") { + await this.connect(mode); + this.info("Detecting chip type... ", false); + if (this.chip != null) { + this.info(this.chip.CHIP_NAME); + } + else { + this.info("unknown!"); + } + } + /** + * Execute the command and check the command response. + * @param {string} opDescription Command operation description. + * @param {number} op Command operation number + * @param {Uint8Array} data Command value + * @param {number} chk Checksum to use + * @param {number} timeout TImeout number in milliseconds (ms) + * @returns {number} Command result + */ + async checkCommand(opDescription = "", op = null, data = new Uint8Array(0), chk = 0, timeout = 3000) { + this.debug("check_command " + opDescription); + const resp = await this.command(op, data, chk, undefined, timeout); + if (resp[1].length > 4) { + return resp[1]; + } + else { + return resp[0]; + } + } + /** + * Start downloading an application image to RAM + * @param {number} size Image size number + * @param {number} blocks Number of data blocks + * @param {number} blocksize Size of each data block + * @param {number} offset Image offset number + */ + async memBegin(size, blocks, blocksize, offset) { + /* XXX: Add check to ensure that STUB is not getting overwritten */ + this.debug("mem_begin " + size + " " + blocks + " " + blocksize + " " + offset.toString(16)); + let pkt = this._appendArray(this._intToByteArray(size), this._intToByteArray(blocks)); + pkt = this._appendArray(pkt, this._intToByteArray(blocksize)); + pkt = this._appendArray(pkt, this._intToByteArray(offset)); + await this.checkCommand("enter RAM download mode", this.ESP_MEM_BEGIN, pkt); + } + /** + * Send a block of image to RAM + * @param {Uint8Array} buffer Unsigned 8-bit array + * @param {number} seq Sequence number + */ + async memBlock(buffer, seq) { + let pkt = this._appendArray(this._intToByteArray(buffer.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, buffer); + const checksum = this.checksum(buffer); + await this.checkCommand("write to target RAM", this.ESP_MEM_DATA, pkt, checksum); + } + /** + * Leave RAM download mode and run application + * @param {number} entrypoint - Entrypoint number + */ + async memFinish(entrypoint) { + const isEntry = entrypoint === 0 ? 1 : 0; + const pkt = this._appendArray(this._intToByteArray(isEntry), this._intToByteArray(entrypoint)); + await this.checkCommand("leave RAM download mode", this.ESP_MEM_END, pkt, undefined, 50); // XXX: handle non-stub with diff timeout + } + /** + * Configure SPI flash pins + * @param {number} hspiArg - Argument for SPI attachment + */ + async flashSpiAttach(hspiArg) { + const pkt = this._intToByteArray(hspiArg); + await this.checkCommand("configure SPI flash pins", this.ESP_SPI_ATTACH, pkt); + } + /** + * Start downloading to Flash (performs an erase) + * @param {number} size Size to erase + * @param {number} offset Offset to erase + * @returns {number} Number of blocks (of size self.FLASH_WRITE_SIZE) to write. + */ + async flashBegin(size, offset) { + const numBlocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); + const eraseSize = this.chip.getEraseSize(offset, size); + const d = new Date(); + const t1 = d.getTime(); + let timeout = 3000; + if (this.IS_STUB == false) { + timeout = this.timeoutPerMb(this.ERASE_REGION_TIMEOUT_PER_MB, size); + } + this.debug("flash begin " + eraseSize + " " + numBlocks + " " + this.FLASH_WRITE_SIZE + " " + offset + " " + size); + let pkt = this._appendArray(this._intToByteArray(eraseSize), this._intToByteArray(numBlocks)); + pkt = this._appendArray(pkt, this._intToByteArray(this.FLASH_WRITE_SIZE)); + pkt = this._appendArray(pkt, this._intToByteArray(offset)); + if (this.IS_STUB == false) { + pkt = this._appendArray(pkt, this._intToByteArray(0)); // XXX: Support encrypted + } + await this.checkCommand("enter Flash download mode", this.ESP_FLASH_BEGIN, pkt, undefined, timeout); + const t2 = d.getTime(); + if (size != 0 && this.IS_STUB == false) { + this.info("Took " + (t2 - t1) / 1000 + "." + ((t2 - t1) % 1000) + "s to erase flash block"); + } + return numBlocks; + } + /** + * Start downloading compressed data to Flash (performs an erase) + * @param {number} size Write size + * @param {number} compsize Compressed size + * @param {number} offset Offset for write + * @returns {number} Returns number of blocks (size self.FLASH_WRITE_SIZE) to write. + */ + async flashDeflBegin(size, compsize, offset) { + const numBlocks = Math.floor((compsize + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); + const eraseBlocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); + const d = new Date(); + const t1 = d.getTime(); + let writeSize, timeout; + if (this.IS_STUB) { + writeSize = size; + timeout = 3000; + } + else { + writeSize = eraseBlocks * this.FLASH_WRITE_SIZE; + timeout = this.timeoutPerMb(this.ERASE_REGION_TIMEOUT_PER_MB, writeSize); + } + this.info("Compressed " + size + " bytes to " + compsize + "..."); + let pkt = this._appendArray(this._intToByteArray(writeSize), this._intToByteArray(numBlocks)); + pkt = this._appendArray(pkt, this._intToByteArray(this.FLASH_WRITE_SIZE)); + pkt = this._appendArray(pkt, this._intToByteArray(offset)); + if ((this.chip.CHIP_NAME === "ESP32-S2" || + this.chip.CHIP_NAME === "ESP32-S3" || + this.chip.CHIP_NAME === "ESP32-C3" || + this.chip.CHIP_NAME === "ESP32-C2") && + this.IS_STUB === false) { + pkt = this._appendArray(pkt, this._intToByteArray(0)); + } + await this.checkCommand("enter compressed flash mode", this.ESP_FLASH_DEFL_BEGIN, pkt, undefined, timeout); + const t2 = d.getTime(); + if (size != 0 && this.IS_STUB === false) { + this.info("Took " + (t2 - t1) / 1000 + "." + ((t2 - t1) % 1000) + "s to erase flash block"); + } + return numBlocks; + } + /** + * Write block to flash, retry if fail + * @param {Uint8Array} data Unsigned 8-bit array data. + * @param {number} seq Sequence number + * @param {number} timeout Timeout in milliseconds (ms) + */ + async flashBlock(data, seq, timeout) { + let pkt = this._appendArray(this._intToByteArray(data.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, data); + const checksum = this.checksum(data); + await this.checkCommand("write to target Flash after seq " + seq, this.ESP_FLASH_DATA, pkt, checksum, timeout); + } + /** + * Write block to flash, send compressed, retry if fail + * @param {Uint8Array} data Unsigned int 8-bit array data to write + * @param {number} seq Sequence number + * @param {number} timeout Timeout in milliseconds (ms) + */ + async flashDeflBlock(data, seq, timeout) { + let pkt = this._appendArray(this._intToByteArray(data.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, data); + const checksum = this.checksum(data); + this.debug("flash_defl_block " + data[0].toString(16) + " " + data[1].toString(16)); + await this.checkCommand("write compressed data to flash after seq " + seq, this.ESP_FLASH_DEFL_DATA, pkt, checksum, timeout); + } + /** + * Leave flash mode and run/reboot + * @param {boolean} reboot Reboot after leaving flash mode ? + */ + async flashFinish(reboot = false) { + const val = reboot ? 0 : 1; + const pkt = this._intToByteArray(val); + await this.checkCommand("leave Flash mode", this.ESP_FLASH_END, pkt); + } + /** + * Leave compressed flash mode and run/reboot + * @param {boolean} reboot Reboot after leaving flash mode ? + */ + async flashDeflFinish(reboot = false) { + const val = reboot ? 0 : 1; + const pkt = this._intToByteArray(val); + await this.checkCommand("leave compressed flash mode", this.ESP_FLASH_DEFL_END, pkt); + } + /** + * 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 spiflashCommand is an actual command + * byte, sent over the wire. + * + * After writing command byte, writes 'data' to MOSI and then + * reads back 'readBits' of reply on MISO. Result is a number. + * @param {number} spiflashCommand Command to execute in SPI + * @param {Uint8Array} data Data to send + * @param {number} readBits Number of bits to read + * @returns {number} Register SPI_W0_REG value + */ + async runSpiflashCommand(spiflashCommand, data, readBits) { + // 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 ESP32* vs 8266 + const base = this.chip.SPI_REG_BASE; + const SPI_CMD_REG = base + 0x00; + const SPI_USR_REG = base + this.chip.SPI_USR_OFFS; + const SPI_USR1_REG = base + this.chip.SPI_USR1_OFFS; + const SPI_USR2_REG = base + this.chip.SPI_USR2_OFFS; + const SPI_W0_REG = base + this.chip.SPI_W0_OFFS; + let setDataLengths; + if (this.chip.SPI_MOSI_DLEN_OFFS != null) { + setDataLengths = async (mosiBits, misoBits) => { + const SPI_MOSI_DLEN_REG = base + this.chip.SPI_MOSI_DLEN_OFFS; + const SPI_MISO_DLEN_REG = base + this.chip.SPI_MISO_DLEN_OFFS; + if (mosiBits > 0) { + await this.writeReg(SPI_MOSI_DLEN_REG, mosiBits - 1); + } + if (misoBits > 0) { + await this.writeReg(SPI_MISO_DLEN_REG, misoBits - 1); + } + }; + } + else { + setDataLengths = async (mosiBits, misoBits) => { + const SPI_DATA_LEN_REG = SPI_USR1_REG; + 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 val = (misoMask << SPI_MISO_BITLEN_S) | (mosiMask << SPI_MOSI_BITLEN_S); + await this.writeReg(SPI_DATA_LEN_REG, val); + }; + } + const SPI_CMD_USR = 1 << 18; + const SPI_USR2_COMMAND_LEN_SHIFT = 28; + if (readBits > 32) { + throw new ESPError("Reading more than 32 bits back from a SPI flash operation is unsupported"); + } + if (data.length > 64) { + throw new ESPError("Writing more than 64 bytes of data with one SPI command is unsupported"); + } + const dataBits = data.length * 8; + const oldSpiUsr = await this.readReg(SPI_USR_REG); + const oldSpiUsr2 = await this.readReg(SPI_USR2_REG); + let flags = SPI_USR_COMMAND; + let i; + if (readBits > 0) { + flags |= SPI_USR_MISO; + } + if (dataBits > 0) { + flags |= SPI_USR_MOSI; + } + await setDataLengths(dataBits, readBits); + await this.writeReg(SPI_USR_REG, flags); + let val = (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand; + await this.writeReg(SPI_USR2_REG, val); + if (dataBits == 0) { + await this.writeReg(SPI_W0_REG, 0); + } + else { + if (data.length % 4 != 0) { + const padding = new Uint8Array(data.length % 4); + data = this._appendArray(data, padding); + } + let nextReg = SPI_W0_REG; + for (i = 0; i < data.length - 4; i += 4) { + val = this._byteArrayToInt(data[i], data[i + 1], data[i + 2], data[i + 3]); + await this.writeReg(nextReg, val); + nextReg += 4; + } + } + await this.writeReg(SPI_CMD_REG, SPI_CMD_USR); + for (i = 0; i < 10; i++) { + val = (await this.readReg(SPI_CMD_REG)) & SPI_CMD_USR; + if (val == 0) { + break; + } + } + if (i === 10) { + throw new ESPError("SPI command did not complete in time"); + } + const stat = await this.readReg(SPI_W0_REG); + await this.writeReg(SPI_USR_REG, oldSpiUsr); + await this.writeReg(SPI_USR2_REG, oldSpiUsr2); + return stat; + } + /** + * Read flash id by executing the SPIFLASH_RDID flash command. + * @returns {Promise} Register SPI_W0_REG value + */ + async readFlashId() { + const SPIFLASH_RDID = 0x9f; + const pkt = new Uint8Array(0); + return await this.runSpiflashCommand(SPIFLASH_RDID, pkt, 24); + } + /** + * Execute the erase flash command + * @returns {Promise} Erase flash command result + */ + async eraseFlash() { + this.info("Erasing flash (this may take a while)..."); + let d = new Date(); + const t1 = d.getTime(); + const ret = await this.checkCommand("erase flash", this.ESP_ERASE_FLASH, undefined, undefined, this.CHIP_ERASE_TIMEOUT); + d = new Date(); + const t2 = d.getTime(); + this.info("Chip erase completed successfully in " + (t2 - t1) / 1000 + "s"); + return ret; + } + /** + * Convert a number or unsigned 8-bit array to hex string + * @param {number | Uint8Array } buffer Data to convert to hex string. + * @returns {string} A hex string + */ + toHex(buffer) { + return Array.prototype.map.call(buffer, (x) => ("00" + x.toString(16)).slice(-2)).join(""); + } + /** + * Calculate the MD5 Checksum command + * @param {number} addr Address number + * @param {number} size Package size + * @returns {string} MD5 Checksum string + */ + async flashMd5sum(addr, size) { + const timeout = this.timeoutPerMb(this.MD5_TIMEOUT_PER_MB, size); + let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(size)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + let res = await this.checkCommand("calculate md5sum", this.ESP_SPI_FLASH_MD5, pkt, undefined, timeout); + if (res instanceof Uint8Array && res.length > 16) { + res = res.slice(0, 16); + } + const strmd5 = this.toHex(res); + return strmd5; + } + async readFlash(addr, size, onPacketReceived = null) { + let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(size)); + pkt = this._appendArray(pkt, this._intToByteArray(0x1000)); + pkt = this._appendArray(pkt, this._intToByteArray(1024)); + const res = await this.checkCommand("read flash", this.ESP_READ_FLASH, pkt); + if (res != 0) { + throw new ESPError("Failed to read memory: " + res); + } + let resp = new Uint8Array(0); + while (resp.length < size) { + const packet = await this.transport.read(this.FLASH_READ_TIMEOUT); + if (packet instanceof Uint8Array) { + if (packet.length > 0) { + resp = this._appendArray(resp, packet); + await this.transport.write(this._intToByteArray(resp.length)); + if (onPacketReceived) { + onPacketReceived(packet, resp.length, size); + } + } + } + else { + throw new ESPError("Failed to read memory: " + packet); + } + } + return resp; + } + /** + * Upload the flasher ROM bootloader (flasher stub) to the chip. + * @returns {ROM} The Chip ROM + */ + async runStub() { + this.info("Uploading stub..."); + let decoded = atob(this.chip.ROM_TEXT); + let chardata = decoded.split("").map(function (x) { + return x.charCodeAt(0); + }); + const text = new Uint8Array(chardata); + decoded = atob(this.chip.ROM_DATA); + chardata = decoded.split("").map(function (x) { + return x.charCodeAt(0); + }); + const data = new Uint8Array(chardata); + let blocks = Math.floor((text.length + this.ESP_RAM_BLOCK - 1) / this.ESP_RAM_BLOCK); + let i; + await this.memBegin(text.length, blocks, this.ESP_RAM_BLOCK, this.chip.TEXT_START); + for (i = 0; i < blocks; i++) { + const fromOffs = i * this.ESP_RAM_BLOCK; + const toOffs = fromOffs + this.ESP_RAM_BLOCK; + await this.memBlock(text.slice(fromOffs, toOffs), i); + } + blocks = Math.floor((data.length + this.ESP_RAM_BLOCK - 1) / this.ESP_RAM_BLOCK); + await this.memBegin(data.length, blocks, this.ESP_RAM_BLOCK, this.chip.DATA_START); + for (i = 0; i < blocks; i++) { + const fromOffs = i * this.ESP_RAM_BLOCK; + const toOffs = fromOffs + this.ESP_RAM_BLOCK; + await this.memBlock(data.slice(fromOffs, toOffs), i); + } + this.info("Running stub..."); + await this.memFinish(this.chip.ENTRY); + // Check up-to next 100 packets to see if stub is running + for (let i = 0; i < 100; i++) { + const res = await this.transport.read(1000, 6); + if (res[0] === 79 && res[1] === 72 && res[2] === 65 && res[3] === 73) { + this.info("Stub running..."); + this.IS_STUB = true; + this.FLASH_WRITE_SIZE = 0x4000; + return this.chip; + } + } + throw new ESPError("Failed to start stub. Unexpected response"); + } + /** + * Change the chip baudrate. + */ + async changeBaud() { + this.info("Changing baudrate to " + this.baudrate); + const secondArg = this.IS_STUB ? this.transport.baudrate : 0; + const pkt = this._appendArray(this._intToByteArray(this.baudrate), this._intToByteArray(secondArg)); + const resp = await this.command(this.ESP_CHANGE_BAUDRATE, pkt); + this.debug(resp[0].toString()); + this.info("Changed"); + await this.transport.disconnect(); + await this._sleep(50); + await this.transport.connect(this.baudrate, this.serialOptions); + /* original code seemed absolutely unreliable. use retries and less sleep */ + try { + let i = 64; + while (i--) { + try { + await this.sync(); + break; + } + catch (error) { + this.debug(error.message); + } + await this._sleep(10); + } + } + catch (e) { + this.debug(e.message); + } + } + /** + * Execute the main function of ESPLoader. + * @param {string} mode Reset mode to use + * @returns {string} chip ROM + */ + async main(mode = "default_reset") { + await this.detectChip(mode); + const chip = await this.chip.getChipDescription(this); + this.info("Chip is " + chip); + this.info("Features: " + (await this.chip.getChipFeatures(this))); + this.info("Crystal is " + (await this.chip.getCrystalFreq(this)) + "MHz"); + this.info("MAC: " + (await this.chip.readMac(this))); + await this.chip.readMac(this); + if (typeof this.chip.postConnect != "undefined") { + await this.chip.postConnect(this); + } + await this.runStub(); + if (this.romBaudrate !== this.baudrate) { + await this.changeBaud(); + } + return chip; + } + /** + * Parse a given flash size string to a number + * @param {string} flsz Flash size to request + * @returns {number} Flash size number + */ + parseFlashSizeArg(flsz) { + if (typeof this.chip.FLASH_SIZES[flsz] === "undefined") { + throw new ESPError("Flash size " + flsz + " is not supported by this chip type. Supported sizes: " + this.chip.FLASH_SIZES); + } + return this.chip.FLASH_SIZES[flsz]; + } + /** + * Update the image flash parameters with given arguments. + * @param {string} image binary image as string + * @param {number} address flash address number + * @param {string} flashSize Flash size string + * @param {string} flashMode Flash mode string + * @param {string} flashFreq Flash frequency string + * @returns {string} modified image string + */ + _updateImageFlashParams(image, address, flashSize, flashMode, flashFreq) { + this.debug("_update_image_flash_params " + flashSize + " " + flashMode + " " + flashFreq); + if (image.length < 8) { + return image; + } + if (address != this.chip.BOOTLOADER_FLASH_OFFSET) { + return image; + } + if (flashSize === "keep" && flashMode === "keep" && flashFreq === "keep") { + this.info("Not changing the image"); + return image; + } + const magic = parseInt(image[0]); + let aFlashMode = parseInt(image[2]); + const flashSizeFreq = parseInt(image[3]); + if (magic !== this.ESP_IMAGE_MAGIC) { + this.info("Warning: Image file at 0x" + + address.toString(16) + + " doesn't look like an image file, so not changing any flash settings."); + return image; + } + /* XXX: Yet to implement actual image verification */ + if (flashMode !== "keep") { + const flashModes = { qio: 0, qout: 1, dio: 2, dout: 3 }; + aFlashMode = flashModes[flashMode]; + } + let aFlashFreq = flashSizeFreq & 0x0f; + if (flashFreq !== "keep") { + const flashFreqs = { "40m": 0, "26m": 1, "20m": 2, "80m": 0xf }; + aFlashFreq = flashFreqs[flashFreq]; + } + let aFlashSize = flashSizeFreq & 0xf0; + if (flashSize !== "keep") { + aFlashSize = this.parseFlashSizeArg(flashSize); + } + const flashParams = (aFlashMode << 8) | (aFlashFreq + aFlashSize); + this.info("Flash params set to " + flashParams.toString(16)); + if (parseInt(image[2]) !== aFlashMode << 8) { + image = image.substring(0, 2) + (aFlashMode << 8).toString() + image.substring(2 + 1); + } + if (parseInt(image[3]) !== aFlashFreq + aFlashSize) { + image = image.substring(0, 3) + (aFlashFreq + aFlashSize).toString() + image.substring(3 + 1); + } + return image; + } + /** + * Write set of file images into given address based on given FlashOptions object. + * @param {FlashOptions} options FlashOptions to configure how and what to write into flash. + */ + async writeFlash(options) { + this.debug("EspLoader program"); + if (options.flashSize !== "keep") { + const flashEnd = this.flashSizeBytes(options.flashSize); + for (let i = 0; i < options.fileArray.length; i++) { + if (options.fileArray[i].data.length + options.fileArray[i].address > flashEnd) { + throw new ESPError(`File ${i + 1} doesn't fit in the available flash`); + } + } + } + if (this.IS_STUB === true && options.eraseAll === true) { + await this.eraseFlash(); + } + let image, address; + for (let i = 0; i < options.fileArray.length; i++) { + this.debug("Data Length " + options.fileArray[i].data.length); + image = options.fileArray[i].data; + const reminder = options.fileArray[i].data.length % 4; + if (reminder > 0) + image += "\xff\xff\xff\xff".substring(4 - reminder); + address = options.fileArray[i].address; + this.debug("Image Length " + image.length); + if (image.length === 0) { + this.debug("Warning: File is empty"); + continue; + } + image = this._updateImageFlashParams(image, address, options.flashSize, options.flashMode, options.flashFreq); + let calcmd5 = null; + if (options.calculateMD5Hash) { + calcmd5 = options.calculateMD5Hash(image); + this.debug("Image MD5 " + calcmd5); + } + const uncsize = image.length; + let blocks; + if (options.compress) { + const uncimage = this.bstrToUi8(image); + image = this.ui8ToBstr(deflate(uncimage, { level: 9 })); + blocks = await this.flashDeflBegin(uncsize, image.length, address); + } + else { + blocks = await this.flashBegin(uncsize, address); + } + let seq = 0; + let bytesSent = 0; + const totalBytes = image.length; + if (options.reportProgress) + options.reportProgress(i, 0, totalBytes); + let d = new Date(); + const t1 = d.getTime(); + let timeout = 5000; + // Create a decompressor to keep track of the size of uncompressed data + // to be written in each chunk. + const inflate = new Inflate({ chunkSize: 1 }); + let totalLenUncompressed = 0; + inflate.onData = function (chunk) { + totalLenUncompressed += chunk.byteLength; + }; + while (image.length > 0) { + this.debug("Write loop " + address + " " + seq + " " + blocks); + this.info("Writing at 0x" + + (address + totalLenUncompressed).toString(16) + + "... (" + + Math.floor((100 * (seq + 1)) / blocks) + + "%)"); + const block = this.bstrToUi8(image.slice(0, this.FLASH_WRITE_SIZE)); + if (options.compress) { + const lenUncompressedPrevious = totalLenUncompressed; + inflate.push(block, false); + const blockUncompressed = totalLenUncompressed - lenUncompressedPrevious; + let blockTimeout = 3000; + if (this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, blockUncompressed) > 3000) { + blockTimeout = this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, blockUncompressed); + } + if (this.IS_STUB === false) { + // ROM code writes block to flash before ACKing + timeout = blockTimeout; + } + await this.flashDeflBlock(block, seq, timeout); + if (this.IS_STUB) { + // Stub ACKs when block is received, then writes to flash while receiving the block after it + timeout = blockTimeout; + } + } + else { + throw new ESPError("Yet to handle Non Compressed writes"); + } + bytesSent += block.length; + image = image.slice(this.FLASH_WRITE_SIZE, image.length); + seq++; + if (options.reportProgress) + options.reportProgress(i, bytesSent, totalBytes); + } + if (this.IS_STUB) { + await this.readReg(this.CHIP_DETECT_MAGIC_REG_ADDR, timeout); + } + d = new Date(); + const t = d.getTime() - t1; + if (options.compress) { + this.info("Wrote " + + uncsize + + " bytes (" + + bytesSent + + " compressed) at 0x" + + address.toString(16) + + " in " + + t / 1000 + + " seconds."); + } + if (calcmd5) { + const res = await this.flashMd5sum(address, uncsize); + if (new String(res).valueOf() != new String(calcmd5).valueOf()) { + this.info("File md5: " + calcmd5); + this.info("Flash md5: " + res); + throw new ESPError("MD5 of file does not match data in flash!"); + } + else { + this.info("Hash of data verified."); + } + } + } + this.info("Leaving..."); + if (this.IS_STUB) { + await this.flashBegin(0, 0); + if (options.compress) { + await this.flashDeflFinish(); + } + else { + await this.flashFinish(); + } + } + } + /** + * Read SPI flash manufacturer and device id. + */ + async flashId() { + this.debug("flash_id"); + const flashid = await this.readFlashId(); + this.info("Manufacturer: " + (flashid & 0xff).toString(16)); + const flidLowbyte = (flashid >> 16) & 0xff; + this.info("Device: " + ((flashid >> 8) & 0xff).toString(16) + flidLowbyte.toString(16)); + this.info("Detected flash size: " + this.DETECTED_FLASH_SIZES[flidLowbyte]); + } + async getFlashSize() { + this.debug("flash_id"); + const flashid = await this.readFlashId(); + const flidLowbyte = (flashid >> 16) & 0xff; + return this.DETECTED_FLASH_SIZES_NUM[flidLowbyte]; + } + /** + * Perform a chip hard reset by setting RTS to LOW and then HIGH. + */ + async hardReset() { + await this.transport.setRTS(true); // EN->LOW + await this._sleep(100); + await this.transport.setRTS(false); + } + /** + * Soft reset the device chip. Soft reset with run user code is the closest. + */ + async softReset() { + if (!this.IS_STUB) { + // "run user code" is as close to a soft reset as we can do + await this.flashBegin(0, 0); + await this.flashFinish(false); + } + else if (this.chip.CHIP_NAME != "ESP8266") { + throw new ESPError("Soft resetting is currently only supported on ESP8266"); + } + else { + // running user code from stub loader requires some hacks + // in the stub loader + await this.command(this.ESP_RUN_USER_CODE, undefined, undefined, false); + } + } +} diff --git a/esp-flasher/lib_esptools-js/index.d.ts b/esp-flasher/lib_esptools-js/index.d.ts new file mode 100644 index 0000000..425d806 --- /dev/null +++ b/esp-flasher/lib_esptools-js/index.d.ts @@ -0,0 +1,4 @@ +export { IEspLoaderTerminal, ESPLoader, FlashOptions, LoaderOptions } from "./esploader"; +export { classicReset, customReset, hardReset, usbJTAGSerialReset, validateCustomResetStringSequence, } from "./reset"; +export { ROM } from "./targets/rom"; +export { Transport, SerialOptions } from "./webserial"; diff --git a/esp-flasher/lib_esptools-js/index.js b/esp-flasher/lib_esptools-js/index.js new file mode 100644 index 0000000..9e86673 --- /dev/null +++ b/esp-flasher/lib_esptools-js/index.js @@ -0,0 +1,4 @@ +export { ESPLoader } from "./esploader.js"; +export { classicReset, customReset, hardReset, usbJTAGSerialReset, validateCustomResetStringSequence, } from "./reset.js"; +export { ROM } from "./targets/rom.js"; +export { Transport } from "./webserial.js"; diff --git a/esp-flasher/lib_esptools-js/reset.d.ts b/esp-flasher/lib_esptools-js/reset.d.ts new file mode 100644 index 0000000..59a238b --- /dev/null +++ b/esp-flasher/lib_esptools-js/reset.d.ts @@ -0,0 +1,94 @@ +import { Transport } from "./webserial"; +/** + * Execute a classic set of commands that will reset the chip. + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * + * "D0|R1|W100|D1|R0|W50|D0" represents the classic reset strategy + * @param {Transport} transport Transport class to perform serial communication. + * @param {number} resetDelay Delay in milliseconds for reset. + */ +export declare function classicReset(transport: Transport, resetDelay?: number): Promise; +/** + * Execute a set of commands for USB JTAG serial reset. + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * @param {Transport} transport Transport class to perform serial communication. + */ +export declare function usbJTAGSerialReset(transport: Transport): Promise; +/** + * Execute a set of commands that will hard reset the chip. + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * @param {Transport} transport Transport class to perform serial communication. + * @param {boolean} usingUsbOtg is it using USB-OTG ? + */ +export declare function hardReset(transport: Transport, usingUsbOtg?: boolean): Promise; +/** + * Validate a sequence string based on the following format: + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * @param {string} seqStr Sequence string to validate + * @returns {boolean} Is the sequence string valid ? + */ +export declare function validateCustomResetStringSequence(seqStr: string): boolean; +/** + * Custom reset strategy defined with a string. + * + * The sequenceString input string consists of individual commands divided by "|". + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * + * "D0|R1|W100|D1|R0|W50|D0" represents the classic reset strategy + * @param {Transport} transport Transport class to perform serial communication. + * @param {string} sequenceString Custom string sequence for reset strategy + */ +export declare function customReset(transport: Transport, sequenceString: string): Promise; +declare const _default: { + classicReset: typeof classicReset; + customReset: typeof customReset; + hardReset: typeof hardReset; + usbJTAGSerialReset: typeof usbJTAGSerialReset; + validateCustomResetStringSequence: typeof validateCustomResetStringSequence; +}; +export default _default; diff --git a/esp-flasher/lib_esptools-js/reset.js b/esp-flasher/lib_esptools-js/reset.js new file mode 100644 index 0000000..590cb11 --- /dev/null +++ b/esp-flasher/lib_esptools-js/reset.js @@ -0,0 +1,174 @@ +const DEFAULT_RESET_DELAY = 50; +/** + * Sleep for ms milliseconds + * @param {number} ms Milliseconds to wait + * @returns {Promise} + */ +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +/** + * Execute a classic set of commands that will reset the chip. + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * + * "D0|R1|W100|D1|R0|W50|D0" represents the classic reset strategy + * @param {Transport} transport Transport class to perform serial communication. + * @param {number} resetDelay Delay in milliseconds for reset. + */ +export async function classicReset(transport, resetDelay = DEFAULT_RESET_DELAY) { + await transport.setDTR(false); + await transport.setRTS(true); + await sleep(100); + await transport.setDTR(true); + await transport.setRTS(false); + await sleep(resetDelay); + await transport.setDTR(false); +} +/** + * Execute a set of commands for USB JTAG serial reset. + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * @param {Transport} transport Transport class to perform serial communication. + */ +export async function usbJTAGSerialReset(transport) { + await transport.setRTS(false); + await transport.setDTR(false); + await sleep(100); + await transport.setDTR(true); + await transport.setRTS(false); + await sleep(100); + await transport.setRTS(true); + await transport.setDTR(false); + await transport.setRTS(true); + await sleep(100); + await transport.setRTS(false); + await transport.setDTR(false); +} +/** + * Execute a set of commands that will hard reset the chip. + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * @param {Transport} transport Transport class to perform serial communication. + * @param {boolean} usingUsbOtg is it using USB-OTG ? + */ +export async function hardReset(transport, usingUsbOtg = false) { + if (usingUsbOtg) { + await sleep(200); + await transport.setRTS(false); + await sleep(200); + } + else { + await sleep(100); + await transport.setRTS(false); + } +} +/** + * Validate a sequence string based on the following format: + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * @param {string} seqStr Sequence string to validate + * @returns {boolean} Is the sequence string valid ? + */ +export function validateCustomResetStringSequence(seqStr) { + const commands = ["D", "R", "W"]; + const commandsList = seqStr.split("|"); + for (const cmd of commandsList) { + const code = cmd[0]; + const arg = cmd.slice(1); + if (!commands.includes(code)) { + return false; // Invalid command code + } + if (code === "D" || code === "R") { + if (arg !== "0" && arg !== "1") { + return false; // Invalid argument for D and R commands + } + } + else if (code === "W") { + const delay = parseInt(arg); + if (isNaN(delay) || delay <= 0) { + return false; // Invalid argument for W command + } + } + } + return true; // All commands are valid +} +/** + * Custom reset strategy defined with a string. + * + * The sequenceString input string consists of individual commands divided by "|". + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * + * "D0|R1|W100|D1|R0|W50|D0" represents the classic reset strategy + * @param {Transport} transport Transport class to perform serial communication. + * @param {string} sequenceString Custom string sequence for reset strategy + */ +export async function customReset(transport, sequenceString) { + const resetDictionary = { + D: async (arg) => await transport.setDTR(arg), + R: async (arg) => await transport.setRTS(arg), + W: async (delay) => await sleep(delay), + }; + try { + const isValidSequence = validateCustomResetStringSequence(sequenceString); + if (!isValidSequence) { + return; + } + const cmds = sequenceString.split("|"); + for (const cmd of cmds) { + const cmdKey = cmd[0]; + const cmdVal = cmd.slice(1); + if (cmdKey === "W") { + await resetDictionary["W"](Number(cmdVal)); + } + else if (cmdKey === "D" || cmdKey === "R") { + await resetDictionary[cmdKey](cmdVal === "1"); + } + } + } + catch (error) { + throw new Error("Invalid custom reset sequence"); + } +} +export default { classicReset, customReset, hardReset, usbJTAGSerialReset, validateCustomResetStringSequence }; diff --git a/esp-flasher/lib_esptools-js/targets/esp32.d.ts b/esp-flasher/lib_esptools-js/targets/esp32.d.ts new file mode 100644 index 0000000..2e955e4 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32.d.ts @@ -0,0 +1,37 @@ +import { ESPLoader } from "../esploader"; +import { ROM } from "./rom"; +export declare class ESP32ROM extends ROM { + CHIP_NAME: string; + IMAGE_CHIP_ID: number; + EFUSE_RD_REG_BASE: number; + DR_REG_SYSCON_BASE: number; + UART_CLKDIV_REG: number; + UART_CLKDIV_MASK: number; + UART_DATE_REG_ADDR: number; + XTAL_CLK_DIVIDER: number; + FLASH_SIZES: { + [key: string]: number; + }; + FLASH_WRITE_SIZE: number; + BOOTLOADER_FLASH_OFFSET: number; + SPI_REG_BASE: number; + SPI_USR_OFFS: number; + SPI_USR1_OFFS: number; + SPI_USR2_OFFS: number; + SPI_W0_OFFS: number; + SPI_MOSI_DLEN_OFFS: number; + SPI_MISO_DLEN_OFFS: number; + TEXT_START: number; + ENTRY: number; + DATA_START: number; + ROM_DATA: string; + ROM_TEXT: string; + readEfuse(loader: ESPLoader, offset: number): Promise; + getPkgVersion(loader: ESPLoader): Promise; + getChipRevision(loader: ESPLoader): Promise; + getChipDescription(loader: ESPLoader): Promise; + getChipFeatures(loader: ESPLoader): Promise; + getCrystalFreq(loader: ESPLoader): Promise; + _d2h(d: number): string; + readMac(loader: ESPLoader): Promise; +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32.js b/esp-flasher/lib_esptools-js/targets/esp32.js new file mode 100644 index 0000000..58f0a5e --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32.js @@ -0,0 +1,191 @@ +import { ROM } from "./rom.js"; +import ESP32_STUB from "./stub_flasher/stub_flasher_32.json"; +export class ESP32ROM extends ROM { + constructor() { + super(...arguments); + this.CHIP_NAME = "ESP32"; + this.IMAGE_CHIP_ID = 0; + this.EFUSE_RD_REG_BASE = 0x3ff5a000; + this.DR_REG_SYSCON_BASE = 0x3ff66000; + this.UART_CLKDIV_REG = 0x3ff40014; + this.UART_CLKDIV_MASK = 0xfffff; + this.UART_DATE_REG_ADDR = 0x60000078; + this.XTAL_CLK_DIVIDER = 1; + this.FLASH_SIZES = { + "1MB": 0x00, + "2MB": 0x10, + "4MB": 0x20, + "8MB": 0x30, + "16MB": 0x40, + }; + this.FLASH_WRITE_SIZE = 0x400; + this.BOOTLOADER_FLASH_OFFSET = 0x1000; + this.SPI_REG_BASE = 0x3ff42000; + this.SPI_USR_OFFS = 0x1c; + this.SPI_USR1_OFFS = 0x20; + this.SPI_USR2_OFFS = 0x24; + this.SPI_W0_OFFS = 0x80; + this.SPI_MOSI_DLEN_OFFS = 0x28; + this.SPI_MISO_DLEN_OFFS = 0x2c; + this.TEXT_START = ESP32_STUB.text_start; + this.ENTRY = ESP32_STUB.entry; + this.DATA_START = ESP32_STUB.data_start; + this.ROM_DATA = ESP32_STUB.data; + this.ROM_TEXT = ESP32_STUB.text; + } + async readEfuse(loader, offset) { + const addr = this.EFUSE_RD_REG_BASE + 4 * offset; + loader.debug("Read efuse " + addr); + return await loader.readReg(addr); + } + async getPkgVersion(loader) { + const word3 = await this.readEfuse(loader, 3); + let pkgVersion = (word3 >> 9) & 0x07; + pkgVersion += ((word3 >> 2) & 0x1) << 3; + return pkgVersion; + } + async getChipRevision(loader) { + const word3 = await this.readEfuse(loader, 3); + const word5 = await this.readEfuse(loader, 5); + const apbCtlDate = await loader.readReg(this.DR_REG_SYSCON_BASE + 0x7c); + const revBit0 = (word3 >> 15) & 0x1; + const revBit1 = (word5 >> 20) & 0x1; + const revBit2 = (apbCtlDate >> 31) & 0x1; + if (revBit0 != 0) { + if (revBit1 != 0) { + if (revBit2 != 0) { + return 3; + } + else { + return 2; + } + } + else { + return 1; + } + } + return 0; + } + async getChipDescription(loader) { + const chipDesc = [ + "ESP32-D0WDQ6", + "ESP32-D0WD", + "ESP32-D2WD", + "", + "ESP32-U4WDH", + "ESP32-PICO-D4", + "ESP32-PICO-V3-02", + ]; + let chipName = ""; + const pkgVersion = await this.getPkgVersion(loader); + const chipRevision = await this.getChipRevision(loader); + const rev3 = chipRevision == 3; + const single_core = (await this.readEfuse(loader, 3)) & (1 << 0); + if (single_core != 0) { + chipDesc[0] = "ESP32-S0WDQ6"; + chipDesc[1] = "ESP32-S0WD"; + } + if (rev3) { + chipDesc[5] = "ESP32-PICO-V3"; + } + if (pkgVersion >= 0 && pkgVersion <= 6) { + chipName = chipDesc[pkgVersion]; + } + else { + chipName = "Unknown ESP32"; + } + if (rev3 && (pkgVersion === 0 || pkgVersion === 1)) { + chipName += "-V3"; + } + return chipName + " (revision " + chipRevision + ")"; + } + async getChipFeatures(loader) { + const features = ["Wi-Fi"]; + const word3 = await this.readEfuse(loader, 3); + const chipVerDisBt = word3 & (1 << 1); + if (chipVerDisBt === 0) { + features.push(" BT"); + } + const chipVerDisAppCpu = word3 & (1 << 0); + if (chipVerDisAppCpu !== 0) { + features.push(" Single Core"); + } + else { + features.push(" Dual Core"); + } + const chipCpuFreqRated = word3 & (1 << 13); + if (chipCpuFreqRated !== 0) { + const chipCpuFreqLow = word3 & (1 << 12); + if (chipCpuFreqLow !== 0) { + features.push(" 160MHz"); + } + else { + features.push(" 240MHz"); + } + } + const pkgVersion = await this.getPkgVersion(loader); + if ([2, 4, 5, 6].indexOf(pkgVersion) !== -1) { + features.push(" Embedded Flash"); + } + if (pkgVersion === 6) { + features.push(" Embedded PSRAM"); + } + const word4 = await this.readEfuse(loader, 4); + const adcVref = (word4 >> 8) & 0x1f; + if (adcVref !== 0) { + features.push(" VRef calibration in efuse"); + } + const blk3PartRes = (word3 >> 14) & 0x1; + if (blk3PartRes !== 0) { + features.push(" BLK3 partially reserved"); + } + const word6 = await this.readEfuse(loader, 6); + const codingScheme = word6 & 0x3; + const codingSchemeArr = ["None", "3/4", "Repeat (UNSUPPORTED)", "Invalid"]; + features.push(" Coding Scheme " + codingSchemeArr[codingScheme]); + return features; + } + async getCrystalFreq(loader) { + const uartDiv = (await loader.readReg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; + const etsXtal = (loader.transport.baudrate * uartDiv) / 1000000 / this.XTAL_CLK_DIVIDER; + let normXtal; + if (etsXtal > 33) { + normXtal = 40; + } + else { + normXtal = 26; + } + if (Math.abs(normXtal - etsXtal) > 1) { + loader.info("WARNING: Unsupported crystal in use"); + } + return normXtal; + } + _d2h(d) { + const h = (+d).toString(16); + return h.length === 1 ? "0" + h : h; + } + async readMac(loader) { + let mac0 = await this.readEfuse(loader, 1); + mac0 = mac0 >>> 0; + let mac1 = await this.readEfuse(loader, 2); + mac1 = mac1 >>> 0; + const mac = new Uint8Array(6); + mac[0] = (mac1 >> 8) & 0xff; + mac[1] = mac1 & 0xff; + mac[2] = (mac0 >> 24) & 0xff; + mac[3] = (mac0 >> 16) & 0xff; + mac[4] = (mac0 >> 8) & 0xff; + mac[5] = mac0 & 0xff; + return (this._d2h(mac[0]) + + ":" + + this._d2h(mac[1]) + + ":" + + this._d2h(mac[2]) + + ":" + + this._d2h(mac[3]) + + ":" + + this._d2h(mac[4]) + + ":" + + this._d2h(mac[5])); + } +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32c2.d.ts b/esp-flasher/lib_esptools-js/targets/esp32c2.d.ts new file mode 100644 index 0000000..16b7e90 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32c2.d.ts @@ -0,0 +1,42 @@ +import { ESPLoader } from "../esploader"; +import { ESP32C3ROM } from "./esp32c3"; +export declare class ESP32C2ROM extends ESP32C3ROM { + CHIP_NAME: string; + IMAGE_CHIP_ID: number; + EFUSE_BASE: number; + MAC_EFUSE_REG: number; + UART_CLKDIV_REG: number; + UART_CLKDIV_MASK: number; + UART_DATE_REG_ADDR: number; + XTAL_CLK_DIVIDER: number; + FLASH_WRITE_SIZE: number; + BOOTLOADER_FLASH_OFFSET: number; + FLASH_SIZES: { + "1MB": number; + "2MB": number; + "4MB": number; + "8MB": number; + "16MB": number; + }; + SPI_REG_BASE: number; + SPI_USR_OFFS: number; + SPI_USR1_OFFS: number; + SPI_USR2_OFFS: number; + SPI_MOSI_DLEN_OFFS: number; + SPI_MISO_DLEN_OFFS: number; + SPI_W0_OFFS: number; + TEXT_START: number; + ENTRY: number; + DATA_START: number; + ROM_DATA: string; + ROM_TEXT: string; + getPkgVersion(loader: ESPLoader): Promise; + getChipRevision(loader: ESPLoader): Promise; + getChipDescription(loader: ESPLoader): Promise; + getChipFeatures(loader: ESPLoader): Promise; + getCrystalFreq(loader: ESPLoader): Promise; + changeBaudRate(loader: ESPLoader): Promise; + _d2h(d: number): string; + readMac(loader: ESPLoader): Promise; + getEraseSize(offset: number, size: number): number; +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32c2.js b/esp-flasher/lib_esptools-js/targets/esp32c2.js new file mode 100644 index 0000000..5a026e8 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32c2.js @@ -0,0 +1,120 @@ +import { ESP32C3ROM } from "./esp32c3.js"; +import ESP32C2_STUB from "./stub_flasher/stub_flasher_32c2.json"; +export class ESP32C2ROM extends ESP32C3ROM { + constructor() { + super(...arguments); + this.CHIP_NAME = "ESP32-C2"; + this.IMAGE_CHIP_ID = 12; + this.EFUSE_BASE = 0x60008800; + this.MAC_EFUSE_REG = this.EFUSE_BASE + 0x040; + this.UART_CLKDIV_REG = 0x60000014; + this.UART_CLKDIV_MASK = 0xfffff; + this.UART_DATE_REG_ADDR = 0x6000007c; + this.XTAL_CLK_DIVIDER = 1; + this.FLASH_WRITE_SIZE = 0x400; + this.BOOTLOADER_FLASH_OFFSET = 0; + this.FLASH_SIZES = { + "1MB": 0x00, + "2MB": 0x10, + "4MB": 0x20, + "8MB": 0x30, + "16MB": 0x40, + }; + this.SPI_REG_BASE = 0x60002000; + this.SPI_USR_OFFS = 0x18; + this.SPI_USR1_OFFS = 0x1c; + this.SPI_USR2_OFFS = 0x20; + this.SPI_MOSI_DLEN_OFFS = 0x24; + this.SPI_MISO_DLEN_OFFS = 0x28; + this.SPI_W0_OFFS = 0x58; + this.TEXT_START = ESP32C2_STUB.text_start; + this.ENTRY = ESP32C2_STUB.entry; + this.DATA_START = ESP32C2_STUB.data_start; + this.ROM_DATA = ESP32C2_STUB.data; + this.ROM_TEXT = ESP32C2_STUB.text; + } + async getPkgVersion(loader) { + const numWord = 1; + const block1Addr = this.EFUSE_BASE + 0x040; + const addr = block1Addr + 4 * numWord; + const word3 = await loader.readReg(addr); + const pkgVersion = (word3 >> 22) & 0x07; + return pkgVersion; + } + async getChipRevision(loader) { + const block1Addr = this.EFUSE_BASE + 0x040; + const numWord = 1; + const pos = 20; + const addr = block1Addr + 4 * numWord; + const ret = ((await loader.readReg(addr)) & (0x03 << pos)) >> pos; + return ret; + } + async getChipDescription(loader) { + let desc; + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer === 0 || pkgVer === 1) { + desc = "ESP32-C2"; + } + else { + desc = "unknown ESP32-C2"; + } + const chip_rev = await this.getChipRevision(loader); + desc += " (revision " + chip_rev + ")"; + return desc; + } + async getChipFeatures(loader) { + return ["Wi-Fi", "BLE"]; + } + async getCrystalFreq(loader) { + const uartDiv = (await loader.readReg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; + const etsXtal = (loader.transport.baudrate * uartDiv) / 1000000 / this.XTAL_CLK_DIVIDER; + let normXtal; + if (etsXtal > 33) { + normXtal = 40; + } + else { + normXtal = 26; + } + if (Math.abs(normXtal - etsXtal) > 1) { + loader.info("WARNING: Unsupported crystal in use"); + } + return normXtal; + } + async changeBaudRate(loader) { + const rom_with_26M_XTAL = await this.getCrystalFreq(loader); + if (rom_with_26M_XTAL === 26) { + loader.changeBaud(); + } + } + _d2h(d) { + const h = (+d).toString(16); + return h.length === 1 ? "0" + h : h; + } + async readMac(loader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); + mac0 = mac0 >>> 0; + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); + mac1 = (mac1 >>> 0) & 0x0000ffff; + const mac = new Uint8Array(6); + mac[0] = (mac1 >> 8) & 0xff; + mac[1] = mac1 & 0xff; + mac[2] = (mac0 >> 24) & 0xff; + mac[3] = (mac0 >> 16) & 0xff; + mac[4] = (mac0 >> 8) & 0xff; + mac[5] = mac0 & 0xff; + return (this._d2h(mac[0]) + + ":" + + this._d2h(mac[1]) + + ":" + + this._d2h(mac[2]) + + ":" + + this._d2h(mac[3]) + + ":" + + this._d2h(mac[4]) + + ":" + + this._d2h(mac[5])); + } + getEraseSize(offset, size) { + return size; + } +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32c3.d.ts b/esp-flasher/lib_esptools-js/targets/esp32c3.d.ts new file mode 100644 index 0000000..a49da0a --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32c3.d.ts @@ -0,0 +1,40 @@ +import { ESPLoader } from "../esploader"; +import { ROM } from "./rom"; +export declare class ESP32C3ROM extends ROM { + CHIP_NAME: string; + IMAGE_CHIP_ID: number; + EFUSE_BASE: number; + MAC_EFUSE_REG: number; + UART_CLKDIV_REG: number; + UART_CLKDIV_MASK: number; + UART_DATE_REG_ADDR: number; + FLASH_WRITE_SIZE: number; + BOOTLOADER_FLASH_OFFSET: number; + FLASH_SIZES: { + "1MB": number; + "2MB": number; + "4MB": number; + "8MB": number; + "16MB": number; + }; + SPI_REG_BASE: number; + SPI_USR_OFFS: number; + SPI_USR1_OFFS: number; + SPI_USR2_OFFS: number; + SPI_MOSI_DLEN_OFFS: number; + SPI_MISO_DLEN_OFFS: number; + SPI_W0_OFFS: number; + TEXT_START: number; + ENTRY: number; + DATA_START: number; + ROM_DATA: string; + ROM_TEXT: string; + getPkgVersion(loader: ESPLoader): Promise; + getChipRevision(loader: ESPLoader): Promise; + getChipDescription(loader: ESPLoader): Promise; + getChipFeatures(loader: ESPLoader): Promise; + getCrystalFreq(loader: ESPLoader): Promise; + _d2h(d: number): string; + readMac(loader: ESPLoader): Promise; + getEraseSize(offset: number, size: number): number; +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32c3.js b/esp-flasher/lib_esptools-js/targets/esp32c3.js new file mode 100644 index 0000000..5c941ad --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32c3.js @@ -0,0 +1,101 @@ +import { ROM } from "./rom.js"; +import ESP32C3_STUB from "./stub_flasher/stub_flasher_32c3.json"; +export class ESP32C3ROM extends ROM { + constructor() { + super(...arguments); + this.CHIP_NAME = "ESP32-C3"; + this.IMAGE_CHIP_ID = 5; + this.EFUSE_BASE = 0x60008800; + this.MAC_EFUSE_REG = this.EFUSE_BASE + 0x044; + this.UART_CLKDIV_REG = 0x3ff40014; + this.UART_CLKDIV_MASK = 0xfffff; + this.UART_DATE_REG_ADDR = 0x6000007c; + this.FLASH_WRITE_SIZE = 0x400; + this.BOOTLOADER_FLASH_OFFSET = 0; + this.FLASH_SIZES = { + "1MB": 0x00, + "2MB": 0x10, + "4MB": 0x20, + "8MB": 0x30, + "16MB": 0x40, + }; + this.SPI_REG_BASE = 0x60002000; + this.SPI_USR_OFFS = 0x18; + this.SPI_USR1_OFFS = 0x1c; + this.SPI_USR2_OFFS = 0x20; + this.SPI_MOSI_DLEN_OFFS = 0x24; + this.SPI_MISO_DLEN_OFFS = 0x28; + this.SPI_W0_OFFS = 0x58; + this.TEXT_START = ESP32C3_STUB.text_start; + this.ENTRY = ESP32C3_STUB.entry; + this.DATA_START = ESP32C3_STUB.data_start; + this.ROM_DATA = ESP32C3_STUB.data; + this.ROM_TEXT = ESP32C3_STUB.text; + } + async getPkgVersion(loader) { + const numWord = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const addr = block1Addr + 4 * numWord; + const word3 = await loader.readReg(addr); + const pkgVersion = (word3 >> 21) & 0x07; + return pkgVersion; + } + async getChipRevision(loader) { + const block1Addr = this.EFUSE_BASE + 0x044; + const numWord = 3; + const pos = 18; + const addr = block1Addr + 4 * numWord; + const ret = ((await loader.readReg(addr)) & (0x7 << pos)) >> pos; + return ret; + } + async getChipDescription(loader) { + let desc; + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer === 0) { + desc = "ESP32-C3"; + } + else { + desc = "unknown ESP32-C3"; + } + const chip_rev = await this.getChipRevision(loader); + desc += " (revision " + chip_rev + ")"; + return desc; + } + async getChipFeatures(loader) { + return ["Wi-Fi"]; + } + async getCrystalFreq(loader) { + return 40; + } + _d2h(d) { + const h = (+d).toString(16); + return h.length === 1 ? "0" + h : h; + } + async readMac(loader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); + mac0 = mac0 >>> 0; + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); + mac1 = (mac1 >>> 0) & 0x0000ffff; + const mac = new Uint8Array(6); + mac[0] = (mac1 >> 8) & 0xff; + mac[1] = mac1 & 0xff; + mac[2] = (mac0 >> 24) & 0xff; + mac[3] = (mac0 >> 16) & 0xff; + mac[4] = (mac0 >> 8) & 0xff; + mac[5] = mac0 & 0xff; + return (this._d2h(mac[0]) + + ":" + + this._d2h(mac[1]) + + ":" + + this._d2h(mac[2]) + + ":" + + this._d2h(mac[3]) + + ":" + + this._d2h(mac[4]) + + ":" + + this._d2h(mac[5])); + } + getEraseSize(offset, size) { + return size; + } +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32c6.d.ts b/esp-flasher/lib_esptools-js/targets/esp32c6.d.ts new file mode 100644 index 0000000..a31294c --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32c6.d.ts @@ -0,0 +1,40 @@ +import { ESPLoader } from "../esploader"; +import { ROM } from "./rom"; +export declare class ESP32C6ROM extends ROM { + CHIP_NAME: string; + IMAGE_CHIP_ID: number; + EFUSE_BASE: number; + MAC_EFUSE_REG: number; + UART_CLKDIV_REG: number; + UART_CLKDIV_MASK: number; + UART_DATE_REG_ADDR: number; + FLASH_WRITE_SIZE: number; + BOOTLOADER_FLASH_OFFSET: number; + FLASH_SIZES: { + "1MB": number; + "2MB": number; + "4MB": number; + "8MB": number; + "16MB": number; + }; + SPI_REG_BASE: number; + SPI_USR_OFFS: number; + SPI_USR1_OFFS: number; + SPI_USR2_OFFS: number; + SPI_MOSI_DLEN_OFFS: number; + SPI_MISO_DLEN_OFFS: number; + SPI_W0_OFFS: number; + TEXT_START: number; + ENTRY: number; + DATA_START: number; + ROM_DATA: string; + ROM_TEXT: string; + getPkgVersion(loader: ESPLoader): Promise; + getChipRevision(loader: ESPLoader): Promise; + getChipDescription(loader: ESPLoader): Promise; + getChipFeatures(loader: ESPLoader): Promise; + getCrystalFreq(loader: ESPLoader): Promise; + _d2h(d: number): string; + readMac(loader: ESPLoader): Promise; + getEraseSize(offset: number, size: number): number; +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32c6.js b/esp-flasher/lib_esptools-js/targets/esp32c6.js new file mode 100644 index 0000000..253efca --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32c6.js @@ -0,0 +1,101 @@ +import { ROM } from "./rom.js"; +import ESP32C6_STUB from "./stub_flasher/stub_flasher_32c6.json"; +export class ESP32C6ROM extends ROM { + constructor() { + super(...arguments); + this.CHIP_NAME = "ESP32-C6"; + this.IMAGE_CHIP_ID = 13; + this.EFUSE_BASE = 0x600b0800; + this.MAC_EFUSE_REG = this.EFUSE_BASE + 0x044; + this.UART_CLKDIV_REG = 0x3ff40014; + this.UART_CLKDIV_MASK = 0xfffff; + this.UART_DATE_REG_ADDR = 0x6000007c; + this.FLASH_WRITE_SIZE = 0x400; + this.BOOTLOADER_FLASH_OFFSET = 0; + this.FLASH_SIZES = { + "1MB": 0x00, + "2MB": 0x10, + "4MB": 0x20, + "8MB": 0x30, + "16MB": 0x40, + }; + this.SPI_REG_BASE = 0x60002000; + this.SPI_USR_OFFS = 0x18; + this.SPI_USR1_OFFS = 0x1c; + this.SPI_USR2_OFFS = 0x20; + this.SPI_MOSI_DLEN_OFFS = 0x24; + this.SPI_MISO_DLEN_OFFS = 0x28; + this.SPI_W0_OFFS = 0x58; + this.TEXT_START = ESP32C6_STUB.text_start; + this.ENTRY = ESP32C6_STUB.entry; + this.DATA_START = ESP32C6_STUB.data_start; + this.ROM_DATA = ESP32C6_STUB.data; + this.ROM_TEXT = ESP32C6_STUB.text; + } + async getPkgVersion(loader) { + const numWord = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const addr = block1Addr + 4 * numWord; + const word3 = await loader.readReg(addr); + const pkgVersion = (word3 >> 21) & 0x07; + return pkgVersion; + } + async getChipRevision(loader) { + const block1Addr = this.EFUSE_BASE + 0x044; + const numWord = 3; + const pos = 18; + const addr = block1Addr + 4 * numWord; + const ret = ((await loader.readReg(addr)) & (0x7 << pos)) >> pos; + return ret; + } + async getChipDescription(loader) { + let desc; + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer === 0) { + desc = "ESP32-C6"; + } + else { + desc = "unknown ESP32-C6"; + } + const chipRev = await this.getChipRevision(loader); + desc += " (revision " + chipRev + ")"; + return desc; + } + async getChipFeatures(loader) { + return ["Wi-Fi"]; + } + async getCrystalFreq(loader) { + return 40; + } + _d2h(d) { + const h = (+d).toString(16); + return h.length === 1 ? "0" + h : h; + } + async readMac(loader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); + mac0 = mac0 >>> 0; + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); + mac1 = (mac1 >>> 0) & 0x0000ffff; + const mac = new Uint8Array(6); + mac[0] = (mac1 >> 8) & 0xff; + mac[1] = mac1 & 0xff; + mac[2] = (mac0 >> 24) & 0xff; + mac[3] = (mac0 >> 16) & 0xff; + mac[4] = (mac0 >> 8) & 0xff; + mac[5] = mac0 & 0xff; + return (this._d2h(mac[0]) + + ":" + + this._d2h(mac[1]) + + ":" + + this._d2h(mac[2]) + + ":" + + this._d2h(mac[3]) + + ":" + + this._d2h(mac[4]) + + ":" + + this._d2h(mac[5])); + } + getEraseSize(offset, size) { + return size; + } +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32h2.d.ts b/esp-flasher/lib_esptools-js/targets/esp32h2.d.ts new file mode 100644 index 0000000..dd0b753 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32h2.d.ts @@ -0,0 +1,42 @@ +import { ESPLoader } from "../esploader"; +import { ROM } from "./rom"; +export declare class ESP32H2ROM extends ROM { + CHIP_NAME: string; + IMAGE_CHIP_ID: number; + EFUSE_BASE: number; + MAC_EFUSE_REG: number; + UART_CLKDIV_REG: number; + UART_CLKDIV_MASK: number; + UART_DATE_REG_ADDR: number; + FLASH_WRITE_SIZE: number; + BOOTLOADER_FLASH_OFFSET: number; + FLASH_SIZES: { + "1MB": number; + "2MB": number; + "4MB": number; + "8MB": number; + "16MB": number; + }; + SPI_REG_BASE: number; + SPI_USR_OFFS: number; + SPI_USR1_OFFS: number; + SPI_USR2_OFFS: number; + SPI_MOSI_DLEN_OFFS: number; + SPI_MISO_DLEN_OFFS: number; + SPI_W0_OFFS: number; + USB_RAM_BLOCK: number; + UARTDEV_BUF_NO_USB: number; + UARTDEV_BUF_NO: number; + TEXT_START: number; + ENTRY: number; + DATA_START: number; + ROM_DATA: string; + ROM_TEXT: string; + getChipDescription(loader: ESPLoader): Promise; + getChipFeatures(loader: ESPLoader): Promise; + getCrystalFreq(loader: ESPLoader): Promise; + _d2h(d: number): string; + postConnect(loader: ESPLoader): Promise; + readMac(loader: ESPLoader): Promise; + getEraseSize(offset: number, size: number): number; +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32h2.js b/esp-flasher/lib_esptools-js/targets/esp32h2.js new file mode 100644 index 0000000..8132b61 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32h2.js @@ -0,0 +1,86 @@ +import { ROM } from "./rom.js"; +import ESP32H2_STUB from "./stub_flasher/stub_flasher_32h2.json"; +export class ESP32H2ROM extends ROM { + constructor() { + super(...arguments); + this.CHIP_NAME = "ESP32-H2"; + this.IMAGE_CHIP_ID = 16; + this.EFUSE_BASE = 0x60008800; + this.MAC_EFUSE_REG = this.EFUSE_BASE + 0x044; + this.UART_CLKDIV_REG = 0x3ff40014; + this.UART_CLKDIV_MASK = 0xfffff; + this.UART_DATE_REG_ADDR = 0x6000007c; + this.FLASH_WRITE_SIZE = 0x400; + this.BOOTLOADER_FLASH_OFFSET = 0x0; + this.FLASH_SIZES = { + "1MB": 0x00, + "2MB": 0x10, + "4MB": 0x20, + "8MB": 0x30, + "16MB": 0x40, + }; + this.SPI_REG_BASE = 0x60002000; + this.SPI_USR_OFFS = 0x18; + this.SPI_USR1_OFFS = 0x1c; + this.SPI_USR2_OFFS = 0x20; + this.SPI_MOSI_DLEN_OFFS = 0x24; + this.SPI_MISO_DLEN_OFFS = 0x28; + this.SPI_W0_OFFS = 0x58; + this.USB_RAM_BLOCK = 0x800; + this.UARTDEV_BUF_NO_USB = 3; + this.UARTDEV_BUF_NO = 0x3fcef14c; + this.TEXT_START = ESP32H2_STUB.text_start; + this.ENTRY = ESP32H2_STUB.entry; + this.DATA_START = ESP32H2_STUB.data_start; + this.ROM_DATA = ESP32H2_STUB.data; + this.ROM_TEXT = ESP32H2_STUB.text; + } + async getChipDescription(loader) { + return this.CHIP_NAME; + } + async getChipFeatures(loader) { + return ["BLE", "IEEE802.15.4"]; + } + async getCrystalFreq(loader) { + // ESP32H2 XTAL is fixed to 32MHz + return 32; + } + _d2h(d) { + const h = (+d).toString(16); + return h.length === 1 ? "0" + h : h; + } + async postConnect(loader) { + const bufNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; + loader.debug("In _post_connect " + bufNo); + if (bufNo == this.UARTDEV_BUF_NO_USB) { + loader.ESP_RAM_BLOCK = this.USB_RAM_BLOCK; + } + } + async readMac(loader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); + mac0 = mac0 >>> 0; + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); + mac1 = (mac1 >>> 0) & 0x0000ffff; + const mac = new Uint8Array(6); + mac[0] = (mac1 >> 8) & 0xff; + mac[1] = mac1 & 0xff; + mac[2] = (mac0 >> 24) & 0xff; + mac[3] = (mac0 >> 16) & 0xff; + mac[4] = (mac0 >> 8) & 0xff; + mac[5] = mac0 & 0xff; + return (this._d2h(mac[0]) + + ":" + + this._d2h(mac[1]) + + ":" + + this._d2h(mac[2]) + + ":" + + this._d2h(mac[3]) + + ":" + + this._d2h(mac[4]) + + ":" + + this._d2h(mac[5])); + } + getEraseSize(offset, size) { + return size; + } +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32s2.d.ts b/esp-flasher/lib_esptools-js/targets/esp32s2.d.ts new file mode 100644 index 0000000..5554d72 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32s2.d.ts @@ -0,0 +1,39 @@ +import { ESPLoader } from "../esploader"; +import { ROM } from "./rom"; +export declare class ESP32S2ROM extends ROM { + CHIP_NAME: string; + IMAGE_CHIP_ID: number; + MAC_EFUSE_REG: number; + EFUSE_BASE: number; + UART_CLKDIV_REG: number; + UART_CLKDIV_MASK: number; + UART_DATE_REG_ADDR: number; + FLASH_WRITE_SIZE: number; + BOOTLOADER_FLASH_OFFSET: number; + FLASH_SIZES: { + "1MB": number; + "2MB": number; + "4MB": number; + "8MB": number; + "16MB": number; + }; + SPI_REG_BASE: number; + SPI_USR_OFFS: number; + SPI_USR1_OFFS: number; + SPI_USR2_OFFS: number; + SPI_W0_OFFS: number; + SPI_MOSI_DLEN_OFFS: number; + SPI_MISO_DLEN_OFFS: number; + TEXT_START: number; + ENTRY: number; + DATA_START: number; + ROM_DATA: string; + ROM_TEXT: string; + getPkgVersion(loader: ESPLoader): Promise; + getChipDescription(loader: ESPLoader): Promise; + getChipFeatures(loader: ESPLoader): Promise; + getCrystalFreq(loader: ESPLoader): Promise; + _d2h(d: number): string; + readMac(loader: ESPLoader): Promise; + getEraseSize(offset: number, size: number): number; +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32s2.js b/esp-flasher/lib_esptools-js/targets/esp32s2.js new file mode 100644 index 0000000..f48b8c5 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32s2.js @@ -0,0 +1,106 @@ +import { ROM } from "./rom.js"; +import ESP32S2_STUB from "./stub_flasher/stub_flasher_32s2.json"; +export class ESP32S2ROM extends ROM { + constructor() { + super(...arguments); + this.CHIP_NAME = "ESP32-S2"; + this.IMAGE_CHIP_ID = 2; + this.MAC_EFUSE_REG = 0x3f41a044; + this.EFUSE_BASE = 0x3f41a000; + this.UART_CLKDIV_REG = 0x3f400014; + this.UART_CLKDIV_MASK = 0xfffff; + this.UART_DATE_REG_ADDR = 0x60000078; + this.FLASH_WRITE_SIZE = 0x400; + this.BOOTLOADER_FLASH_OFFSET = 0x1000; + this.FLASH_SIZES = { + "1MB": 0x00, + "2MB": 0x10, + "4MB": 0x20, + "8MB": 0x30, + "16MB": 0x40, + }; + this.SPI_REG_BASE = 0x3f402000; + this.SPI_USR_OFFS = 0x18; + this.SPI_USR1_OFFS = 0x1c; + this.SPI_USR2_OFFS = 0x20; + this.SPI_W0_OFFS = 0x58; + this.SPI_MOSI_DLEN_OFFS = 0x24; + this.SPI_MISO_DLEN_OFFS = 0x28; + this.TEXT_START = ESP32S2_STUB.text_start; + this.ENTRY = ESP32S2_STUB.entry; + this.DATA_START = ESP32S2_STUB.data_start; + this.ROM_DATA = ESP32S2_STUB.data; + this.ROM_TEXT = ESP32S2_STUB.text; + } + async getPkgVersion(loader) { + const numWord = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const addr = block1Addr + 4 * numWord; + const word3 = await loader.readReg(addr); + const pkgVersion = (word3 >> 21) & 0x0f; + return pkgVersion; + } + async getChipDescription(loader) { + const chipDesc = ["ESP32-S2", "ESP32-S2FH16", "ESP32-S2FH32"]; + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer >= 0 && pkgVer <= 2) { + return chipDesc[pkgVer]; + } + else { + return "unknown ESP32-S2"; + } + } + async getChipFeatures(loader) { + const features = ["Wi-Fi"]; + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer == 1) { + features.push("Embedded 2MB Flash"); + } + else if (pkgVer == 2) { + features.push("Embedded 4MB Flash"); + } + const numWord = 4; + const block2Addr = this.EFUSE_BASE + 0x05c; + const addr = block2Addr + 4 * numWord; + const word4 = await loader.readReg(addr); + const block2Ver = (word4 >> 4) & 0x07; + if (block2Ver == 1) { + features.push("ADC and temperature sensor calibration in BLK2 of efuse"); + } + return features; + } + async getCrystalFreq(loader) { + return 40; + } + _d2h(d) { + const h = (+d).toString(16); + return h.length === 1 ? "0" + h : h; + } + async readMac(loader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); + mac0 = mac0 >>> 0; + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); + mac1 = (mac1 >>> 0) & 0x0000ffff; + const mac = new Uint8Array(6); + mac[0] = (mac1 >> 8) & 0xff; + mac[1] = mac1 & 0xff; + mac[2] = (mac0 >> 24) & 0xff; + mac[3] = (mac0 >> 16) & 0xff; + mac[4] = (mac0 >> 8) & 0xff; + mac[5] = mac0 & 0xff; + return (this._d2h(mac[0]) + + ":" + + this._d2h(mac[1]) + + ":" + + this._d2h(mac[2]) + + ":" + + this._d2h(mac[3]) + + ":" + + this._d2h(mac[4]) + + ":" + + this._d2h(mac[5])); + } + getEraseSize(offset, size) { + return size; + } +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32s3.d.ts b/esp-flasher/lib_esptools-js/targets/esp32s3.d.ts new file mode 100644 index 0000000..5f601c0 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32s3.d.ts @@ -0,0 +1,42 @@ +import { ESPLoader } from "../esploader"; +import { ROM } from "./rom"; +export declare class ESP32S3ROM extends ROM { + CHIP_NAME: string; + IMAGE_CHIP_ID: number; + EFUSE_BASE: number; + MAC_EFUSE_REG: number; + UART_CLKDIV_REG: number; + UART_CLKDIV_MASK: number; + UART_DATE_REG_ADDR: number; + FLASH_WRITE_SIZE: number; + BOOTLOADER_FLASH_OFFSET: number; + FLASH_SIZES: { + "1MB": number; + "2MB": number; + "4MB": number; + "8MB": number; + "16MB": number; + }; + SPI_REG_BASE: number; + SPI_USR_OFFS: number; + SPI_USR1_OFFS: number; + SPI_USR2_OFFS: number; + SPI_MOSI_DLEN_OFFS: number; + SPI_MISO_DLEN_OFFS: number; + SPI_W0_OFFS: number; + USB_RAM_BLOCK: number; + UARTDEV_BUF_NO_USB: number; + UARTDEV_BUF_NO: number; + TEXT_START: number; + ENTRY: number; + DATA_START: number; + ROM_DATA: string; + ROM_TEXT: string; + getChipDescription(loader: ESPLoader): Promise; + getChipFeatures(loader: ESPLoader): Promise; + getCrystalFreq(loader: ESPLoader): Promise; + _d2h(d: number): string; + postConnect(loader: ESPLoader): Promise; + readMac(loader: ESPLoader): Promise; + getEraseSize(offset: number, size: number): number; +} diff --git a/esp-flasher/lib_esptools-js/targets/esp32s3.js b/esp-flasher/lib_esptools-js/targets/esp32s3.js new file mode 100644 index 0000000..7562567 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp32s3.js @@ -0,0 +1,85 @@ +import { ROM } from "./rom.js"; +import ESP32S3_STUB from "./stub_flasher/stub_flasher_32s3.json"; +export class ESP32S3ROM extends ROM { + constructor() { + super(...arguments); + this.CHIP_NAME = "ESP32-S3"; + this.IMAGE_CHIP_ID = 9; + this.EFUSE_BASE = 0x60007000; + this.MAC_EFUSE_REG = this.EFUSE_BASE + 0x044; + this.UART_CLKDIV_REG = 0x60000014; + this.UART_CLKDIV_MASK = 0xfffff; + this.UART_DATE_REG_ADDR = 0x60000080; + this.FLASH_WRITE_SIZE = 0x400; + this.BOOTLOADER_FLASH_OFFSET = 0x0; + this.FLASH_SIZES = { + "1MB": 0x00, + "2MB": 0x10, + "4MB": 0x20, + "8MB": 0x30, + "16MB": 0x40, + }; + this.SPI_REG_BASE = 0x60002000; + this.SPI_USR_OFFS = 0x18; + this.SPI_USR1_OFFS = 0x1c; + this.SPI_USR2_OFFS = 0x20; + this.SPI_MOSI_DLEN_OFFS = 0x24; + this.SPI_MISO_DLEN_OFFS = 0x28; + this.SPI_W0_OFFS = 0x58; + this.USB_RAM_BLOCK = 0x800; + this.UARTDEV_BUF_NO_USB = 3; + this.UARTDEV_BUF_NO = 0x3fcef14c; + this.TEXT_START = ESP32S3_STUB.text_start; + this.ENTRY = ESP32S3_STUB.entry; + this.DATA_START = ESP32S3_STUB.data_start; + this.ROM_DATA = ESP32S3_STUB.data; + this.ROM_TEXT = ESP32S3_STUB.text; + } + async getChipDescription(loader) { + return "ESP32-S3"; + } + async getChipFeatures(loader) { + return ["Wi-Fi", "BLE"]; + } + async getCrystalFreq(loader) { + return 40; + } + _d2h(d) { + const h = (+d).toString(16); + return h.length === 1 ? "0" + h : h; + } + async postConnect(loader) { + const bufNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; + loader.debug("In _post_connect " + bufNo); + if (bufNo == this.UARTDEV_BUF_NO_USB) { + loader.ESP_RAM_BLOCK = this.USB_RAM_BLOCK; + } + } + async readMac(loader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); + mac0 = mac0 >>> 0; + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); + mac1 = (mac1 >>> 0) & 0x0000ffff; + const mac = new Uint8Array(6); + mac[0] = (mac1 >> 8) & 0xff; + mac[1] = mac1 & 0xff; + mac[2] = (mac0 >> 24) & 0xff; + mac[3] = (mac0 >> 16) & 0xff; + mac[4] = (mac0 >> 8) & 0xff; + mac[5] = mac0 & 0xff; + return (this._d2h(mac[0]) + + ":" + + this._d2h(mac[1]) + + ":" + + this._d2h(mac[2]) + + ":" + + this._d2h(mac[3]) + + ":" + + this._d2h(mac[4]) + + ":" + + this._d2h(mac[5])); + } + getEraseSize(offset, size) { + return size; + } +} diff --git a/esp-flasher/lib_esptools-js/targets/esp8266.d.ts b/esp-flasher/lib_esptools-js/targets/esp8266.d.ts new file mode 100644 index 0000000..0eca04f --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp8266.d.ts @@ -0,0 +1,43 @@ +import { ESPLoader } from "../esploader"; +import { ROM } from "./rom"; +export declare class ESP8266ROM extends ROM { + CHIP_NAME: string; + CHIP_DETECT_MAGIC_VALUE: number[]; + EFUSE_RD_REG_BASE: number; + UART_CLKDIV_REG: number; + UART_CLKDIV_MASK: number; + XTAL_CLK_DIVIDER: number; + FLASH_WRITE_SIZE: number; + BOOTLOADER_FLASH_OFFSET: number; + UART_DATE_REG_ADDR: number; + FLASH_SIZES: { + "512KB": number; + "256KB": number; + "1MB": number; + "2MB": number; + "4MB": number; + "2MB-c1": number; + "4MB-c1": number; + "8MB": number; + "16MB": number; + }; + SPI_REG_BASE: number; + SPI_USR_OFFS: number; + SPI_USR1_OFFS: number; + SPI_USR2_OFFS: number; + SPI_MOSI_DLEN_OFFS: number; + SPI_MISO_DLEN_OFFS: number; + SPI_W0_OFFS: number; + TEXT_START: number; + ENTRY: number; + DATA_START: number; + ROM_DATA: string; + ROM_TEXT: string; + readEfuse(loader: ESPLoader, offset: number): Promise; + getChipDescription(loader: ESPLoader): Promise<"ESP8285" | "ESP8266EX">; + getChipFeatures: (loader: ESPLoader) => Promise; + getCrystalFreq(loader: ESPLoader): Promise; + _d2h(d: number): string; + readMac(loader: ESPLoader): Promise; + getEraseSize(offset: number, size: number): number; +} diff --git a/esp-flasher/lib_esptools-js/targets/esp8266.js b/esp-flasher/lib_esptools-js/targets/esp8266.js new file mode 100644 index 0000000..067bdef --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/esp8266.js @@ -0,0 +1,124 @@ +import { ROM } from "./rom.js"; +import ESP8266_STUB from "./stub_flasher/stub_flasher_8266.json"; +export class ESP8266ROM extends ROM { + constructor() { + super(...arguments); + this.CHIP_NAME = "ESP8266"; + this.CHIP_DETECT_MAGIC_VALUE = [0xfff0c101]; + this.EFUSE_RD_REG_BASE = 0x3ff00050; + this.UART_CLKDIV_REG = 0x60000014; + this.UART_CLKDIV_MASK = 0xfffff; + this.XTAL_CLK_DIVIDER = 2; + this.FLASH_WRITE_SIZE = 0x4000; + // NOT IMPLEMENTED, SETTING EMPTY VALUE + this.BOOTLOADER_FLASH_OFFSET = 0; + this.UART_DATE_REG_ADDR = 0; + this.FLASH_SIZES = { + "512KB": 0x00, + "256KB": 0x10, + "1MB": 0x20, + "2MB": 0x30, + "4MB": 0x40, + "2MB-c1": 0x50, + "4MB-c1": 0x60, + "8MB": 0x80, + "16MB": 0x90, + }; + this.SPI_REG_BASE = 0x60000200; + this.SPI_USR_OFFS = 0x1c; + this.SPI_USR1_OFFS = 0x20; + this.SPI_USR2_OFFS = 0x24; + this.SPI_MOSI_DLEN_OFFS = 0; // not in esp8266 + this.SPI_MISO_DLEN_OFFS = 0; // not in esp8266 + this.SPI_W0_OFFS = 0x40; + this.TEXT_START = ESP8266_STUB.text_start; + this.ENTRY = ESP8266_STUB.entry; + this.DATA_START = ESP8266_STUB.data_start; + this.ROM_DATA = ESP8266_STUB.data; + this.ROM_TEXT = ESP8266_STUB.text; + this.getChipFeatures = async (loader) => { + const features = ["WiFi"]; + if ((await this.getChipDescription(loader)) == "ESP8285") + features.push("Embedded Flash"); + return features; + }; + } + async readEfuse(loader, offset) { + const addr = this.EFUSE_RD_REG_BASE + 4 * offset; + loader.debug("Read efuse " + addr); + return await loader.readReg(addr); + } + async getChipDescription(loader) { + const efuse3 = await this.readEfuse(loader, 2); + const efuse0 = await this.readEfuse(loader, 0); + const is8285 = ((efuse0 & (1 << 4)) | (efuse3 & (1 << 16))) != 0; // One or the other efuse bit is set for ESP8285 + return is8285 ? "ESP8285" : "ESP8266EX"; + } + async getCrystalFreq(loader) { + const uartDiv = (await loader.readReg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; + const etsXtal = (loader.transport.baudrate * uartDiv) / 1000000 / this.XTAL_CLK_DIVIDER; + let normXtal; + if (etsXtal > 33) { + normXtal = 40; + } + else { + normXtal = 26; + } + if (Math.abs(normXtal - etsXtal) > 1) { + loader.info("WARNING: Detected crystal freq " + + etsXtal + + "MHz is quite different to normalized freq " + + normXtal + + "MHz. Unsupported crystal in use?"); + } + return normXtal; + } + _d2h(d) { + const h = (+d).toString(16); + return h.length === 1 ? "0" + h : h; + } + async readMac(loader) { + let mac0 = await this.readEfuse(loader, 0); + mac0 = mac0 >>> 0; + let mac1 = await this.readEfuse(loader, 1); + mac1 = mac1 >>> 0; + let mac3 = await this.readEfuse(loader, 3); + mac3 = mac3 >>> 0; + const mac = new Uint8Array(6); + if (mac3 != 0) { + mac[0] = (mac3 >> 16) & 0xff; + mac[1] = (mac3 >> 8) & 0xff; + mac[2] = mac3 & 0xff; + } + else if (((mac1 >> 16) & 0xff) == 0) { + mac[0] = 0x18; + mac[1] = 0xfe; + mac[2] = 0x34; + } + else if (((mac1 >> 16) & 0xff) == 1) { + mac[0] = 0xac; + mac[1] = 0xd0; + mac[2] = 0x74; + } + else { + loader.error("Unknown OUI"); + } + mac[3] = (mac1 >> 8) & 0xff; + mac[4] = mac1 & 0xff; + mac[5] = (mac0 >> 24) & 0xff; + return (this._d2h(mac[0]) + + ":" + + this._d2h(mac[1]) + + ":" + + this._d2h(mac[2]) + + ":" + + this._d2h(mac[3]) + + ":" + + this._d2h(mac[4]) + + ":" + + this._d2h(mac[5])); + } + getEraseSize(offset, size) { + return size; + } +} diff --git a/esp-flasher/lib_esptools-js/targets/rom.d.ts b/esp-flasher/lib_esptools-js/targets/rom.d.ts new file mode 100644 index 0000000..3f3fe36 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/rom.d.ts @@ -0,0 +1,88 @@ +import { ESPLoader } from "../esploader"; +/** + * Represents a chip ROM with basic registers field and abstract functions. + */ +export declare abstract class ROM { + /** + * Read ESP32 eFuse. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @param {number} offset - Offset to start erase. + * @returns {number} The eFuse number. + */ + protected readEfuse?(loader: ESPLoader, offset: number): Promise; + /** + * Get the package version number. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {number} The package version number. + */ + protected getPkgVersion?(loader: ESPLoader): Promise; + /** + * Get the chip revision number. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {number} The chip revision number. + */ + protected getChipRevision?(loader: ESPLoader): Promise; + /** + * Get the chip description. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {string} The chip description as string. + */ + abstract getChipDescription(loader: ESPLoader): Promise; + /** + * Get the chip features. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {string} The chip features as string. + */ + abstract getChipFeatures(loader: ESPLoader): Promise; + /** + * Get the crystal frequency for the chip. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {string} The crystal frequency as number. + */ + abstract getCrystalFreq(loader: ESPLoader): Promise; + /** + * Convert a number to hex string. + * @param {number} d - Number to convert to hex string. + * @returns {string} The hex string. + */ + abstract _d2h(d: number): string; + /** + * Get the chip mac address. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {string} The mac address string. + */ + abstract readMac(loader: ESPLoader): Promise; + /** + * Function to be executed after chip connection + * @param {ESPLoader} loader - Loader class to communicate with chip. + */ + postConnect?(loader: ESPLoader): Promise; + /** + * Get the chip erase size. + * @param {number} offset - Offset to start erase. + * @param {number} size - Size to erase. + * @returns {number} The erase size of the chip as number. + */ + getEraseSize(offset: number, size: number): number; + abstract FLASH_SIZES: { + [key: string]: number; + }; + abstract BOOTLOADER_FLASH_OFFSET: number; + abstract CHIP_NAME: string; + abstract DATA_START: number; + abstract ENTRY: number; + abstract FLASH_WRITE_SIZE: number; + abstract ROM_DATA: string; + abstract ROM_TEXT: string; + abstract SPI_MOSI_DLEN_OFFS: number; + abstract SPI_MISO_DLEN_OFFS: number; + abstract SPI_REG_BASE: number; + abstract SPI_USR_OFFS: number; + abstract SPI_USR1_OFFS: number; + abstract SPI_USR2_OFFS: number; + abstract SPI_W0_OFFS: number; + abstract UART_CLKDIV_MASK: number; + abstract UART_CLKDIV_REG: number; + abstract UART_DATE_REG_ADDR: number; + abstract TEXT_START: number; +} diff --git a/esp-flasher/lib_esptools-js/targets/rom.js b/esp-flasher/lib_esptools-js/targets/rom.js new file mode 100644 index 0000000..8b15a31 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/rom.js @@ -0,0 +1,14 @@ +/** + * Represents a chip ROM with basic registers field and abstract functions. + */ +export class ROM { + /** + * Get the chip erase size. + * @param {number} offset - Offset to start erase. + * @param {number} size - Size to erase. + * @returns {number} The erase size of the chip as number. + */ + getEraseSize(offset, size) { + return size; + } +} diff --git a/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32.json b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32.json new file mode 100644 index 0000000..7e54ff3 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32.json @@ -0,0 +1,7 @@ +{ + "entry": 1074521560, + "text": "CAD0PxwA9D8AAPQ/AMD8PxAA9D82QQAh+v/AIAA4AkH5/8AgACgEICB0nOIGBQAAAEH1/4H2/8AgAKgEiAigoHTgCAALImYC54b0/yHx/8AgADkCHfAAAKDr/T8Ya/0/hIAAAEBAAABYq/0/pOv9PzZBALH5/yCgdBARIKXHAJYaBoH2/5KhAZCZEZqYwCAAuAmR8/+goHSaiMAgAJIYAJCQ9BvJwMD0wCAAwlgAmpvAIACiSQDAIACSGACB6v+QkPSAgPSHmUeB5f+SoQGQmRGamMAgAMgJoeX/seP/h5wXxgEAfOiHGt7GCADAIACJCsAgALkJRgIAwCAAuQrAIACJCZHX/5qIDAnAIACSWAAd8AAA+CD0P/gw9D82QQCR/f/AIACICYCAJFZI/5H6/8AgAIgJgIAkVkj/HfAAAAAQIPQ/ACD0PwAAAAg2QQAQESCl/P8h+v8MCMAgAIJiAJH6/4H4/8AgAJJoAMAgAJgIVnn/wCAAiAJ88oAiMCAgBB3wAAAAAEA2QQAQESDl+/8Wav+B7P+R+//AIACSaADAIACYCFZ5/x3wAAAMwPw/////AAQg9D82QQAh/P84QhaDBhARIGX4/xb6BQz4DAQ3qA2YIoCZEIKgAZBIg0BAdBARICX6/xARICXz/4giDBtAmBGQqwHMFICrAbHt/7CZELHs/8AgAJJrAJHO/8AgAKJpAMAgAKgJVnr/HAkMGkCag5AzwJqIOUKJIh3wAAAskgBANkEAoqDAgf3/4AgAHfAAADZBAIKgwK0Ch5IRoqDbgff/4AgAoqDcRgQAAAAAgqDbh5IIgfL/4AgAoqDdgfD/4AgAHfA2QQA6MsYCAACiAgAbIhARIKX7/zeS8R3wAAAAfNoFQNguBkCc2gVAHNsFQDYhIaLREIH6/+AIAEYLAAAADBRARBFAQ2PNBL0BrQKB9f/gCACgoHT8Ws0EELEgotEQgfH/4AgASiJAM8BWA/0iogsQIrAgoiCy0RCB7P/gCACtAhwLEBEgpff/LQOGAAAioGMd8AAA/GcAQNCSAEAIaABANkEhYqEHwGYRGmZZBiwKYtEQDAVSZhqB9//gCAAMGECIEUe4AkZFAK0GgdT/4AgAhjQAAJKkHVBzwOCZERqZQHdjiQnNB70BIKIggc3/4AgAkqQd4JkRGpmgoHSICYyqDAiCZhZ9CIYWAAAAkqQd4JkREJmAgmkAEBEgJer/vQetARARIKXt/xARICXp/80HELEgYKYggbv/4AgAkqQd4JkRGpmICXAigHBVgDe1sJKhB8CZERqZmAmAdcCXtwJG3P+G5v8MCIJGbKKkGxCqoIHK/+AIAFYK/7KiC6IGbBC7sBARIKWPAPfqEvZHD7KiDRC7sHq7oksAG3eG8f9867eawWZHCIImGje4Aoe1nCKiCxAisGC2IK0CgZv/4AgAEBEgpd//rQIcCxARICXj/xARIKXe/ywKgbH/4AgAHfAIIPQ/cOL6P0gkBkDwIgZANmEAEBEg5cr/EKEggfv/4AgAPQoMEvwqiAGSogCQiBCJARARIKXP/5Hy/6CiAcAgAIIpAKCIIMAgAIJpALIhAKHt/4Hu/+AIAKAjgx3wAAD/DwAANkEAgTv/DBmSSAAwnEGZKJH7/zkYKTgwMLSaIiozMDxBDAIpWDlIEBEgJfj/LQqMGiKgxR3wAABQLQZANkEAQSz/WDRQM2MWYwRYFFpTUFxBRgEAEBEgZcr/iESmGASIJIel7xARIKXC/xZq/6gUzQO9AoHx/+AIAKCgdIxKUqDEUmQFWBQ6VVkUWDQwVcBZNB3wAADA/D9PSEFJqOv9P3DgC0AU4AtADAD0PzhA9D///wAAjIAAABBAAACs6/0/vOv9PwTA/D8IwPw/BOz9PxQA9D/w//8AqOv9Pxjr/D8kwPw/fGgAQOxnAEBYhgBAbCoGQDgyBkAULAZAzCwGQEwsBkA0hQBAzJAAQHguBkAw7wVAWJIAQEyCAEA2wQAh3v8MCiJhCEKgAIHu/+AIACHZ/zHa/8YAAEkCSyI3MvgQESBlw/8MS6LBIBARIOXG/yKhARARICXC/1GR/pAiESolMc//sc//wCAAWQIheP4MDAxaMmIAgdz/4AgAMcr/QqEBwCAAKAMsCkAiIMAgACkDgTH/4AgAgdX/4AgAIcP/wCAAKALMuhzDMCIQIsL4DBMgo4MMC4HO/+AIAPG8/wwdwqABDBvioQBA3REAzBGAuwGioACBx//gCAAhtv8MBCpVIcP+ctIrwCAAKAUWcv/AIAA4BQwSwCAASQUiQRAiAwEMKCJBEYJRCUlRJpIHHDiHEh4GCAAiAwOCAwKAIhGAIiBmQhEoI8AgACgCKVFGAQAAHCIiUQkQESCls/8Mi6LBEBARIGW3/4IDAyIDAoCIESCIICGY/yAg9IeyHKKgwBARICWy/6Kg7hARIKWx/xARICWw/4bb/wAAIgMBHDknOTT2IhjG1AAAACLCLyAgdPZCcJGJ/5AioCgCoAIAIsL+ICB0HBknuQLGywCRhP+QIqAoAqACAJLCMJCQdLZZyQbGACxKbQQioMCnGAIGxABJUQxyrQQQESDlqv+tBBARIGWq/xARIOWo/xARIKWo/wyLosEQIsL/EBEg5av/ViL9RikADBJWyCyCYQ+Bev/gCACI8aAog8auACaIBAwSxqwAmCNoM2CJIICAtFbY/pnBEBEgZcf/mMFqKZwqBvf/AACgrEGBbf/gCABW6vxi1vBgosDMJgaBAACgkPRWGf6GBACgoPWZwYFl/+AIAJjBVpr6kGbADBkAmRFgosBnOeEGBAAAAKCsQYFc/+AIAFaq+GLW8GCiwFam/sZvAABtBCKgwCaIAoaNAG0EDALGiwAAACa484ZhAAwSJrgCBoUAuDOoIxARIOWh/6AkgwaBAAwcZrhTiEMgrBFtBCKgwoe6AoZ+ALhTqCPJ4RARIOXA/8YLAAwcZrgviEMgrBFtBCKgwoe6AoZ1ACgzuFOoIyBogsnhEBEgZb7/ITT+SWIi0itpIsjhoMSDLQyGaQChL/5tBLIKACKgxhY7GpgjgsjwIqDAh5kBKFoMCaKg70YCAJqzsgsYG5mwqjCHKfKCAwWSAwSAiBGQiCCSAwZtBACZEYCZIIIDB4CIAZCIIICqwIKgwaAok0ZVAIEY/m0EoggAIqDGFnoUqDgioMhW+hMoWKJIAMZNAByKbQQMEqcYAsZKAPhz6GPYU8hDuDOoI4EM/+AIAG0KoCSDRkQAAAwSJkgCRj8AqCO9BIEE/+AIAAYeAICwNG0EIqDAVgsPgGRBi8N8/UYOAKg8ucHJ4dnRgQD/4AgAyOG4wSgsmByoDNIhDZCSECYCDsAgAOIqACAtMOAiECCZIMAgAJkKG7vCzBBnO8LGm/9mSAJGmv9tBCKgwAYmAAwSJrgCRiEAIdz+mFOII5kCIdv+iQItBIYcAGHX/gwb2AaCyPCtBC0EgCuT0KuDIKoQbQQioMZW6gXB0f4ioMnoDIc+U4DwFCKgwFavBC0KRgIAKqOoaksiqQmtCyD+wCqdhzLtFprfIcT++QyZAsZ7/wwSZogWIcH+iAIWKACCoMhJAiG9/kkCDBKAJINtBEYBAABtBCKg/yCgdBARIOV5/2CgdBARIGV5/xARIOV3/1aiviIDARwoJzge9jICBvf+IsL9ICB0DPgnuAKG8/6BrP6AIqAoAqACAIKg0ocSUoKg1IcSegbt/gAAAIgzoqJxwKoRaCOJ8YGw/uAIACGh/pGi/sAgACgCiPEgNDXAIhGQIhAgIyCAIoKtBGCywoGn/uAIAKKj6IGk/uAIAAbb/gAA2FPIQ7gzqCMQESAlff9G1v4AsgMDIgMCgLsRILsgssvwosMYEBEgZZn/Rs/+ACIDA4IDAmGP/YAiEZg2gCIgIsLwkCJjFiKymBaakpCcQUYCAJnBEBEgZWL/mMGoRqYaBKgmp6nrEBEgpVr/Fmr/qBbNArLDGIGG/uAIAIw6MqDEOVY4FiozORY4NiAjwCk2xrX+ggMCIsMYMgMDDByAMxGAMyAyw/AGIwCBbP6RHf3oCDlx4JnAmWGYJwwal7MBDDqJ8anR6cEQESAlW/+o0ZFj/ujBqQGhYv7dCb0CwsEc8sEYmcGBa/7gCAC4J80KqHGI8aC7wLknoDPAuAiqIqhhmMGqu90EDBq5CMDag5C7wNDgdMx90tuA0K6TFmoBrQmJ8ZnByeEQESAlif+I8ZjByOGSaABhTv2INoyjwJ8xwJnA1ikAVvj11qwAMUn9IqDHKVNGAACMPJwIxoL+FoigYUT9IqDIKVZGf/4AMUH9IqDJKVNGfP4oI1bCnq0EgUX+4AgAoqJxwKoRgT7+4AgAgUL+4AgAxnP+AAAoMxaCnK0EgTz+4AgAoqPogTb+4AgA4AIARmz+HfAAAAA2QQCdAoKgwCgDh5kPzDIMEoYHAAwCKQN84oYPACYSByYiGIYDAAAAgqDbgCkjh5kqDCIpA3zyRggAAAAioNwnmQoMEikDLQgGBAAAAIKg3Xzyh5kGDBIpAyKg2x3wAAA=", + "text_start": 1074520064, + "data": "GOv8P9jnC0Bx6AtA8+wLQO3oC0CP6AtA7egLQEnpC0AG6gtAeOoLQCHqC0CB5wtAo+kLQPjpC0Bn6QtAmuoLQI7pC0Ca6gtAXegLQLPoC0Dt6AtASekLQHfoC0BM6wtAs+wLQKXmC0DX7AtApeYLQKXmC0Cl5gtApeYLQKXmC0Cl5gtApeYLQKXmC0Dz6gtApeYLQM3rC0Cz7AtA", + "data_start": 1073605544 +} diff --git a/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c2.json b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c2.json new file mode 100644 index 0000000..9234f07 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c2.json @@ -0,0 +1,8 @@ +{ + "entry": 1077413304, + "text": "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", + "text_start": 1077411840, + "data": "DEDKP+AIOEAsCThAhAk4QFIKOEC+CjhAbAo4QKgHOEAOCjhATgo4QJgJOEBYBzhAzAk4QFgHOEC6CDhA/gg4QCwJOECECThAzAg4QBIIOEBCCDhAyAg4QBYNOEAsCThA1gs4QMoMOECkBjhA9Aw4QKQGOECkBjhApAY4QKQGOECkBjhApAY4QKQGOECkBjhAcgs4QKQGOEDyCzhAygw4QA==", + "data_start": 1070295976, + "bss_start": 1070219264 +} diff --git a/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c3.json b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c3.json new file mode 100644 index 0000000..0ef3a7b --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c3.json @@ -0,0 +1,7 @@ +{ + "entry": 1077413532, + "text": "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", + "text_start": 1077411840, + "data": "IGvIP3YKOEDGCjhAHgs4QMILOEAuDDhA3As4QEIJOEB+CzhAvgs4QDILOEDyCDhAZgs4QPIIOEBQCjhAlgo4QMYKOEAeCzhAYgo4QKYJOEDWCThAXgo4QIAOOEDGCjhARg04QDgOOEAyCDhAYA44QDIIOEAyCDhAMgg4QDIIOEAyCDhAMgg4QDIIOEAyCDhA4gw4QDIIOEBkDThAOA44QA==", + "data_start": 1070164912 +} diff --git a/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c6.json b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c6.json new file mode 100644 index 0000000..99b3164 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32c6.json @@ -0,0 +1,7 @@ +{ + "entry": 1082132112, + "text": "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", + "text_start": 1082130432, + "data": "HCuEQEIKgECSCoBA6gqAQI4LgED6C4BAqAuAQA4JgEBKC4BAiguAQP4KgEC+CIBAMguAQL4IgEAcCoBAYgqAQJIKgEDqCoBALgqAQHIJgECiCYBAKgqAQEwOgECSCoBAEg2AQAQOgED+B4BALA6AQP4HgED+B4BA/geAQP4HgED+B4BA/geAQP4HgED+B4BArgyAQP4HgEAwDYBABA6AQA==", + "data_start": 1082469292 +} diff --git a/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32h2.json b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32h2.json new file mode 100644 index 0000000..fd70476 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32h2.json @@ -0,0 +1,7 @@ +{ + "entry": 1082132112, + "text": "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", + "text_start": 1082130432, + "data": "EACDQEIKgECSCoBA6gqAQI4LgED6C4BAqAuAQA4JgEBKC4BAiguAQP4KgEC+CIBAMguAQL4IgEAcCoBAYgqAQJIKgEDqCoBALgqAQHIJgECiCYBAKgqAQFIOgECSCoBAEg2AQAoOgED+B4BAMg6AQP4HgED+B4BA/geAQP4HgED+B4BA/geAQP4HgED+B4BArgyAQP4HgEAwDYBACg6AQA==", + "data_start": 1082403756 +} diff --git a/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32s2.json b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32s2.json new file mode 100644 index 0000000..0d3989b --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32s2.json @@ -0,0 +1,7 @@ +{ + "entry": 1073907696, + "text": "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", + "text_start": 1073905664, + "data": "ZCv9PzaLAkDBiwJAhpACQEqMAkDjiwJASowCQKmMAkByjQJA5Y0CQI2NAkDAigJAC40CQGSNAkDMjAJACI4CQPaMAkAIjgJAr4sCQA6MAkBKjAJAqYwCQMeLAkACiwJAx44CQD2QAkDYiQJAZZACQNiJAkDYiQJA2IkCQNiJAkDYiQJA2IkCQNiJAkDYiQJAZI4CQNiJAkBZjwJAPZACQA==", + "data_start": 1073622012 +} diff --git a/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32s3.json b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32s3.json new file mode 100644 index 0000000..e6b6c01 --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_32s3.json @@ -0,0 +1,7 @@ +{ + "entry": 1077381696, + "text": "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", + "text_start": 1077379072, + "data": "ZCvKP8qNN0CvjjdAcJM3QDqPN0DPjjdAOo83QJmPN0BmkDdA2ZA3QIGQN0BVjTdA/I83QFiQN0C8jzdA+5A3QOaPN0D7kDdAnY43QPqON0A6jzdAmY83QLWON0CWjTdAvJE3QDaTN0ByjDdAVpM3QHKMN0ByjDdAcow3QHKMN0ByjDdAcow3QHKMN0ByjDdAVpE3QHKMN0BRkjdANpM3QAQInwAAAAAAAAAYAQQIBQAAAAAAAAAIAQQIBgAAAAAAAAAAAQQIIQAAAAAAIAAAEQQI3AAAAAAAIAAAEQQIDAAAAAAAIAAAAQQIEgAAAAAAIAAAESAoDAAQAQAA", + "data_start": 1070279668 +} diff --git a/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_8266.json b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_8266.json new file mode 100644 index 0000000..74a5dab --- /dev/null +++ b/esp-flasher/lib_esptools-js/targets/stub_flasher/stub_flasher_8266.json @@ -0,0 +1,7 @@ +{ + "entry": 1074843652, + "text": "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", + "text_start": 1074843648, + "data": "CIH+PwUFBAACAwcAAwMLALnXEEDv1xBAHdgQQLrYEEBo5xBAHtkQQHTZEEDA2RBAaOcQQILaEED/2hBAwNsQQGjnEEBo5xBAWNwQQGjnEEA33xBAAOAQQDvgEEBo5xBAaOcQQNfgEEBo5xBAv+EQQGXiEECj4xBAY+QQQDTlEEBo5xBAaOcQQGjnEEBo5xBAYuYQQGjnEEBX5xBAkN0QQI/YEECm5RBAq9oQQPzZEEBo5xBA7OYQQDHnEEBo5xBAaOcQQGjnEEBo5xBAaOcQQGjnEEBo5xBAaOcQQCLaEEBf2hBAvuUQQAEAAAACAAAAAwAAAAQAAAAFAAAABwAAAAkAAAANAAAAEQAAABkAAAAhAAAAMQAAAEEAAABhAAAAgQAAAMEAAAABAQAAgQEAAAECAAABAwAAAQQAAAEGAAABCAAAAQwAAAEQAAABGAAAASAAAAEwAAABQAAAAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAUAAAAGAAAABgAAAAcAAAAHAAAACAAAAAgAAAAJAAAACQAAAAoAAAAKAAAACwAAAAsAAAAMAAAADAAAAA0AAAANAAAAAAAAAAAAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAANAAAADwAAABEAAAATAAAAFwAAABsAAAAfAAAAIwAAACsAAAAzAAAAOwAAAEMAAABTAAAAYwAAAHMAAACDAAAAowAAAMMAAADjAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAgAAAAMAAAADAAAAAwAAAAMAAAAEAAAABAAAAAQAAAAEAAAABQAAAAUAAAAFAAAABQAAAAAAAAAAAAAAAAAAABAREgAIBwkGCgULBAwDDQIOAQ8AAQEAAAEAAAAEAAAA", + "data_start": 1073720488 +} diff --git a/esp-flasher/lib_esptools-js/webserial.d.ts b/esp-flasher/lib_esptools-js/webserial.d.ts new file mode 100644 index 0000000..1908eae --- /dev/null +++ b/esp-flasher/lib_esptools-js/webserial.d.ts @@ -0,0 +1,148 @@ +/// +/** + * Options for device serialPort. + * @interface SerialOptions + * + * Note: According to the documentation of the Web Serial API, 'baudRate' is a + * 'required' field as part of serial options. However, we are currently + * maintaining 'baudRate' as a separate parameter outside the options + * dictionary, and it is effectively used in the code. For now, we are + * keeping it optional in the dictionary to avoid conflicts. + */ +export interface SerialOptions { + /** + * A positive, non-zero value indicating the baud rate at which serial communication should be established. + * @type {number | undefined} + */ + baudRate?: number | undefined; + /** + * The number of data bits per frame. Either 7 or 8. + * @type {number | undefined} + */ + dataBits?: number | undefined; + /** + * The number of stop bits at the end of a frame. Either 1 or 2. + * @type {number | undefined} + */ + stopBits?: number | undefined; + /** + * The parity mode: none, even or odd + * @type {ParityType | undefined} + */ + parity?: ParityType | undefined; + /** + * A positive, non-zero value indicating the size of the read and write buffers that should be created. + * @type {number | undefined} + */ + bufferSize?: number | undefined; + /** + * The flow control mode: none or hardware. + * @type {FlowControlType | undefined} + */ + flowControl?: FlowControlType | undefined; +} +/** + * Wrapper class around Webserial API to communicate with the serial device. + * @param {typeof import("w3c-web-serial").SerialPort} device - Requested device prompted by the browser. + * + * ``` + * const port = await navigator.serial.requestPort(); + * ``` + */ +declare class Transport { + device: SerialPort; + tracing: boolean; + slipReaderEnabled: boolean; + leftOver: Uint8Array; + baudrate: number; + private traceLog; + private lastTraceTime; + private reader; + constructor(device: SerialPort, tracing?: boolean, enableSlipReader?: boolean); + /** + * Request the serial device vendor ID and Product ID as string. + * @returns {string} Return the device VendorID and ProductID from SerialPortInfo as formatted string. + */ + getInfo(): string; + /** + * Request the serial device product id from SerialPortInfo. + * @returns {number | undefined} Return the product ID. + */ + getPid(): number | undefined; + /** + * Format received or sent data for tracing output. + * @param {string} message Message to format as trace line. + */ + trace(message: string): void; + returnTrace(): Promise; + hexify(s: Uint8Array): string; + hexConvert(uint8Array: Uint8Array, autoSplit?: boolean): string; + /** + * Format data packet using the Serial Line Internet Protocol (SLIP). + * @param {Uint8Array} data Binary unsigned 8 bit array data to format. + * @returns {Uint8Array} Formatted unsigned 8 bit data array. + */ + slipWriter(data: Uint8Array): Uint8Array; + /** + * Write binary data to device using the WebSerial device writable stream. + * @param {Uint8Array} data 8 bit unsigned data array to write to device. + */ + write(data: Uint8Array): Promise; + /** + * Concatenate buffer2 to buffer1 and return the resulting ArrayBuffer. + * @param {ArrayBuffer} buffer1 First buffer to concatenate. + * @param {ArrayBuffer} buffer2 Second buffer to concatenate. + * @returns {ArrayBuffer} Result Array buffer. + */ + _appendBuffer(buffer1: ArrayBuffer, buffer2: ArrayBuffer): ArrayBufferLike; + /** + * Take a data array and return the first well formed packet after + * replacing the escape sequence. Reads at least 8 bytes. + * @param {Uint8Array} data Unsigned 8 bit array from the device read stream. + * @returns {Uint8Array} Formatted packet using SLIP escape sequences. + */ + slipReader(data: Uint8Array): Uint8Array; + /** + * Read from serial device using the device ReadableStream. + * @param {number} timeout Read timeout number + * @param {number} minData Minimum packet array length + * @returns {Uint8Array} 8 bit unsigned data array read from device. + */ + read(timeout?: number, minData?: number): Promise; + /** + * Read from serial device without slip formatting. + * @param {number} timeout Read timeout in milliseconds (ms) + * @returns {Uint8Array} 8 bit unsigned data array read from device. + */ + rawRead(timeout?: number): Promise; + _DTR_state: boolean; + /** + * Send the RequestToSend (RTS) signal to given state + * # True for EN=LOW, chip in reset and False EN=HIGH, chip out of reset + * @param {boolean} state Boolean state to set the signal + */ + setRTS(state: boolean): Promise; + /** + * Send the dataTerminalReady (DTS) signal to given state + * # True for IO0=LOW, chip in reset and False IO0=HIGH + * @param {boolean} state Boolean state to set the signal + */ + setDTR(state: boolean): Promise; + /** + * Connect to serial device using the Webserial open method. + * @param {number} baud Number baud rate for serial connection. + * @param {typeof import("w3c-web-serial").SerialOptions} serialOptions Serial Options for WebUSB SerialPort class. + */ + connect(baud?: number, serialOptions?: SerialOptions): Promise; + sleep(ms: number): Promise; + /** + * Wait for a given timeout ms for serial device unlock. + * @param {number} timeout Timeout time in milliseconds (ms) to sleep + */ + waitForUnlock(timeout: number): Promise; + /** + * Disconnect from serial device by running SerialPort.close() after streams unlock. + */ + disconnect(): Promise; +} +export { Transport }; diff --git a/esp-flasher/lib_esptools-js/webserial.js b/esp-flasher/lib_esptools-js/webserial.js new file mode 100644 index 0000000..0e8ee79 --- /dev/null +++ b/esp-flasher/lib_esptools-js/webserial.js @@ -0,0 +1,347 @@ +/* global SerialPort, ParityType, FlowControlType */ +/** + * Wrapper class around Webserial API to communicate with the serial device. + * @param {typeof import("w3c-web-serial").SerialPort} device - Requested device prompted by the browser. + * + * ``` + * const port = await navigator.serial.requestPort(); + * ``` + */ +class Transport { + constructor(device, tracing = false, enableSlipReader = true) { + this.device = device; + this.tracing = tracing; + this.slipReaderEnabled = false; + this.leftOver = new Uint8Array(0); + this.baudrate = 0; + this.traceLog = ""; + this.lastTraceTime = Date.now(); + this._DTR_state = false; + this.slipReaderEnabled = enableSlipReader; + } + /** + * Request the serial device vendor ID and Product ID as string. + * @returns {string} Return the device VendorID and ProductID from SerialPortInfo as formatted string. + */ + getInfo() { + const info = this.device.getInfo(); + return info.usbVendorId && info.usbProductId + ? `WebSerial VendorID 0x${info.usbVendorId.toString(16)} ProductID 0x${info.usbProductId.toString(16)}` + : ""; + } + /** + * Request the serial device product id from SerialPortInfo. + * @returns {number | undefined} Return the product ID. + */ + getPid() { + return this.device.getInfo().usbProductId; + } + /** + * Format received or sent data for tracing output. + * @param {string} message Message to format as trace line. + */ + trace(message) { + const delta = Date.now() - this.lastTraceTime; + const prefix = `TRACE ${delta.toFixed(3)}`; + const traceMessage = `${prefix} ${message}`; + console.log(traceMessage); + this.traceLog += traceMessage + "\n"; + } + async returnTrace() { + try { + await navigator.clipboard.writeText(this.traceLog); + console.log("Text copied to clipboard!"); + } + catch (err) { + console.error("Failed to copy text:", err); + } + } + hexify(s) { + return Array.from(s) + .map((byte) => byte.toString(16).padStart(2, "0")) + .join("") + .padEnd(16, " "); + } + hexConvert(uint8Array, autoSplit = true) { + if (autoSplit && uint8Array.length > 16) { + let result = ""; + let s = uint8Array; + while (s.length > 0) { + const line = s.slice(0, 16); + const asciiLine = String.fromCharCode(...line) + .split("") + .map((c) => (c === " " || (c >= " " && c <= "~" && c !== " ") ? c : ".")) + .join(""); + s = s.slice(16); + result += `\n ${this.hexify(line.slice(0, 8))} ${this.hexify(line.slice(8))} | ${asciiLine}`; + } + return result; + } + else { + return this.hexify(uint8Array); + } + } + /** + * Format data packet using the Serial Line Internet Protocol (SLIP). + * @param {Uint8Array} data Binary unsigned 8 bit array data to format. + * @returns {Uint8Array} Formatted unsigned 8 bit data array. + */ + slipWriter(data) { + const outData = []; + outData.push(0xc0); + for (let i = 0; i < data.length; i++) { + if (data[i] === 0xdb) { + outData.push(0xdb, 0xdd); + } + else if (data[i] === 0xc0) { + outData.push(0xdb, 0xdc); + } + else { + outData.push(data[i]); + } + } + outData.push(0xc0); + return new Uint8Array(outData); + } + /** + * Write binary data to device using the WebSerial device writable stream. + * @param {Uint8Array} data 8 bit unsigned data array to write to device. + */ + async write(data) { + const outData = this.slipWriter(data); + if (this.device.writable) { + const writer = this.device.writable.getWriter(); + if (this.tracing) { + console.log("Write bytes"); + this.trace(`Write ${outData.length} bytes: ${this.hexConvert(outData)}`); + } + await writer.write(outData); + writer.releaseLock(); + } + } + /** + * Concatenate buffer2 to buffer1 and return the resulting ArrayBuffer. + * @param {ArrayBuffer} buffer1 First buffer to concatenate. + * @param {ArrayBuffer} buffer2 Second buffer to concatenate. + * @returns {ArrayBuffer} Result Array buffer. + */ + _appendBuffer(buffer1, buffer2) { + const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); + tmp.set(new Uint8Array(buffer1), 0); + tmp.set(new Uint8Array(buffer2), buffer1.byteLength); + return tmp.buffer; + } + /** + * Take a data array and return the first well formed packet after + * replacing the escape sequence. Reads at least 8 bytes. + * @param {Uint8Array} data Unsigned 8 bit array from the device read stream. + * @returns {Uint8Array} Formatted packet using SLIP escape sequences. + */ + slipReader(data) { + let i = 0; + let dataStart = 0, dataEnd = 0; + let state = "init"; + while (i < data.length) { + if (state === "init" && data[i] == 0xc0) { + dataStart = i + 1; + state = "valid_data"; + i++; + continue; + } + if (state === "valid_data" && data[i] == 0xc0) { + dataEnd = i - 1; + state = "packet_complete"; + break; + } + i++; + } + if (state !== "packet_complete") { + this.leftOver = data; + return new Uint8Array(0); + } + this.leftOver = data.slice(dataEnd + 2); + const tempPkt = new Uint8Array(dataEnd - dataStart + 1); + let j = 0; + for (i = dataStart; i <= dataEnd; i++, j++) { + if (data[i] === 0xdb && data[i + 1] === 0xdc) { + tempPkt[j] = 0xc0; + i++; + continue; + } + if (data[i] === 0xdb && data[i + 1] === 0xdd) { + tempPkt[j] = 0xdb; + i++; + continue; + } + tempPkt[j] = data[i]; + } + const packet = tempPkt.slice(0, j); /* Remove unused bytes due to escape seq */ + return packet; + } + /** + * Read from serial device using the device ReadableStream. + * @param {number} timeout Read timeout number + * @param {number} minData Minimum packet array length + * @returns {Uint8Array} 8 bit unsigned data array read from device. + */ + async read(timeout = 0, minData = 12) { + let t; + let packet = this.leftOver; + this.leftOver = new Uint8Array(0); + if (this.slipReaderEnabled) { + const valFinal = this.slipReader(packet); + if (valFinal.length > 0) { + return valFinal; + } + packet = this.leftOver; + this.leftOver = new Uint8Array(0); + } + if (this.device.readable == null) { + return this.leftOver; + } + this.reader = this.device.readable.getReader(); + try { + if (timeout > 0) { + t = setTimeout(() => { + if (this.reader) { + this.reader.cancel(); + } + }, timeout); + } + do { + const { value, done } = await this.reader.read(); + if (done) { + this.leftOver = packet; + throw new Error("Timeout"); + } + const p = new Uint8Array(this._appendBuffer(packet.buffer, value.buffer)); + packet = p; + } while (packet.length < minData); + } + finally { + if (timeout > 0) { + clearTimeout(t); + } + this.reader.releaseLock(); + } + if (this.tracing) { + console.log("Read bytes"); + this.trace(`Read ${packet.length} bytes: ${this.hexConvert(packet)}`); + } + if (this.slipReaderEnabled) { + const slipReaderResult = this.slipReader(packet); + if (this.tracing) { + console.log("Slip reader results"); + this.trace(`Read ${slipReaderResult.length} bytes: ${this.hexConvert(slipReaderResult)}`); + } + return slipReaderResult; + } + return packet; + } + /** + * Read from serial device without slip formatting. + * @param {number} timeout Read timeout in milliseconds (ms) + * @returns {Uint8Array} 8 bit unsigned data array read from device. + */ + async rawRead(timeout = 0) { + if (this.leftOver.length != 0) { + const p = this.leftOver; + this.leftOver = new Uint8Array(0); + return p; + } + if (!this.device.readable) { + return this.leftOver; + } + this.reader = this.device.readable.getReader(); + let t; + try { + if (timeout > 0) { + t = setTimeout(() => { + if (this.reader) { + this.reader.cancel(); + } + }, timeout); + } + const { value, done } = await this.reader.read(); + if (done) { + return value; + } + if (this.tracing) { + console.log("Raw Read bytes"); + this.trace(`Read ${value.length} bytes: ${this.hexConvert(value)}`); + } + return value; + } + finally { + if (timeout > 0) { + clearTimeout(t); + } + this.reader.releaseLock(); + } + } + /** + * Send the RequestToSend (RTS) signal to given state + * # True for EN=LOW, chip in reset and False EN=HIGH, chip out of reset + * @param {boolean} state Boolean state to set the signal + */ + async setRTS(state) { + await this.device.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._DTR_state); + } + /** + * Send the dataTerminalReady (DTS) signal to given state + * # True for IO0=LOW, chip in reset and False IO0=HIGH + * @param {boolean} state Boolean state to set the signal + */ + async setDTR(state) { + this._DTR_state = state; + await this.device.setSignals({ dataTerminalReady: state }); + } + /** + * Connect to serial device using the Webserial open method. + * @param {number} baud Number baud rate for serial connection. + * @param {typeof import("w3c-web-serial").SerialOptions} serialOptions Serial Options for WebUSB SerialPort class. + */ + async connect(baud = 115200, serialOptions = {}) { + await this.device.open({ + baudRate: baud, + dataBits: serialOptions === null || serialOptions === void 0 ? void 0 : serialOptions.dataBits, + stopBits: serialOptions === null || serialOptions === void 0 ? void 0 : serialOptions.stopBits, + bufferSize: serialOptions === null || serialOptions === void 0 ? void 0 : serialOptions.bufferSize, + parity: serialOptions === null || serialOptions === void 0 ? void 0 : serialOptions.parity, + flowControl: serialOptions === null || serialOptions === void 0 ? void 0 : serialOptions.flowControl, + }); + this.baudrate = baud; + this.leftOver = new Uint8Array(0); + } + async sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + /** + * Wait for a given timeout ms for serial device unlock. + * @param {number} timeout Timeout time in milliseconds (ms) to sleep + */ + async waitForUnlock(timeout) { + while ((this.device.readable && this.device.readable.locked) || + (this.device.writable && this.device.writable.locked)) { + await this.sleep(timeout); + } + } + /** + * Disconnect from serial device by running SerialPort.close() after streams unlock. + */ + async disconnect() { + var _a, _b; + if ((_a = this.device.readable) === null || _a === void 0 ? void 0 : _a.locked) { + await ((_b = this.reader) === null || _b === void 0 ? void 0 : _b.cancel()); + } + await this.waitForUnlock(400); + this.reader = undefined; + await this.device.close(); + } +} +export { Transport };