Skip to content

Instantly share code, notes, and snippets.

@nuta
Last active February 23, 2023 05:06
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save nuta/2c70ba8855f50c536a51f0c5993c1e4c to your computer and use it in GitHub Desktop.
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

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
Copy link
Author

nuta commented Mar 20, 2019

@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

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

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

@nuta
Copy link
Author

nuta commented Jul 29, 2019

@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
Copy link
Author

nuta commented Jul 29, 2019

@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

@nuta
Copy link
Author

nuta commented Jul 29, 2019

@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
Copy link
Author

nuta commented Jul 29, 2019

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

Thank you for sharing! It looks interesting :)

@AlexFundorin
Copy link

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

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

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
Copy link

beckmx commented Aug 14, 2019

@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