Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 76 additions & 2 deletions src/esploader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { ESPError } from "./types/error.js";
import { Data, deflate, Inflate } from "pako";
import { Transport, SerialOptions } from "./webserial.js";
import {
Transport,
SerialOptions,
ESPRESSIF_VID as ESPRESSIF_USB_VID,
USB_JTAG_SERIAL_PID as ESPRESSIF_USB_JTAG_SERIAL_PID,
} from "./webserial.js";
import { ROM } from "./targets/rom.js";
import { ClassicReset, CustomReset, HardReset, ResetConstructors, ResetStrategy, UsbJtagSerialReset } from "./reset.js";
import { getStubJsonByChipName } from "./stubFlasher.js";
Expand Down Expand Up @@ -159,7 +164,8 @@
0x3a: "64MB",
};

USB_JTAG_SERIAL_PID = 0x1001;
ESPRESSIF_VID = ESPRESSIF_USB_VID;
USB_JTAG_SERIAL_PID = ESPRESSIF_USB_JTAG_SERIAL_PID;

chip!: ROM;
IS_STUB: boolean;
Expand Down Expand Up @@ -585,6 +591,71 @@
return lastError;
}

/**

Check warning on line 594 in src/esploader.ts

View workflow job for this annotation

GitHub Actions / ci

Missing JSDoc @returns declaration
* True if the host sees this port as Espressif USB Serial/JTAG (VID/PID match).
* Falls back to the chip UARTDEV_BUF_NO helper when Web Serial omits IDs
* or the USB product ID was customized.
*/
async usesUsbJtagSerial(): Promise<boolean> {
const vid = this.transport.getVid();
const pid = this.transport.getPid();
if (vid === this.ESPRESSIF_VID && pid === this.USB_JTAG_SERIAL_PID) {
return true;
}
if (vid === this.ESPRESSIF_VID && pid === this.chip.IMAGE_CHIP_ID) {
return false;
}
if (vid !== undefined && vid !== this.ESPRESSIF_VID) {
return false;
}
if (typeof this.chip.usesUsbJtagSerial === "function") {
return await this.chip.usesUsbJtagSerial(this);
}
return false;
}

/**

Check warning on line 617 in src/esploader.ts

View workflow job for this annotation

GitHub Actions / ci

Missing JSDoc @returns declaration
* True if the host sees this port as Espressif USB-OTG (VID/PID match).
* Falls back to the chip UARTDEV_BUF_NO helper when Web Serial omits IDs
* or the USB product ID was customized.
*/
async usesUsbOtg(): Promise<boolean> {
const vid = this.transport.getVid();
const pid = this.transport.getPid();
if (vid === this.ESPRESSIF_VID && this.chip.IMAGE_CHIP_ID != null && pid === this.chip.IMAGE_CHIP_ID) {
return true;
}
if (vid === this.ESPRESSIF_VID && pid === this.USB_JTAG_SERIAL_PID) {
return false;
}
if (vid !== undefined && vid !== this.ESPRESSIF_VID) {
return false;
}
if (typeof this.chip.usesUsbOtg === "function") {
return await this.chip.usesUsbOtg(this);
}
if (typeof this.chip.usingUsbOtg === "function") {
return await this.chip.usingUsbOtg(this);
}
return false;
}

/**
* Cap FLASH_WRITE_SIZE to USB_RAM_BLOCK when the stub is talking over
* USB-OTG. Matches esptool.py's stub USB buffer limit; USB-Serial/JTAG
* and USB-UART bridges keep the 16 KB default.
*/
private async applyUsbFlashWriteSize() {
const usbRamBlock = this.chip.USB_RAM_BLOCK;
if (!usbRamBlock) {
return;
}
if (await this.usesUsbOtg()) {
this.FLASH_WRITE_SIZE = usbRamBlock;
this.debug(`Using USB_RAM_BLOCK (0x${usbRamBlock.toString(16)}) for FLASH_WRITE_SIZE (USB-OTG)`);
}
}

