initial commit
This commit is contained in:
commit
b1c5c4aa26
|
|
@ -0,0 +1,469 @@
|
|||
<script lang="ts">
|
||||
|
||||
interface Navigator {
|
||||
serial: {
|
||||
// Define the methods and properties you need from the Web Serial API
|
||||
// For example:
|
||||
requestPort: (options?: SerialPortRequestOptions) => Promise<SerialPort>;
|
||||
getPorts: () => Promise<SerialPort[]>;
|
||||
// Add other properties and methods as needed
|
||||
};
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import 'xterm/css/xterm.css';
|
||||
import {onMounted, reactive, ref, watch} from "vue";
|
||||
import {ESPLoader, type FlashOptions, type IEspLoaderTerminal, type LoaderOptions, Transport} from "./lib_esptools-js";
|
||||
import CryptoJS from "crypto-js";
|
||||
import {useData} from 'vitepress';
|
||||
|
||||
const terminalContainer = ref();
|
||||
let terminal: any;
|
||||
let fitAddon: any;
|
||||
const isDarkMode = useData().isDark;
|
||||
|
||||
watch(isDarkMode, value => {
|
||||
|
||||
});
|
||||
|
||||
const terminalConfig = {
|
||||
theme: {
|
||||
background: '#4b4b4b', // dark gray background
|
||||
foreground: '#c5c8c6', // light gray text
|
||||
cursor: '#f0c674', // yellow cursor
|
||||
// You can also set specific ANSI colors if needed
|
||||
black: '#1d1f21',
|
||||
red: '#cc6666',
|
||||
convertEol: true,
|
||||
// ...and so on for other colors
|
||||
}
|
||||
}
|
||||
|
||||
const notSupportedMsg = "您的浏览器不支持虚拟串口,请使用电脑版Chrome或者Edge。"
|
||||
|
||||
onMounted(async () => {
|
||||
if (!('serial' in navigator)) {
|
||||
alert(notSupportedMsg);
|
||||
console.log("Serial not supported");
|
||||
} else {
|
||||
console.log("serial ok");
|
||||
serialSupported.value = true;
|
||||
const { Terminal } = await import('xterm');
|
||||
const { FitAddon } = await import('xterm-addon-fit');
|
||||
fitAddon = new FitAddon();
|
||||
terminal = new Terminal(terminalConfig);
|
||||
terminal.loadAddon(fitAddon);
|
||||
|
||||
// Initialize the terminal
|
||||
// terminal.open(terminalContainer.value);
|
||||
terminal.open(terminalContainer.value);
|
||||
fitAddon.fit();
|
||||
|
||||
// You can write some data to the terminal or set up your own handlers here
|
||||
terminal.writeln('请选择一个固件,连接后烧录。');
|
||||
|
||||
const terminalResizeObserver = new ResizeObserver(() => {
|
||||
fitAddon.fit();
|
||||
})
|
||||
|
||||
terminalResizeObserver.observe(terminalContainer.value);
|
||||
}
|
||||
});
|
||||
|
||||
const chip = ref("");
|
||||
const programBaud = ref("115200");
|
||||
const programBaudOption = [
|
||||
{text: '115200', value: '115200'},
|
||||
{text: '230400', value: '230400'},
|
||||
{text: '460800', value: '460800'},
|
||||
{text: '921600', value: '921600'},
|
||||
]
|
||||
|
||||
const connectedBaud = ref("")
|
||||
const isConnected = ref(false)
|
||||
const serialSupported = ref(false);
|
||||
|
||||
const imageOption = [
|
||||
{
|
||||
value: 'wireless_tools_v0.3.0_esp32c3.bin',
|
||||
link: '/downloads/wireless_proxy_v0.3.0_esp32c3.bin'
|
||||
},
|
||||
]
|
||||
const imageSelect = ref(imageOption[0]);
|
||||
|
||||
let transport: Transport | null;
|
||||
|
||||
let esploader: ESPLoader;
|
||||
|
||||
const espLoaderTerminal: IEspLoaderTerminal = {
|
||||
clean() {
|
||||
terminal.clear();
|
||||
},
|
||||
writeLine(data) {
|
||||
terminal.writeln(data);
|
||||
},
|
||||
write(data) {
|
||||
terminal.write(data);
|
||||
},
|
||||
};
|
||||
|
||||
async function programConnect() {
|
||||
if (chip.value === "") {
|
||||
let port = await navigator.serial.requestPort({});
|
||||
transport = new Transport(port, true);
|
||||
}
|
||||
|
||||
if (!transport) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const flashOptions: LoaderOptions = {
|
||||
transport,
|
||||
romBaudrate: 115200,
|
||||
baudrate: parseInt(programBaud.value),
|
||||
terminal: espLoaderTerminal,
|
||||
};
|
||||
esploader = new ESPLoader(flashOptions);
|
||||
|
||||
chip.value = await esploader.main();
|
||||
connectedBaud.value = programBaud.value;
|
||||
isConnected.value = true;
|
||||
|
||||
// Temporarily broken
|
||||
// await esploader.flashId();
|
||||
} catch (error) {
|
||||
let message = "";
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
console.error(error);
|
||||
terminal.writeln(`Error: ${message}`);
|
||||
}
|
||||
|
||||
binaryLoadStatus.status = "";
|
||||
binaryLoadStatus.progress = 0;
|
||||
console.log("Settings done for :" + chip.value);
|
||||
}
|
||||
|
||||
function cleanUp() {
|
||||
transport = null;
|
||||
chip.value = "";
|
||||
}
|
||||
|
||||
// async function consoleConnectBtn() {
|
||||
// if (transport) {
|
||||
// await transport.disconnect();
|
||||
// await transport.waitForUnlock(1500);
|
||||
// }
|
||||
// terminal.reset();
|
||||
// cleanUp();
|
||||
// }
|
||||
//
|
||||
// async function consoleResetBtn() {
|
||||
//
|
||||
// }
|
||||
|
||||
interface IBinImage {
|
||||
data: string;
|
||||
address: number;
|
||||
}
|
||||
|
||||
function arrayBufferToBinaryString(buffer: ArrayBuffer) {
|
||||
const byteArray = new Uint8Array(buffer);
|
||||
let binaryString = '';
|
||||
byteArray.forEach((byte) => {
|
||||
binaryString += String.fromCharCode(byte);
|
||||
});
|
||||
return binaryString;
|
||||
}
|
||||
|
||||
async function loadBinaryFile_back(imageLink: string) {
|
||||
try {
|
||||
const response = await fetch(imageLink);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
return await response.blob();
|
||||
} catch (error) {
|
||||
console.error('Error fetching the binary file:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/* cache the last binary, prevent user spam download */
|
||||
const lastLoadedBinary = {
|
||||
link: "",
|
||||
blob: new Blob(),
|
||||
}
|
||||
const binaryLoadStatus = reactive({
|
||||
status: "未连接",
|
||||
progress: 0,
|
||||
});
|
||||
|
||||
function updateProgress(loaded: number, total: number) {
|
||||
binaryLoadStatus.progress = Math.round((loaded / total) * 100);
|
||||
}
|
||||
|
||||
async function loadBinaryFile(imageLink: string) {
|
||||
if (lastLoadedBinary.link === imageLink) {
|
||||
return lastLoadedBinary.blob;
|
||||
}
|
||||
|
||||
try {
|
||||
binaryLoadStatus.progress = 0;
|
||||
binaryLoadStatus.status = "固件下载中";
|
||||
const response = await fetch(imageLink);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
|
||||
const contentLength = response.headers.get('content-length');
|
||||
if (!contentLength) {
|
||||
throw new Error('Content-Length header is missing');
|
||||
}
|
||||
|
||||
const total = parseInt(contentLength, 10);
|
||||
let loaded = 0;
|
||||
|
||||
// Stream response body
|
||||
const reader = response.body.getReader();
|
||||
let chunks = []; // to store chunks of data
|
||||
let receivedLength = 0; // received that many bytes at the moment
|
||||
|
||||
while(true) {
|
||||
const {done, value} = await reader.read();
|
||||
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
|
||||
chunks.push(value);
|
||||
receivedLength += value.length;
|
||||
|
||||
// report progress
|
||||
loaded += value.length;
|
||||
updateProgress(loaded, total);
|
||||
}
|
||||
|
||||
// Concatenate chunks into single Uint8Array
|
||||
let chunksAll = new Uint8Array(receivedLength);
|
||||
let position = 0;
|
||||
for(let chunk of chunks) {
|
||||
chunksAll.set(chunk, position);
|
||||
position += chunk.length;
|
||||
}
|
||||
|
||||
lastLoadedBinary.link = imageLink;
|
||||
lastLoadedBinary.blob = new Blob([chunksAll]); // Convert to blob
|
||||
binaryLoadStatus.status = "固件下载完成";
|
||||
return lastLoadedBinary.blob;
|
||||
} catch (error) {
|
||||
binaryLoadStatus.status = "固件下载错误";
|
||||
console.error('Error fetching the binary file:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function programFlash() {
|
||||
const fileArray: IBinImage[] = [];
|
||||
|
||||
const blob = await loadBinaryFile(imageSelect.value.link);
|
||||
|
||||
console.log(blob);
|
||||
if (blob && blob.size > 100000) {
|
||||
let data = arrayBufferToBinaryString(await blob.arrayBuffer());
|
||||
|
||||
fileArray.push({
|
||||
data: data,
|
||||
address: 0x0,
|
||||
});
|
||||
} else {
|
||||
alert("???");
|
||||
return;
|
||||
}
|
||||
binaryLoadStatus.status = "固件烧录中";
|
||||
try {
|
||||
const flashOptions: FlashOptions = {
|
||||
fileArray: fileArray,
|
||||
flashSize: "keep",
|
||||
eraseAll: false,
|
||||
compress: true,
|
||||
flashMode: "DIO",
|
||||
flashFreq: programBaud.value,
|
||||
reportProgress: (fileIndex, written, total) => {
|
||||
updateProgress(written, total);
|
||||
console.log(fileIndex, written, total);
|
||||
},
|
||||
calculateMD5Hash: (image) => {
|
||||
const hash = CryptoJS.MD5(CryptoJS.enc.Latin1.parse(image));
|
||||
return hash.toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
};
|
||||
await esploader.writeFlash(flashOptions);
|
||||
} catch (e) {
|
||||
let message = "";
|
||||
if (e instanceof Error) {
|
||||
message = e.message;
|
||||
terminal.writeln(`Error: ${message}`);
|
||||
}
|
||||
console.error(e);
|
||||
}
|
||||
binaryLoadStatus.status = "固件烧录完成";
|
||||
terminal.writeln("烧录完成,请断开连接,手动重启");
|
||||
await resetClick();
|
||||
}
|
||||
|
||||
async function programErase() {
|
||||
try {
|
||||
await esploader.eraseFlash();
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
terminal.writeln(`Error: ${e?.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function programDisconnect() {
|
||||
if (transport) {
|
||||
await transport.disconnect();
|
||||
await transport.waitForUnlock(1500);
|
||||
}
|
||||
|
||||
isConnected.value = false;
|
||||
chip.value = "";
|
||||
connectedBaud.value = "";
|
||||
binaryLoadStatus.status = "未连接";
|
||||
terminal.reset();
|
||||
}
|
||||
|
||||
async function resetClick() {
|
||||
if (transport) {
|
||||
await transport.setDTR(false);
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
await transport.setDTR(true);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleFileChange(e: Event) {
|
||||
const target = e.target as HTMLInputElement
|
||||
const files = target.files
|
||||
const fileArray: IBinImage[] = [];
|
||||
|
||||
const blob = await loadBinaryFile(imageSelect.value.link);
|
||||
if (blob) {
|
||||
|
||||
let data = arrayBufferToBinaryString(await blob.arrayBuffer());
|
||||
console.log(blob.size, data);
|
||||
}
|
||||
|
||||
if (files && files.length > 0) {
|
||||
const file = files[0];
|
||||
|
||||
let data: string = arrayBufferToBinaryString(await file.arrayBuffer());
|
||||
fileArray.push({
|
||||
data: data,
|
||||
address: 0x0,
|
||||
})
|
||||
console.log(file, data);
|
||||
}
|
||||
}
|
||||
|
||||
const customColors = [
|
||||
{ color: '#f56c6c', percentage: 20 },
|
||||
{ color: '#f5816c', percentage: 30 },
|
||||
{ color: '#e6a23c', percentage: 40 },
|
||||
{ color: '#e6be3c', percentage: 60 },
|
||||
{ color: '#d5e63c', percentage: 80 },
|
||||
{ color: '#ade63c', percentage: 95 },
|
||||
{ color: '#019d30', percentage: 100 },
|
||||
]
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>在线ESP32烧录<span v-if="serialSupported">(免环境配置,免装软件)</span></h1>
|
||||
<el-divider></el-divider>
|
||||
<div v-show="serialSupported">
|
||||
<el-form label-width="auto">
|
||||
<el-form-item label="固件">
|
||||
<el-select
|
||||
v-model="imageSelect"
|
||||
placeholder="选择固件"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in imageOption"
|
||||
:key="item.value"
|
||||
:label="item.value"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="波特率">
|
||||
<el-select
|
||||
v-model="programBaud"
|
||||
placeholder="选择波特率"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in programBaudOption"
|
||||
:key="item.value"
|
||||
:label="item.value"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作">
|
||||
<el-button v-if="!isConnected" @click="programConnect" type="primary">连接</el-button>
|
||||
<el-button v-show="isConnected" @click="programFlash" type="primary">烧录</el-button>
|
||||
<el-button v-show="isConnected" @click="programErase" type="danger">全片擦除</el-button>
|
||||
<el-button v-show="isConnected" @click="programDisconnect" type="info">断开连接</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="已连接" v-show="isConnected">
|
||||
<div class="flex gap-2">
|
||||
<el-tag type="primary">芯片型号 {{ chip }}</el-tag>
|
||||
<el-tag type="success">波特率 {{ connectedBaud }}</el-tag>
|
||||
<!-- <el-tag type="info">Tag 3</el-tag>-->
|
||||
<!-- <el-tag type="warning">Tag 4</el-tag>-->
|
||||
<!-- <el-tag type="danger">Tag 5</el-tag>-->
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" class="border" v-if="binaryLoadStatus.status">
|
||||
<div class="flex flex-row w-full">
|
||||
<el-text class="w-32">{{ binaryLoadStatus.status }}</el-text>
|
||||
<el-progress :percentage="binaryLoadStatus.progress" :color="customColors" class="w-full"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- <input type="file" @change="handleFileChange"/>-->
|
||||
|
||||
<!-- <div>-->
|
||||
<!-- <h1>Console</h1>-->
|
||||
<!-- <p>Connected to device: {{chip}}</p>-->
|
||||
<!-- <button @click="consoleConnectBtn">stop</button>-->
|
||||
<!-- <button @click="consoleResetBtn">reset</button>-->
|
||||
<!-- </div>-->
|
||||
<div>
|
||||
<div id="terminal-container" ref="terminalContainer" class="terminal"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="!serialSupported">
|
||||
<div class="text-center">
|
||||
<a href="/"><el-button type="primary">返回至首页</el-button></a>
|
||||
</div>
|
||||
<h2>{{notSupportedMsg}}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.terminal {
|
||||
background-color: black;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.el-popper {
|
||||
transition: all 0.05s;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -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 };
|
||||
|
|
@ -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 };
|
||||
|
|
@ -0,0 +1,495 @@
|
|||
/// <reference types="w3c-web-serial" />
|
||||
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<unknown>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* 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<number>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* Connect and detect the existing chip.
|
||||
* @param {string} mode Reset mode to use for connection.
|
||||
*/
|
||||
detectChip(mode?: string): Promise<void>;
|
||||
/**
|
||||
* 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<number | Uint8Array>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* Leave RAM download mode and run application
|
||||
* @param {number} entrypoint - Entrypoint number
|
||||
*/
|
||||
memFinish(entrypoint: number): Promise<void>;
|
||||
/**
|
||||
* Configure SPI flash pins
|
||||
* @param {number} hspiArg - Argument for SPI attachment
|
||||
*/
|
||||
flashSpiAttach(hspiArg: number): Promise<void>;
|
||||
/**
|
||||
* 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<number>;
|
||||
/**
|
||||
* 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<number>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* Leave flash mode and run/reboot
|
||||
* @param {boolean} reboot Reboot after leaving flash mode ?
|
||||
*/
|
||||
flashFinish(reboot?: boolean): Promise<void>;
|
||||
/**
|
||||
* Leave compressed flash mode and run/reboot
|
||||
* @param {boolean} reboot Reboot after leaving flash mode ?
|
||||
*/
|
||||
flashDeflFinish(reboot?: boolean): Promise<void>;
|
||||
/**
|
||||
* 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<number>;
|
||||
/**
|
||||
* Read flash id by executing the SPIFLASH_RDID flash command.
|
||||
* @returns {Promise<number>} Register SPI_W0_REG value
|
||||
*/
|
||||
readFlashId(): Promise<number>;
|
||||
/**
|
||||
* Execute the erase flash command
|
||||
* @returns {Promise<number | Uint8Array>} Erase flash command result
|
||||
*/
|
||||
eraseFlash(): Promise<number | Uint8Array>;
|
||||
/**
|
||||
* 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<string>;
|
||||
readFlash(addr: number, size: number, onPacketReceived?: FlashReadCallback): Promise<Uint8Array>;
|
||||
/**
|
||||
* Upload the flasher ROM bootloader (flasher stub) to the chip.
|
||||
* @returns {ROM} The Chip ROM
|
||||
*/
|
||||
runStub(): Promise<ROM>;
|
||||
/**
|
||||
* Change the chip baudrate.
|
||||
*/
|
||||
changeBaud(): Promise<void>;
|
||||
/**
|
||||
* Execute the main function of ESPLoader.
|
||||
* @param {string} mode Reset mode to use
|
||||
* @returns {string} chip ROM
|
||||
*/
|
||||
main(mode?: string): Promise<string>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* Read SPI flash manufacturer and device id.
|
||||
*/
|
||||
flashId(): Promise<void>;
|
||||
getFlashSize(): Promise<number>;
|
||||
/**
|
||||
* Perform a chip hard reset by setting RTS to LOW and then HIGH.
|
||||
*/
|
||||
hardReset(): Promise<void>;
|
||||
/**
|
||||
* Soft reset the device chip. Soft reset with run user code is the closest.
|
||||
*/
|
||||
softReset(): Promise<void>;
|
||||
}
|
||||
export {};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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";
|
||||
|
|
@ -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";
|
||||
|
|
@ -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<void>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* 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<void>;
|
||||
declare const _default: {
|
||||
classicReset: typeof classicReset;
|
||||
customReset: typeof customReset;
|
||||
hardReset: typeof hardReset;
|
||||
usbJTAGSerialReset: typeof usbJTAGSerialReset;
|
||||
validateCustomResetStringSequence: typeof validateCustomResetStringSequence;
|
||||
};
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
const DEFAULT_RESET_DELAY = 50;
|
||||
/**
|
||||
* Sleep for ms milliseconds
|
||||
* @param {number} ms Milliseconds to wait
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
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 };
|
||||
|
|
@ -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<number>;
|
||||
getPkgVersion(loader: ESPLoader): Promise<number>;
|
||||
getChipRevision(loader: ESPLoader): Promise<number>;
|
||||
getChipDescription(loader: ESPLoader): Promise<string>;
|
||||
getChipFeatures(loader: ESPLoader): Promise<string[]>;
|
||||
getCrystalFreq(loader: ESPLoader): Promise<number>;
|
||||
_d2h(d: number): string;
|
||||
readMac(loader: ESPLoader): Promise<string>;
|
||||
}
|
||||
|
|
@ -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]));
|
||||
}
|
||||
}
|
||||
|
|
@ -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<number>;
|
||||
getChipRevision(loader: ESPLoader): Promise<number>;
|
||||
getChipDescription(loader: ESPLoader): Promise<string>;
|
||||
getChipFeatures(loader: ESPLoader): Promise<string[]>;
|
||||
getCrystalFreq(loader: ESPLoader): Promise<number>;
|
||||
changeBaudRate(loader: ESPLoader): Promise<void>;
|
||||
_d2h(d: number): string;
|
||||
readMac(loader: ESPLoader): Promise<string>;
|
||||
getEraseSize(offset: number, size: number): number;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<number>;
|
||||
getChipRevision(loader: ESPLoader): Promise<number>;
|
||||
getChipDescription(loader: ESPLoader): Promise<string>;
|
||||
getChipFeatures(loader: ESPLoader): Promise<string[]>;
|
||||
getCrystalFreq(loader: ESPLoader): Promise<number>;
|
||||
_d2h(d: number): string;
|
||||
readMac(loader: ESPLoader): Promise<string>;
|
||||
getEraseSize(offset: number, size: number): number;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<number>;
|
||||
getChipRevision(loader: ESPLoader): Promise<number>;
|
||||
getChipDescription(loader: ESPLoader): Promise<string>;
|
||||
getChipFeatures(loader: ESPLoader): Promise<string[]>;
|
||||
getCrystalFreq(loader: ESPLoader): Promise<number>;
|
||||
_d2h(d: number): string;
|
||||
readMac(loader: ESPLoader): Promise<string>;
|
||||
getEraseSize(offset: number, size: number): number;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<string>;
|
||||
getChipFeatures(loader: ESPLoader): Promise<string[]>;
|
||||
getCrystalFreq(loader: ESPLoader): Promise<number>;
|
||||
_d2h(d: number): string;
|
||||
postConnect(loader: ESPLoader): Promise<void>;
|
||||
readMac(loader: ESPLoader): Promise<string>;
|
||||
getEraseSize(offset: number, size: number): number;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<number>;
|
||||
getChipDescription(loader: ESPLoader): Promise<string>;
|
||||
getChipFeatures(loader: ESPLoader): Promise<string[]>;
|
||||
getCrystalFreq(loader: ESPLoader): Promise<number>;
|
||||
_d2h(d: number): string;
|
||||
readMac(loader: ESPLoader): Promise<string>;
|
||||
getEraseSize(offset: number, size: number): number;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<string>;
|
||||
getChipFeatures(loader: ESPLoader): Promise<string[]>;
|
||||
getCrystalFreq(loader: ESPLoader): Promise<number>;
|
||||
_d2h(d: number): string;
|
||||
postConnect(loader: ESPLoader): Promise<void>;
|
||||
readMac(loader: ESPLoader): Promise<string>;
|
||||
getEraseSize(offset: number, size: number): number;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<number>;
|
||||
getChipDescription(loader: ESPLoader): Promise<"ESP8285" | "ESP8266EX">;
|
||||
getChipFeatures: (loader: ESPLoader) => Promise<string[]>;
|
||||
getCrystalFreq(loader: ESPLoader): Promise<number>;
|
||||
_d2h(d: number): string;
|
||||
readMac(loader: ESPLoader): Promise<string>;
|
||||
getEraseSize(offset: number, size: number): number;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<number>;
|
||||
/**
|
||||
* 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<number>;
|
||||
/**
|
||||
* 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<number>;
|
||||
/**
|
||||
* 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<string>;
|
||||
/**
|
||||
* 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<string[]>;
|
||||
/**
|
||||
* 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<number>;
|
||||
/**
|
||||
* 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<string>;
|
||||
/**
|
||||
* Function to be executed after chip connection
|
||||
* @param {ESPLoader} loader - Loader class to communicate with chip.
|
||||
*/
|
||||
postConnect?(loader: ESPLoader): Promise<void>;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"entry": 1074521560,
|
||||
"text": "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",
|
||||
"text_start": 1074520064,
|
||||
"data": "GOv8P9jnC0Bx6AtA8+wLQO3oC0CP6AtA7egLQEnpC0AG6gtAeOoLQCHqC0CB5wtAo+kLQPjpC0Bn6QtAmuoLQI7pC0Ca6gtAXegLQLPoC0Dt6AtASekLQHfoC0BM6wtAs+wLQKXmC0DX7AtApeYLQKXmC0Cl5gtApeYLQKXmC0Cl5gtApeYLQKXmC0Dz6gtApeYLQM3rC0Cz7AtA",
|
||||
"data_start": 1073605544
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"entry": 1082132112,
|
||||
"text": "QREixCbCBsa39wBgEUc3BIRA2Mu39ABgEwQEANxAkYuR57JAIkSSREEBgoCIQBxAE3X1D4KX3bcBEbcHAGBOxoOphwBKyDcJhEAmylLEBs4izLcEAGB9WhMJCQDATBN09A8N4PJAYkQjqDQBQknSRLJJIkoFYYKAiECDJwkAE3X1D4KXfRTjGUT/yb8TBwAMlEGqh2MY5QCFR4XGI6AFAHlVgoAFR2OH5gAJRmONxgB9VYKAQgUTB7ANQYVjlecCiUecwfW3kwbADWMW1QCYwRMFAAyCgJMG0A19VWOV1wCYwRMFsA2CgLc1hUBBEZOFRboGxmE/Y0UFBrc3hUCTh8exA6cHCAPWRwgTdfUPkwYWAMIGwYIjktcIMpcjAKcAA9dHCJFnk4cHBGMe9wI3t4RAEwfHsaFnupcDpgcIt/aEQLc3hUCTh8exk4bGtWMf5gAjpscII6DXCCOSBwghoPlX4wb1/LJAQQGCgCOm1wgjoOcI3bc3NwBgfEudi/X/NycAYHxLnYv1/4KAQREGxt03tzcAYCOmBwI3BwAImMOYQ33/yFeyQBNF9f8FiUEBgoBBEQbG2T993TcHAEC3NwBgmMM3NwBgHEP9/7JAQQGCgEERIsQ3BIRAkwcEAUrAA6kHAQbGJsJjCgkERTc5xb1HEwQEAYFEY9YnAQREvYiTtBQAfTeFPxxENwaAABOXxwCZ4DcGAAG39v8AdY+3NgBg2MKQwphCff9BR5HgBUczCelAupcjKCQBHMSyQCJEkkQCSUEBgoABEQbOIswlNzcEzj9sABMFRP+XAID/54Cg8qqHBUWV57JHk/cHID7GiTc3NwBgHEe3BkAAEwVE/9WPHMeyRZcAgP/ngCDwMzWgAPJAYkQFYYKAQRG3B4RABsaThwcBBUcjgOcAE9fFAJjHBWd9F8zDyMf5jTqVqpWxgYzLI6oHAEE3GcETBVAMskBBAYKAAREizDcEhECTBwQBJsrER07GBs5KyKqJEwQEAWPzlQCuhKnAAylEACaZE1nJABxIY1XwABxEY175ArU9fd1IQCaGzoWXAID/54Ag4xN19Q8BxZMHQAxcyFxAppdcwFxEhY9cxPJAYkTSREJJskkFYYKAaTVtv0ERBsaXAID/54BA1gNFhQGyQHUVEzUVAEEBgoBBEQbGxTcNxbcHhECThwcA1EOZzjdnCWATBwcRHEM3Bv3/fRbxjzcGAwDxjtWPHMOyQEEBgoBBEQbGbTcRwQ1FskBBARcDgP9nAIPMQREGxpcAgP/ngEDKcTcBxbJAQQHZv7JAQQGCgEERBsYTBwAMYxrlABMFsA3RPxMFwA2yQEEB6bcTB7AN4xvl/sE3EwXQDfW3QREixCbCBsYqhLMEtQBjF5QAskAiRJJEQQGCgANFBAAFBE0/7bc1cSbLTsf9coVp/XQizUrJUsVWwwbPk4SE+haRk4cJB6aXGAizhOcAKokmhS6ElwCA/+eAwC+ThwkHGAgFarqXs4pHQTHkBWd9dZMFhfqTBwcHEwWF+RQIqpczhdcAkwcHB66Xs4XXACrGlwCA/+eAgCwyRcFFlTcBRYViFpH6QGpE2kRKSbpJKkqaSg1hgoCiiWNzigCFaU6G1oVKhZcAgP/ngADJE3X1DwHtTobWhSaFlwCA/+eAwCdOmTMENEFRtxMFMAZVvxMFAAzZtTFx/XIFZ07XUtVW017PBt8i3SbbStla0WLNZstqyW7H/XcWkRMHBwc+lxwIupc+xiOqB/iqiS6Ksoq2iwU1kwcAAhnBtwcCAD6FlwCA/+eAYCCFZ2PlVxMFZH15EwmJ+pMHBAfKlxgIM4nnAEqFlwCA/+eA4B59exMMO/mTDIv5EwcEB5MHBAcUCGKX5peBRDMM1wCzjNcAUk1jfE0JY/GkA0GomT+ihQgBjTW5NyKGDAFKhZcAgP/ngMAaopmilGP1RAOzh6RBY/F3AzMEmkBj84oAVoQihgwBToWXAID/54BAuBN19Q9V3QLMAUR5XY1NowkBAGKFlwCA/+eAgKd9+QNFMQHmhVE8Y08FAOPijf6FZ5OHBweilxgIupfalyOKp/gFBPG34xWl/ZFH4wX09gVnfXWTBwcHkwWF+hMFhfkUCKqXM4XXAJMHBweul7OF1wAqxpcAgP/ngOAQcT0yRcFFZTNRPdU5twcCABnhkwcAAj6FlwCA/+eA4A2FYhaR+lBqVNpUSlm6WSpamloKW/pLakzaTEpNuk0pYYKAt1dBSRlxk4f3hAFFht6i3KbaytjO1tLU1tLa0N7O4szmyurI7sY+zpcAgP/ngMCgcTENwTdnCWATBwcRHEO3BoRAI6L2ALcG/f/9FvWPwWbVjxzDpTEFzbcnC2A3R9hQk4aHwRMHF6qYwhOGB8AjIAYAI6AGAJOGB8KYwpOHx8GYQzcGBABRj5jDI6AGALcHhEA3N4VAk4cHABMHx7ohoCOgBwCRB+Pt5/5FO5FFaAh1OWUzt7eEQJOHx7EhZz6XIyD3CLcHgEA3CYRAk4eHDiMg+QC3OYVA1TYTCQkAk4nJsWMHBRC3BwFgRUcjoOcMhUVFRZcAgP/ngED5twWAQAFGk4UFAEVFlwCA/+eAQPo39wBgHEs3BQIAk+dHABzLlwCA/+eAQPm3FwlgiF+BRbcEhEBxiWEVEzUVAJcAgP/ngAChwWf9FxMHABCFZkFmtwUAAQFFk4QEAQ1qtzqEQJcAgP/ngACXJpoTi8qxg6fJCPXfg6vJCIVHI6YJCCMC8QKDxxsACUcjE+ECowLxAgLUTUdjgecIUUdjj+cGKUdjn+cAg8c7AAPHKwCiB9mPEUdjlucAg6eLAJxDPtRxOaFFSBBlNoPHOwADxysAogfZjxFnQQdjdPcEEwWwDZk2EwXADYE2EwXgDi0+vTFBt7cFgEABRpOFhQMVRZcAgP/ngADrNwcAYFxHEwUAApPnFxBcxzG3yUcjE/ECTbcDxxsA0UZj5+YChUZj5uYAAUwTBPAPhah5FxN39w/JRuPo5v63NoVACgeThga7NpcYQwKHkwYHA5P29g8RRuNp1vwTB/cCE3f3D41GY+vmCLc2hUAKB5OGxr82lxhDAocTB0ACY5jnEALUHUQBRWE8AUVFPOE22TahRUgQfRTBPHX0AUwBRBN19A9hPBN1/A9JPG024x4E6oPHGwBJR2Nj9y4JR+N29+r1F5P39w89R+Ng9+o3N4VAigcTB8fAupecQ4KHBUSd63AQgUUBRZfwf//ngAB0HeHRRWgQjTwBRDGoBUSB75fwf//ngAB5MzSgACmgIUdjhecABUQBTGG3A6yLAAOkywCzZ4wA0gf19+/wv4h98cFsIpz9HH19MwWMQFXcs3eVAZXjwWwzBYxAY+aMAv18MwWMQFXQMYGX8H//54CAdVX5ZpT1tzGBl/B//+eAgHRV8WqU0bdBgZfwf//ngMBzUfkzBJRBwbchR+OJ5/ABTBMEAAwxt0FHzb9BRwVE45zn9oOlywADpYsA1TKxv0FHBUTjkuf2A6cLAZFnY+XnHIOlSwEDpYsA7/D/gzW/QUcFROOS5/SDpwsBEWdjZfcaA6fLAIOlSwEDpYsAM4TnAu/wf4EjrAQAIySKsDG3A8cEAGMOBxADp4sAwRcTBAAMYxP3AMBIAUeTBvAOY0b3AoPHWwADx0sAAUyiB9mPA8drAEIHXY+Dx3sA4gfZj+OB9uYTBBAMqb0zhusAA0aGAQUHsY7ht4PHBADxw9xEY5gHEsBII4AEAH21YUdjlucCg6fLAQOniwGDpksBA6YLAYOlywADpYsAl/B//+eAQGQqjDM0oAAptQFMBUQRtRFHBUTjmufmA6WLAIFFl/B//+eAwGmRtRP39wDjGgfsk9xHABOEiwABTH1d43mc3UhEl/B//+eAwE0YRFRAEED5jmMHpwEcQhNH9/99j9mOFMIFDEEE2b8RR0m9QUcFROOc5+CDp4sAA6dLASMm+QAjJOkA3bODJYkAwReR5YnPAUwTBGAMtbsDJ8kAY2b3BhP3NwDjHgfkAyjJAAFGAUczBehAs4blAGNp9wDjCQbUIyapACMk2QCZszOG6wAQThEHkMIFRum/IUcFROOW59oDJMkAGcATBIAMIyYJACMkCQAzNIAASbsBTBMEIAwRuwFMEwSADDGzAUwTBJAMEbMTByANY4PnDBMHQA3jkOe8A8Q7AIPHKwAiBF2Ml/B//+eA4EwDrMQAQRRjc4QBIozjDgy4wEBilDGAnEhjVfAAnERjW/QK7/BP0XXdyEBihpOFiwGX8H//54DgSAHFkwdADNzI3EDil9zA3ESzh4dB3MSX8H//54DAR4m+CWUTBQVxA6zLAAOkiwCX8H//54BAOLcHAGDYS7cGAAHBFpNXRwESB3WPvYvZj7OHhwMBRbPVhwKX8H//54BgORMFgD6X8H//54DgNBG2g6ZLAQOmCwGDpcsAA6WLAO/wT/79tIPFOwCDxysAE4WLAaIF3Y3BFe/wL9vZvO/wj8o9v4PHOwADxysAE4yLAaIH2Y8TjQf/BUS3O4VA3ERjBQ0AmcNjTIAAY1AEChMHcAzYyOOfB6iTB5AMYaiTh8u6mEO3t4RAk4fHsZmPPtaDJ4qwtzyEQGrQk4wMAZONy7oFSGNz/QANSELGOsTv8I/DIkcySDcFhEDihXwQk4bKsRAQEwWFApfwf//ngEA0glcDp4ywg6UNADMN/UAdjz6cslcjpOywKoS+lSOgvQCTh8qxnY0BxaFn45L19lqF7/CvziOgbQGZvy3044MHoJMHgAzcyPW6g6eLAOObB57v8C/ZCWUTBQVxl/B//+eAoCLv8K/Ul/B//+eA4CbRugOkywDjBwSc7/Cv1hMFgD6X8H//54BAIO/wT9IClFW67/DP0fZQZlTWVEZZtlkmWpZaBlv2S2ZM1kxGTbZNCWGCgAAA",
|
||||
"text_start": 1082130432,
|
||||
"data": "HCuEQEIKgECSCoBA6gqAQI4LgED6C4BAqAuAQA4JgEBKC4BAiguAQP4KgEC+CIBAMguAQL4IgEAcCoBAYgqAQJIKgEDqCoBALgqAQHIJgECiCYBAKgqAQEwOgECSCoBAEg2AQAQOgED+B4BALA6AQP4HgED+B4BA/geAQP4HgED+B4BA/geAQP4HgED+B4BArgyAQP4HgEAwDYBABA6AQA==",
|
||||
"data_start": 1082469292
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,148 @@
|
|||
/// <reference types="w3c-web-serial" />
|
||||
/**
|
||||
* 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<void>;
|
||||
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<void>;
|
||||
/**
|
||||
* 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<Uint8Array>;
|
||||
/**
|
||||
* 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<Uint8Array | undefined>;
|
||||
_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<void>;
|
||||
/**
|
||||
* 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<void>;
|
||||
/**
|
||||
* 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<void>;
|
||||
sleep(ms: number): Promise<unknown>;
|
||||
/**
|
||||
* Wait for a given timeout ms for serial device unlock.
|
||||
* @param {number} timeout Timeout time in milliseconds (ms) to sleep
|
||||
*/
|
||||
waitForUnlock(timeout: number): Promise<void>;
|
||||
/**
|
||||
* Disconnect from serial device by running SerialPort.close() after streams unlock.
|
||||
*/
|
||||
disconnect(): Promise<void>;
|
||||
}
|
||||
export { Transport };
|
||||
|
|
@ -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 };
|
||||
Loading…
Reference in New Issue