Skip to content

Instantly share code, notes, and snippets.

@nuta
Last active June 14, 2024 01:03
Show Gist options
  • Select an option

  • Save nuta/2c70ba8855f50c536a51f0c5993c1e4c to your computer and use it in GitHub Desktop.

Select an option

Save nuta/2c70ba8855f50c536a51f0c5993c1e4c to your computer and use it in GitHub Desktop.
CP2102 (used by ESP32-DevKitC) WebUSB device driver (deprecated: use Serial API instead: https://crbug.com/884928)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>esptool.js</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xterm/2.9.2/xterm.min.js" integrity="sha256-8rsVcpCnO6HdeJL84i0VdubjM42fjSmO8aONghdq3gc=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/xterm/2.9.2/xterm.min.css" integrity="sha256-w69o8Y6P5VZjfYFmn2KlqMU7TUi2I+oWObi8FLlVZZg=" crossorigin="anonymous" />
</head>
<body>
<h1>esptool.js</h1>
<button id="flash-button" style="padding: 30px; font-size: 40px">Flash</button>
<div id="serial"></div>
<script src="esptool.js"></script>
<script>
const term = new Terminal()
term.open(document.querySelector("#serial"))
document.querySelector("#flash-button").addEventListener("click", () => {
const esp = new Esptool()
esp.connect().then(() => {
const receive = () => {
esp.serial.read().then(data => {
const s = String.fromCharCode.apply(null, new Uint8Array(data))
term.write(s)
receive()
})
}
receive()
})
})
</script>
</body>
</html>
const { Serial } = require("./serial")
class Esptool {
constructor() {
this.serial = new Serial()
}
connect() {
return this.serial.connect().then(() => {
return this.serial.initialize()
})
}
async flash() {
}
}
if (window) {
// Web browser
window.Esptool = Esptool;
}
{
"name": "esptool.js",
"version": "0.0.1",
"description": "Esptool implemented for Node.js and web browsers.",
"main": "lib/index.js",
"repository": "https://github.com/seiyanuta/esptool.js",
"author": "Seiya Nuta <nuta@seiya.me>",
"license": "(CC0-1.0 OR MIT)",
"devDependencies": {
"copy-webpack-plugin": "^4.3.1",
"webpack": "^3.10.0",
"webpack-dev-server": "^2.11.1"
}
}
class Serial {
constructor() {
this.usb = null
}
connect() {
const filters = [
{ 'vendorId': 0x10c4, 'productId': 0xea60 }
]
return navigator.usb.getDevices().then(devices => {
if (devices.length > 0) {
const usb = devices[0]
this.usb = usb
return usb
} else {
return navigator.usb.requestDevice({ filters }).then(usb => {
this.usb = usb
return usb
})
}
})
}
initialize() {
return this.usb.open()
.then(() => {
return this.usb.selectConfiguration(1)
})
.then(() => {
console.log(this.usb)
return this.usb.claimInterface(0)
})
.then(() => {
return this.usb.controlTransferOut({
requestType: 'vendor',
recipient: 'device',
request: 0x00,
index: 0x00,
value: 0x01
})
})
.then(() => {
return this.usb.controlTransferOut({
requestType: 'vendor',
recipient: 'device',
request: 0x07,
index: 0x00,
value: 0x03 | 0x0100 | 0x0200
})
})
.then(() => {
return this.usb.controlTransferOut({
requestType: 'vendor',
recipient: 'device',
request: 0x01,
index: 0x00,
value: 0x384000 / 115200
})
})
}
async read() {
const r = await this.usb.transferIn(1, 64)
return new Uint8Array(r.data.buffer)
}
async write(data) {
await this.usb.transferIn(1, data)
}
}
module.exports = { Serial }
const path = require("path")
module.exports = {
entry: {
app: ["./index.js"]
},
output: {
path: __dirname,
publicPath: "/",
filename: "esptool.js"
}
};
@ChristopherLaytonWasTakenSoIWentWithT

Copy link
Copy Markdown

Hey,
Thank you for this GIST! It helped me through a big blocker.
Quick question if you have the time:
Where/how did you learn the setup for the series of control transfer out calls to get it all working?
Would love to learn any debug tips or tricks with this stuff!

Thank you,
FeedDahBirds

@nuta

nuta commented Mar 20, 2019

Copy link
Copy Markdown
Author

@FeedDahBirds IIRC I read its Linux device driver. Maybe this would be helpful: https://github.com/torvalds/linux/blob/master/drivers/usb/serial/cp210x.c

@vanminh0910

Copy link
Copy Markdown

Your sharing is great and this will make ESP32 programming so interesting with Web. Unfortunately I cannot make it working, Chrome does not detect any device when I click Flash button even though the ESP32 DevKit is connected. Any tip to debug?

@AlexFundorin

Copy link
Copy Markdown

Could you, please, explain in a couple of words, what is the purpose of this index.html?

@nuta

nuta commented Jul 29, 2019

Copy link
Copy Markdown
Author

@vanminh0910 I've tried just now but it doesn't work for me. I'd recommend to use Serial API instead. It's way better than this gist.

@nuta

nuta commented Jul 29, 2019

Copy link
Copy Markdown
Author

@vanminh0910 If you want to flash a firmware, in addition to the serial device driver like this, you'll need to implement esptool protocol. ESP32 programming on the web sounds really exciting to me, but unfortunately I have no time to work on it for now.

@AlexFundorin

Copy link
Copy Markdown

@nuta

nuta commented Jul 29, 2019

Copy link
Copy Markdown
Author

@AlexFundorin It seems it no longer work though, index.html instantiates xterm.js (for printing colored device messages) and writes received data into it.

@nuta

nuta commented Jul 29, 2019

Copy link
Copy Markdown
Author

@seiyanuta this - https://github.com/scottchiefbaker/ESP-WebOTA

Thank you for sharing! It looks interesting :)

@AlexFundorin

Copy link
Copy Markdown

I'm already using it in my project. Well, it's working, yet I'm still updating firmware directly from VSCode, using OTA.

@vanminh0910

Copy link
Copy Markdown

This device (https://yolostem.com) using esp32 supports web programming using webusb API which is available on Chrome already, but not Serial API. Here is its programming page https://lab.yolostem.com. Sadly the homepage is mainly in Vietnamese.

@AlexFundorin

Copy link
Copy Markdown

I'm mostly interested in uploading firmware to a second Arduino board via ESP32.
Don't see much point in the actual programming, using webusb.

@beckmx

beckmx commented Aug 14, 2019

Copy link
Copy Markdown

@vanminh0910 looks to me that the device is using an atmega chip inside that translates the webusb, I looked at the files and found this https://lab.yolostem.com/assets/webusb.js, inside the vendorID is 0x2341 which corresponds to the arduino.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment