Skip to content

Commit 7e392d5

Browse files
committed
add s3 h2 support for USB_RAM_BLOCK
1 parent 1fa3416 commit 7e392d5

6 files changed

Lines changed: 119 additions & 4 deletions

File tree

src/esploader.ts

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { ESPError } from "./types/error.js";
22
import { Data, deflate, Inflate } from "pako";
3-
import { Transport, SerialOptions } from "./webserial.js";
3+
import {
4+
Transport,
5+
SerialOptions,
6+
ESPRESSIF_VID as ESPRESSIF_USB_VID,
7+
USB_JTAG_SERIAL_PID as ESPRESSIF_USB_JTAG_SERIAL_PID,
8+
} from "./webserial.js";
49
import { ROM } from "./targets/rom.js";
510
import { ClassicReset, CustomReset, HardReset, ResetConstructors, ResetStrategy, UsbJtagSerialReset } from "./reset.js";
611
import { getStubJsonByChipName } from "./stubFlasher.js";
@@ -159,7 +164,8 @@ export class ESPLoader {
159164
0x3a: "64MB",
160165
};
161166

162-
USB_JTAG_SERIAL_PID = 0x1001;
167+
ESPRESSIF_VID = ESPRESSIF_USB_VID;
168+
USB_JTAG_SERIAL_PID = ESPRESSIF_USB_JTAG_SERIAL_PID;
163169

164170
chip!: ROM;
165171
IS_STUB: boolean;
@@ -585,6 +591,71 @@ export class ESPLoader {
585591
return lastError;
586592
}
587593

594+
/**
595+
* True if the host sees this port as Espressif USB Serial/JTAG (VID/PID match).
596+
* Falls back to the chip UARTDEV_BUF_NO helper when Web Serial omits IDs
597+
* or the USB product ID was customized.
598+
*/
599+
async usesUsbJtagSerial(): Promise<boolean> {
600+
const vid = this.transport.getVid();
601+
const pid = this.transport.getPid();
602+
if (vid === this.ESPRESSIF_VID && pid === this.USB_JTAG_SERIAL_PID) {
603+
return true;
604+
}
605+
if (vid === this.ESPRESSIF_VID && pid === this.chip.IMAGE_CHIP_ID) {
606+
return false;
607+
}
608+
if (vid !== undefined && vid !== this.ESPRESSIF_VID) {
609+
return false;
610+
}
611+
if (typeof this.chip.usesUsbJtagSerial === "function") {
612+
return await this.chip.usesUsbJtagSerial(this);
613+
}
614+
return false;
615+
}
616+
617+
/**
618+
* True if the host sees this port as Espressif USB-OTG (VID/PID match).
619+
* Falls back to the chip UARTDEV_BUF_NO helper when Web Serial omits IDs
620+
* or the USB product ID was customized.
621+
*/
622+
async usesUsbOtg(): Promise<boolean> {
623+
const vid = this.transport.getVid();
624+
const pid = this.transport.getPid();
625+
if (vid === this.ESPRESSIF_VID && this.chip.IMAGE_CHIP_ID != null && pid === this.chip.IMAGE_CHIP_ID) {
626+
return true;
627+
}
628+
if (vid === this.ESPRESSIF_VID && pid === this.USB_JTAG_SERIAL_PID) {
629+
return false;
630+
}
631+
if (vid !== undefined && vid !== this.ESPRESSIF_VID) {
632+
return false;
633+
}
634+
if (typeof this.chip.usesUsbOtg === "function") {
635+
return await this.chip.usesUsbOtg(this);
636+
}
637+
if (typeof this.chip.usingUsbOtg === "function") {
638+
return await this.chip.usingUsbOtg(this);
639+
}
640+
return false;
641+
}
642+
643+
/**
644+
* Cap FLASH_WRITE_SIZE to USB_RAM_BLOCK when the stub is talking over
645+
* USB-OTG. Matches esptool.py's stub USB buffer limit; USB-Serial/JTAG
646+
* and USB-UART bridges keep the 16 KB default.
647+
*/
648+
private async applyUsbFlashWriteSize() {
649+
const usbRamBlock = this.chip.USB_RAM_BLOCK;
650+
if (!usbRamBlock) {
651+
return;
652+
}
653+
if (await this.usesUsbOtg()) {
654+
this.FLASH_WRITE_SIZE = usbRamBlock;
655+
this.debug(`Using USB_RAM_BLOCK (0x${usbRamBlock.toString(16)}) for FLASH_WRITE_SIZE (USB-OTG)`);
656+
}
657+
}
658+
588659
/**
589660
* Constructs a sequence of reset strategies based on the OS,
590661
* used ESP chip, external settings, and environment variables.
@@ -1272,6 +1343,8 @@ export class ESPLoader {
12721343
async runStub(): Promise<ROM> {
12731344
if (this.syncStubDetected) {
12741345
this.info("Stub is already running. No upload is necessary.");
1346+
this.IS_STUB = true;
1347+
await this.applyUsbFlashWriteSize();
12751348
return this.chip;
12761349
}
12771350

@@ -1311,6 +1384,7 @@ export class ESPLoader {
13111384

13121385
this.info("Stub running...");
13131386
this.IS_STUB = true;
1387+
await this.applyUsbFlashWriteSize();
13141388
return this.chip;
13151389
}
13161390

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export {
99
ResetStrategy,
1010
} from "./reset.js";
1111
export { ROM } from "./targets/rom.js";
12-
export { Transport, SerialOptions } from "./webserial.js";
12+
export { Transport, SerialOptions, ESPRESSIF_VID, USB_JTAG_SERIAL_PID } from "./webserial.js";
1313
export { decodeBase64Data, getStubJsonByChipName, Stub } from "./stubFlasher.js";
1414
export { LoaderOptions } from "./types/loaderOptions.js";
1515
export { FlashOptions } from "./types/flashOptions.js";

src/targets/esp32h2.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ export class ESP32H2ROM extends ESP32C6ROM {
9494
}
9595
}
9696

97+
public async usesUsbJtagSerial(loader: ESPLoader): Promise<boolean> {
98+
const bufNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff;
99+
return bufNo === this.UARTDEV_BUF_NO_USB;
100+
}
101+
97102
public async readMac(loader: ESPLoader) {
98103
let mac0 = await loader.readReg(this.MAC_EFUSE_REG);
99104
mac0 = mac0 >>> 0;

src/targets/esp32s3.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,11 @@ export class ESP32S3ROM extends ESP32ROM {
207207
}
208208
}
209209

210+
public async usesUsbJtagSerial(loader: ESPLoader): Promise<boolean> {
211+
const bufNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff;
212+
return bufNo === this.UARTDEV_BUF_NO_USB;
213+
}
214+
210215
public async readMac(loader: ESPLoader) {
211216
let mac0 = await loader.readReg(this.MAC_EFUSE_REG);
212217
mac0 = mac0 >>> 0;

src/targets/rom.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,21 @@ export abstract class ROM {
6767
*/
6868
postConnect?(loader: ESPLoader): Promise<void>;
6969