/**
* Constructs a sequence of reset strategies based on the OS,
* used ESP chip, external settings, and environment variables.
Expand Down Expand Up @@ -1272,6 +1343,8 @@
async runStub(): Promise<ROM> {
if (this.syncStubDetected) {
this.info("Stub is already running. No upload is necessary.");
this.IS_STUB = true;
await this.applyUsbFlashWriteSize();
return this.chip;
}

Expand Down Expand Up @@ -1311,6 +1384,7 @@

this.info("Stub running...");
this.IS_STUB = true;
await this.applyUsbFlashWriteSize();
return this.chip;
}

Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export {
ResetStrategy,
} from "./reset.js";
export { ROM } from "./targets/rom.js";
export { Transport, SerialOptions } from "./webserial.js";
export { Transport, SerialOptions, ESPRESSIF_VID, USB_JTAG_SERIAL_PID } from "./webserial.js";
export { decodeBase64Data, getStubJsonByChipName, Stub } from "./stubFlasher.js";
export { LoaderOptions } from "./types/loaderOptions.js";
export { FlashOptions } from "./types/flashOptions.js";
Expand Down
5 changes: 5 additions & 0 deletions src/targets/esp32h2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ export class ESP32H2ROM extends ESP32C6ROM {
}
}

public async usesUsbJtagSerial(loader: ESPLoader): Promise<boolean> {
const bufNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff;
return bufNo === this.UARTDEV_BUF_NO_USB;
}

public async readMac(loader: ESPLoader) {
let mac0 = await loader.readReg(this.MAC_EFUSE_REG);
mac0 = mac0 >>> 0;
Expand Down
5 changes: 5 additions & 0 deletions src/targets/esp32s3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ export class ESP32S3ROM extends ESP32ROM {
}
}

public async usesUsbJtagSerial(loader: ESPLoader): Promise<boolean> {
const bufNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff;
return bufNo === this.UARTDEV_BUF_NO_USB;
}

public async readMac(loader: ESPLoader) {
let mac0 = await loader.readReg(this.MAC_EFUSE_REG);
mac0 = mac0 >>> 0;
Expand Down
18 changes: 17 additions & 1 deletion src/targets/rom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ export abstract class ROM {
*/
postConnect?(loader: ESPLoader): Promise<void>;

/**
* True if the ROM is talking over USB-OTG (UARTDEV_BUF_NO fallback).
*/
usesUsbOtg?(loader: ESPLoader): Promise<boolean>;

/**
* True if the ROM is talking over USB-OTG (ESP32-S2 naming).
*/
usingUsbOtg?(loader: ESPLoader): Promise<boolean>;

/**
* True if the ROM is talking over USB-Serial/JTAG (UARTDEV_BUF_NO fallback).
*/
usesUsbJtagSerial?(loader: ESPLoader): Promise<boolean>;

/**
* Get the chip erase size.
* @param {number} offset - Offset to start erase.
Expand Down Expand Up @@ -101,7 +116,8 @@ export abstract class ROM {
// abstract EFUSE_RD_REG_BASE: number; //esp32

abstract FLASH_WRITE_SIZE: number;
// abstract IMAGE_CHIP_ID: number; // not in esp8266
IMAGE_CHIP_ID?: number; // not in esp8266
USB_RAM_BLOCK?: number; // max SLIP payload over native USB (USB-OTG / USB-Serial/JTAG)
abstract SPI_MOSI_DLEN_OFFS: number; // not in esp8266
abstract SPI_MISO_DLEN_OFFS: number; // not in esp8266
abstract SPI_REG_BASE: number;
Expand Down
15 changes: 15 additions & 0 deletions src/webserial.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
/* global SerialPort, ParityType, FlowControlType */

import { sleep } from "./util";

/** Espressif USB vendor ID used by native USB-Serial/JTAG and USB-OTG. */
export const ESPRESSIF_VID = 0x303a;

/** Default USB product ID for Espressif USB-Serial/JTAG. */
export const USB_JTAG_SERIAL_PID = 0x1001;

/**
* Options for device serialPort.
* @interface SerialOptions
Expand Down Expand Up @@ -98,6 +105,14 @@ class Transport {
: "";
}

/**
* Request the serial device vendor id from SerialPortInfo.
* @returns {number | undefined} Return the vendor ID.
*/
getVid(): number | undefined {
return this.device.getInfo().usbVendorId;
}

/**
* Request the serial device product id from SerialPortInfo.
* @returns {number | undefined} Return the product ID.
Expand Down
Loading