70+
/**
71+
* True if the ROM is talking over USB-OTG (UARTDEV_BUF_NO fallback).
72+
*/
73+
usesUsbOtg?(loader: ESPLoader): Promise<boolean>;
74+
75+
/**
76+
* True if the ROM is talking over USB-OTG (ESP32-S2 naming).
77+
*/
78+
usingUsbOtg?(loader: ESPLoader): Promise<boolean>;
79+
80+
/**
81+
* True if the ROM is talking over USB-Serial/JTAG (UARTDEV_BUF_NO fallback).
82+
*/
83+
usesUsbJtagSerial?(loader: ESPLoader): Promise<boolean>;
84+
7085
/**
7186
* Get the chip erase size.
7287
* @param {number} offset - Offset to start erase.
@@ -101,7 +116,8 @@ export abstract class ROM {
101116
// abstract EFUSE_RD_REG_BASE: number; //esp32
102117

103118
abstract FLASH_WRITE_SIZE: number;
104-
// abstract IMAGE_CHIP_ID: number; // not in esp8266
119+
IMAGE_CHIP_ID?: number; // not in esp8266
120+
USB_RAM_BLOCK?: number; // max SLIP payload over native USB (USB-OTG / USB-Serial/JTAG)
105121
abstract SPI_MOSI_DLEN_OFFS: number; // not in esp8266
106122
abstract SPI_MISO_DLEN_OFFS: number; // not in esp8266
107123
abstract SPI_REG_BASE: number;

src/webserial.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
/* global SerialPort, ParityType, FlowControlType */
22

33
import { sleep } from "./util";
4+
5+
/** Espressif USB vendor ID used by native USB-Serial/JTAG and USB-OTG. */
6+
export const ESPRESSIF_VID = 0x303a;
7+
8+
/** Default USB product ID for Espressif USB-Serial/JTAG. */
9+
export const USB_JTAG_SERIAL_PID = 0x1001;
10+
411
/**
512
* Options for device serialPort.
613
* @interface SerialOptions
@@ -98,6 +105,14 @@ class Transport {
98105
: "";
99106
}
100107

108+
/**
109+
* Request the serial device vendor id from SerialPortInfo.
110+
* @returns {number | undefined} Return the vendor ID.
111+
*/
112+
getVid(): number | undefined {
113+
return this.device.getInfo().usbVendorId;
114+
}
115+
101116
/**
102117
* Request the serial device product id from SerialPortInfo.
103118
* @returns {number | undefined} Return the product ID.

0 commit comments

Comments
 (0)