From 5a3d4516de8595401d9de99260cb4975b24bdf30 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Fri, 28 Jul 2023 20:10:42 +0800 Subject: [PATCH 1/9] initial api jsdoc --- .eslintrc | 10 +- package-lock.json | 211 +++++++++++++++++++++++++++++++--- package.json | 1 + src/error.ts | 6 + src/esploader.ts | 249 ++++++++++++++++++++++++++++++++--------- src/reset.ts | 41 +++++++ src/targets/esp32.ts | 38 +++---- src/targets/esp32c3.ts | 18 +-- src/targets/esp32c6.ts | 18 +-- src/targets/esp32h2.ts | 12 +- src/targets/esp32s2.ts | 16 +-- src/targets/esp32s3.ts | 12 +- src/targets/esp8266.ts | 24 ++-- src/targets/rom.ts | 74 ++++++++++-- 14 files changed, 570 insertions(+), 160 deletions(-) diff --git a/.eslintrc b/.eslintrc index 924f042..c13def9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,18 +1,16 @@ { "root": true, "parser": "@typescript-eslint/parser", - "plugins": [ - "@typescript-eslint", - "prettier" - ], + "plugins": ["@typescript-eslint", "prettier", "jsdoc"], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", + "plugin:jsdoc/recommended", "prettier" ], "rules": { - "no-console": 1, // Means warning + "no-console": 1, // Means warning "prettier/prettier": 2 // Means error } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 36cf82c..248b348 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "babel-loader": "^9.1.0", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", + "eslint-plugin-jsdoc": "^46.4.5", "eslint-plugin-prettier": "^4.2.1", "prettier": "^2.7.1", "rimraf": "^3.0.2", @@ -453,6 +454,20 @@ "node": ">=6.9.0" } }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.39.4", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz", + "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==", + "dev": true, + "dependencies": { + "comment-parser": "1.3.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -1348,6 +1363,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1572,6 +1596,15 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "node_modules/comment-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", + "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -1777,6 +1810,41 @@ "eslint": ">=7.0.0" } }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.4.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.5.tgz", + "integrity": "sha512-HjTuxqDYplAQFu29F3MHFCDDBgeqOxPXI6TyBhL0u2rr4XntJ0z3C9PmJvpjFscKdHwkZDN/0l1QCG0QwyRi4g==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.39.4", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.3.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-plugin-prettier": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", @@ -1975,9 +2043,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -2374,9 +2442,9 @@ "dev": true }, "node_modules/is-builtin-module": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", - "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", "dev": true, "dependencies": { "builtin-modules": "^3.3.0" @@ -2532,6 +2600,15 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -3141,9 +3218,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3220,6 +3297,28 @@ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "dev": true }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3911,6 +4010,17 @@ "to-fast-properties": "^2.0.0" } }, + "@es-joy/jsdoccomment": { + "version": "0.39.4", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz", + "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==", + "dev": true, + "requires": { + "comment-parser": "1.3.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + } + }, "@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -4568,6 +4678,12 @@ "color-convert": "^2.0.1" } }, + "are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4726,6 +4842,12 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "comment-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", + "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -4958,6 +5080,31 @@ "dev": true, "requires": {} }, + "eslint-plugin-jsdoc": { + "version": "46.4.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.5.tgz", + "integrity": "sha512-HjTuxqDYplAQFu29F3MHFCDDBgeqOxPXI6TyBhL0u2rr4XntJ0z3C9PmJvpjFscKdHwkZDN/0l1QCG0QwyRi4g==", + "dev": true, + "requires": { + "@es-joy/jsdoccomment": "~0.39.4", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.3.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + } + } + }, "eslint-plugin-prettier": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", @@ -5012,9 +5159,9 @@ } }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -5326,9 +5473,9 @@ "dev": true }, "is-builtin-module": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", - "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", "dev": true, "requires": { "builtin-modules": "^3.3.0" @@ -5445,6 +5592,12 @@ "argparse": "^2.0.1" } }, + "jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5864,9 +6017,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -5925,6 +6078,28 @@ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "dev": true }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", diff --git a/package.json b/package.json index 5cbd77d..2057ec2 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "babel-loader": "^9.1.0", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", + "eslint-plugin-jsdoc": "^46.4.5", "eslint-plugin-prettier": "^4.2.1", "prettier": "^2.7.1", "rimraf": "^3.0.2", diff --git a/src/error.ts b/src/error.ts index fe5ec18..e5ed8cf 100644 --- a/src/error.ts +++ b/src/error.ts @@ -1,5 +1,11 @@ +/** + * Represents a Espressif chip error. + */ class ESPError extends Error {} +/** + * Represents a Espressif timeout chip error. + */ class TimeoutError extends ESPError {} export { ESPError, TimeoutError }; diff --git a/src/esploader.ts b/src/esploader.ts index 7ca159c..5e0e144 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -15,6 +15,16 @@ export interface FlashOptions { calculateMD5Hash?: (image: string) => string; } +/** + * Options to initialize the ESPLoader class. + * { + * transport: A Transport class that provide serial communication to the chip + * baudrate: The baud rate used for connecting the device + * terminal?: A IEspLoaderTerminal wrapper interface to call the terminal + * romBaudrate: The baudrate described by the chip ROM class; + * debugLogging: Enable/Disable logging for debug + * } + */ export interface LoaderOptions { transport: Transport; port?: SerialPort; @@ -27,6 +37,11 @@ export interface LoaderOptions { type FlashReadCallback = ((packet: Uint8Array, progress: number, totalSize: number) => void) | null; +/** + * Return the chip ROM based on the given magic number + * @param {number} magic - magic hex number to select ROM. + * @returns {ROM} The chip ROM class related to given magic hex number. + */ async function magic2Chip(magic: number): Promise { switch (magic) { case 0x00f01d83: { @@ -63,12 +78,41 @@ async function magic2Chip(magic: number): Promise { } } +/** + * A wrapper around your implementation of a terminal by + * implementing the clean, write and writeLine methods + * which are called by the ESPLoader class. + */ 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; } +/** + * An ESP loader class to perform serial communication + * such as read and write flash memory and registers. + * + * LoaderOptions: + * { + * transport: Transport; + * baudrate: number; + * terminal?: IEspLoaderTerminal; + * romBaudrate: number; + * debugLogging?: boolean; + * } + */ export class ESPLoader { ESP_RAM_BLOCK = 0x1800; ESP_FLASH_BEGIN = 0x02; @@ -141,6 +185,24 @@ export class ESPLoader { private romBaudrate = 115200; private debugLogging = false; + /** + * Create a new ESPLoader instance using a LoaderOptions object. + * @param {LoaderOptions} options - Options for ESPLoader. + * + * { + * + * transport: Transport; + * + * baudrate: number; + * + * terminal?: IEspLoaderTerminal; + * + * romBaudrate: number; + * + * debugLogging?: boolean; + * + * } + */ constructor(options: LoaderOptions) { this.IS_STUB = false; this.FLASH_WRITE_SIZE = 0x4000; @@ -172,6 +234,11 @@ export class ESPLoader { return new Promise((resolve) => setTimeout(resolve, ms)); } + /** + * 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 = true) { if (this.terminal) { if (withNewline) { @@ -185,36 +252,81 @@ export class ESPLoader { } } + /** + * 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 = true) { this.write(`Error: ${str}`, withNewline); } + /** + * 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 = true) { this.write(str, withNewline); } + /** + * 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 = true) { if (this.debugLogging) { this.write(`Debug: ${str}`, withNewline); } } - _short_to_bytearray(i: number) { + /** + * Convert short integer to byte array + * @param {number} i - Number to convert. + * @returns {Uint8Array} Byte array. + */ + _shortToBytearray(i: number) { return new Uint8Array([i & 0xff, (i >> 8) & 0xff]); } - _int_to_bytearray(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 { return new Uint8Array([i & 0xff, (i >> 8) & 0xff, (i >> 16) & 0xff, (i >> 24) & 0xff]); } + /** + * 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. + */ _bytearray_to_short(i: number, j: number) { return i | (j >> 8); } + /** + * 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. + */ _bytearray_to_int(i: number, j: number, k: number, l: number) { return i | (j << 8) | (k << 16) | (l << 24); } + /** + * 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) { const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); tmp.set(new Uint8Array(buffer1), 0); @@ -222,6 +334,12 @@ export class ESPLoader { return tmp.buffer; } + /** + * 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) { const c = new Uint8Array(arr1.length + arr2.length); c.set(arr1, 0); @@ -229,6 +347,11 @@ export class ESPLoader { return c; } + /** + * 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) { let b_str = ""; for (let i = 0; i < u8Array.length; i++) { @@ -237,6 +360,11 @@ export class ESPLoader { return b_str; } + /** + * 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) { const u8_array = new Uint8Array(bStr.length); for (let i = 0; i < bStr.length; i++) { @@ -273,6 +401,15 @@ export class ESPLoader { throw new ESPError("invalid response"); } + /** + * Run a serial command in the chip + * @param {number} op - Operation number + * @param {string} data - Unsigned 8 bit array + * @param {number} chk - binary string input + * @param {boolean} waitResponse - binary string input + * @param {number} btimeoutStr - binary string input + * @returns {[number, Uint8Array]} Return a 8 bit unsigned integer array. + */ async command( op: number | null = null, data: Uint8Array = new Uint8Array(0), @@ -284,12 +421,12 @@ export class ESPLoader { const pkt = new Uint8Array(8 + data.length); pkt[0] = 0x00; pkt[1] = op; - pkt[2] = this._short_to_bytearray(data.length)[0]; - pkt[3] = this._short_to_bytearray(data.length)[1]; - pkt[4] = this._int_to_bytearray(chk)[0]; - pkt[5] = this._int_to_bytearray(chk)[1]; - pkt[6] = this._int_to_bytearray(chk)[2]; - pkt[7] = this._int_to_bytearray(chk)[3]; + pkt[2] = this._shortToBytearray(data.length)[0]; + pkt[3] = this._shortToBytearray(data.length)[1]; + pkt[4] = this._intToByteArray(chk)[0]; + pkt[5] = this._intToByteArray(chk)[1]; + pkt[6] = this._intToByteArray(chk)[2]; + pkt[7] = this._intToByteArray(chk)[3]; let i; for (i = 0; i < data.length; i++) { @@ -306,21 +443,21 @@ export class ESPLoader { } async read_reg(addr: number, timeout = 3000) { - const pkt = this._int_to_bytearray(addr); + const pkt = this._intToByteArray(addr); const val = await this.command(this.ESP_READ_REG, pkt, undefined, undefined, timeout); return val[0]; } async write_reg(addr: number, value: number, mask = 0xffffffff, delay_us = 0, delay_after_us = 0) { - let pkt = this._appendArray(this._int_to_bytearray(addr), this._int_to_bytearray(value)); - pkt = this._appendArray(pkt, this._int_to_bytearray(mask)); - pkt = this._appendArray(pkt, this._int_to_bytearray(delay_us)); + let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(value)); + pkt = this._appendArray(pkt, this._intToByteArray(mask)); + pkt = this._appendArray(pkt, this._intToByteArray(delay_us)); if (delay_after_us > 0) { - pkt = this._appendArray(pkt, this._int_to_bytearray(this.chip.UART_DATE_REG_ADDR)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(delay_after_us)); + pkt = this._appendArray(pkt, this._intToByteArray(this.chip.UART_DATE_REG_ADDR)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(delay_after_us)); } await this.check_command("write target memory", this.ESP_WRITE_REG, pkt); @@ -456,9 +593,9 @@ export class ESPLoader { async mem_begin(size: number, blocks: number, blocksize: number, offset: number) { /* XXX: Add check to ensure that STUB is not getting overwritten */ this.debug("mem_begin " + size + " " + blocks + " " + blocksize + " " + offset.toString(16)); - let pkt = this._appendArray(this._int_to_bytearray(size), this._int_to_bytearray(blocks)); - pkt = this._appendArray(pkt, this._int_to_bytearray(blocksize)); - pkt = this._appendArray(pkt, this._int_to_bytearray(offset)); + let pkt = this._appendArray(this._intToByteArray(size), this._intToByteArray(blocks)); + pkt = this._appendArray(pkt, this._intToByteArray(blocksize)); + pkt = this._appendArray(pkt, this._intToByteArray(offset)); await this.check_command("enter RAM download mode", this.ESP_MEM_BEGIN, pkt); } @@ -473,9 +610,9 @@ export class ESPLoader { }; async mem_block(buffer: Uint8Array, seq: number) { - let pkt = this._appendArray(this._int_to_bytearray(buffer.length), this._int_to_bytearray(seq)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); + let pkt = this._appendArray(this._intToByteArray(buffer.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, buffer); const checksum = this.checksum(buffer); await this.check_command("write to target RAM", this.ESP_MEM_DATA, pkt, checksum); @@ -483,12 +620,12 @@ export class ESPLoader { async mem_finish(entrypoint: number) { const is_entry = entrypoint === 0 ? 1 : 0; - const pkt = this._appendArray(this._int_to_bytearray(is_entry), this._int_to_bytearray(entrypoint)); + const pkt = this._appendArray(this._intToByteArray(is_entry), this._intToByteArray(entrypoint)); await this.check_command("leave RAM download mode", this.ESP_MEM_END, pkt, undefined, 50); // XXX: handle non-stub with diff timeout } async flash_spi_attach(hspi_arg: number) { - const pkt = this._int_to_bytearray(hspi_arg); + const pkt = this._intToByteArray(hspi_arg); await this.check_command("configure SPI flash pins", this.ESP_SPI_ATTACH, pkt); } @@ -503,7 +640,7 @@ export class ESPLoader { async flash_begin(size: number, offset: number) { const num_blocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); - const erase_size = this.chip.get_erase_size(offset, size); + const erase_size = this.chip.getEraseSize(offset, size); const d = new Date(); const t1 = d.getTime(); @@ -516,11 +653,11 @@ export class ESPLoader { this.debug( "flash begin " + erase_size + " " + num_blocks + " " + this.FLASH_WRITE_SIZE + " " + offset + " " + size, ); - let pkt = this._appendArray(this._int_to_bytearray(erase_size), this._int_to_bytearray(num_blocks)); - pkt = this._appendArray(pkt, this._int_to_bytearray(this.FLASH_WRITE_SIZE)); - pkt = this._appendArray(pkt, this._int_to_bytearray(offset)); + let pkt = this._appendArray(this._intToByteArray(erase_size), this._intToByteArray(num_blocks)); + pkt = this._appendArray(pkt, this._intToByteArray(this.FLASH_WRITE_SIZE)); + pkt = this._appendArray(pkt, this._intToByteArray(offset)); if (this.IS_STUB == false) { - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); // XXX: Support encrypted + pkt = this._appendArray(pkt, this._intToByteArray(0)); // XXX: Support encrypted } await this.check_command("enter Flash download mode", this.ESP_FLASH_BEGIN, pkt, undefined, timeout); @@ -549,9 +686,9 @@ export class ESPLoader { } this.info("Compressed " + size + " bytes to " + compsize + "..."); - let pkt = this._appendArray(this._int_to_bytearray(write_size), this._int_to_bytearray(num_blocks)); - pkt = this._appendArray(pkt, this._int_to_bytearray(this.FLASH_WRITE_SIZE)); - pkt = this._appendArray(pkt, this._int_to_bytearray(offset)); + let pkt = this._appendArray(this._intToByteArray(write_size), this._intToByteArray(num_blocks)); + pkt = this._appendArray(pkt, this._intToByteArray(this.FLASH_WRITE_SIZE)); + pkt = this._appendArray(pkt, this._intToByteArray(offset)); if ( (this.chip.CHIP_NAME === "ESP32-S2" || @@ -559,7 +696,7 @@ export class ESPLoader { this.chip.CHIP_NAME === "ESP32-C3") && this.IS_STUB === false ) { - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); } await this.check_command("enter compressed flash mode", this.ESP_FLASH_DEFL_BEGIN, pkt, undefined, timeout); const t2 = d.getTime(); @@ -570,9 +707,9 @@ export class ESPLoader { } async flash_block(data: Uint8Array, seq: number, timeout: number) { - let pkt = this._appendArray(this._int_to_bytearray(data.length), this._int_to_bytearray(seq)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); + let pkt = this._appendArray(this._intToByteArray(data.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, data); const checksum = this.checksum(data); @@ -581,9 +718,9 @@ export class ESPLoader { } async flash_defl_block(data: Uint8Array, seq: number, timeout: number) { - let pkt = this._appendArray(this._int_to_bytearray(data.length), this._int_to_bytearray(seq)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); + let pkt = this._appendArray(this._intToByteArray(data.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, data); const checksum = this.checksum(data); @@ -600,14 +737,14 @@ export class ESPLoader { async flash_finish(reboot = false) { const val = reboot ? 0 : 1; - const pkt = this._int_to_bytearray(val); + const pkt = this._intToByteArray(val); await this.check_command("leave Flash mode", this.ESP_FLASH_END, pkt); } async flash_defl_finish(reboot = false) { const val = reboot ? 0 : 1; - const pkt = this._int_to_bytearray(val); + const pkt = this._intToByteArray(val); await this.check_command("leave compressed flash mode", this.ESP_FLASH_DEFL_END, pkt); } @@ -733,9 +870,9 @@ export class ESPLoader { async flash_md5sum(addr: number, size: number) { const timeout = this.timeout_per_mb(this.MD5_TIMEOUT_PER_MB, size); - let pkt = this._appendArray(this._int_to_bytearray(addr), this._int_to_bytearray(size)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); + let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(size)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); let res = await this.check_command("calculate md5sum", this.ESP_SPI_FLASH_MD5, pkt, undefined, timeout); if (res instanceof Uint8Array && res.length > 16) { @@ -746,9 +883,9 @@ export class ESPLoader { } async read_flash(addr: number, size: number, onPacketReceived: FlashReadCallback = null) { - let pkt = this._appendArray(this._int_to_bytearray(addr), this._int_to_bytearray(size)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0x1000)); - pkt = this._appendArray(pkt, this._int_to_bytearray(1024)); + let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(size)); + pkt = this._appendArray(pkt, this._intToByteArray(0x1000)); + pkt = this._appendArray(pkt, this._intToByteArray(1024)); const res = await this.check_command("read flash", this.ESP_READ_FLASH, pkt); @@ -763,7 +900,7 @@ export class ESPLoader { if (packet instanceof Uint8Array) { if (packet.length > 0) { resp = this._appendArray(resp, packet); - await this.transport.write(this._int_to_bytearray(resp.length)); + await this.transport.write(this._intToByteArray(resp.length)); if (onPacketReceived) { onPacketReceived(packet, resp.length, size); @@ -829,7 +966,7 @@ export class ESPLoader { async change_baud() { this.info("Changing baudrate to " + this.baudrate); const second_arg = this.IS_STUB ? this.transport.baudrate : 0; - const pkt = this._appendArray(this._int_to_bytearray(this.baudrate), this._int_to_bytearray(second_arg)); + const pkt = this._appendArray(this._intToByteArray(this.baudrate), this._intToByteArray(second_arg)); const resp = await this.command(this.ESP_CHANGE_BAUDRATE, pkt); this.debug(resp[0].toString()); this.info("Changed"); @@ -857,15 +994,15 @@ export class ESPLoader { async main_fn(mode = "default_reset") { await this.detect_chip(mode); - const chip = await this.chip.get_chip_description(this); + const chip = await this.chip.getChipDescription(this); this.info("Chip is " + chip); - this.info("Features: " + (await this.chip.get_chip_features(this))); - this.info("Crystal is " + (await this.chip.get_crystal_freq(this)) + "MHz"); - this.info("MAC: " + (await this.chip.read_mac(this))); - await this.chip.read_mac(this); + this.info("Features: " + (await this.chip.getChipFeatures(this))); + this.info("Crystal is " + (await this.chip.getCrystalFreq(this)) + "MHz"); + this.info("MAC: " + (await this.chip.readMac(this))); + await this.chip.readMac(this); - if (typeof this.chip._post_connect != "undefined") { - await this.chip._post_connect(this); + if (typeof this.chip.postConnect != "undefined") { + await this.chip.postConnect(this); } await this.run_stub(); diff --git a/src/reset.ts b/src/reset.ts index 850e4d9..030b128 100644 --- a/src/reset.ts +++ b/src/reset.ts @@ -6,6 +6,21 @@ function sleep(ms: number): Promise { 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 + */ export async function classicReset(transport: Transport, resetDelay = DEFAULT_RESET_DELAY) { await transport.setDTR(false); await transport.setRTS(true); @@ -16,6 +31,19 @@ export async function classicReset(transport: Transport, resetDelay = DEFAULT_RE 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) + */ export async function usbJTAGSerialReset(transport: Transport) { await transport.setRTS(false); await transport.setDTR(false); @@ -34,6 +62,19 @@ export async function usbJTAGSerialReset(transport: Transport) { 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) + */ export async function hardReset(transport: Transport, usingUsbOtg = false) { if (usingUsbOtg) { await sleep(200); diff --git a/src/targets/esp32.ts b/src/targets/esp32.ts index a052f82..c4da962 100644 --- a/src/targets/esp32.ts +++ b/src/targets/esp32.ts @@ -37,22 +37,22 @@ export class ESP32ROM extends ROM { public ROM_DATA = ESP32_STUB.data; public ROM_TEXT = ESP32_STUB.text; - public async read_efuse(loader: ESPLoader, offset: number) { + public async readEfuse(loader: ESPLoader, offset: number): Promise { const addr = this.EFUSE_RD_REG_BASE + 4 * offset; loader.debug("Read efuse " + addr); return await loader.read_reg(addr); } - public async get_pkg_version(loader: ESPLoader) { - const word3 = await this.read_efuse(loader, 3); + public async getPkgVersion(loader: ESPLoader): Promise { + const word3 = await this.readEfuse(loader, 3); let pkg_version = (word3 >> 9) & 0x07; pkg_version += ((word3 >> 2) & 0x1) << 3; return pkg_version; } - public async get_chip_revision(loader: ESPLoader) { - const word3 = await this.read_efuse(loader, 3); - const word5 = await this.read_efuse(loader, 5); + public async getChipRevision(loader: ESPLoader): Promise { + const word3 = await this.readEfuse(loader, 3); + const word5 = await this.readEfuse(loader, 5); const apb_ctl_date = await loader.read_reg(this.DR_REG_SYSCON_BASE + 0x7c); const rev_bit0 = (word3 >> 15) & 0x1; @@ -72,7 +72,7 @@ export class ESP32ROM extends ROM { return 0; } - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { const chip_desc = [ "ESP32-D0WDQ6", "ESP32-D0WD", @@ -83,10 +83,10 @@ export class ESP32ROM extends ROM { "ESP32-PICO-V3-02", ]; let chip_name = ""; - const pkg_version = await this.get_pkg_version(loader); - const chip_revision = await this.get_chip_revision(loader); + const pkg_version = await this.getPkgVersion(loader); + const chip_revision = await this.getChipRevision(loader); const rev3 = chip_revision == 3; - const single_core = (await this.read_efuse(loader, 3)) & (1 << 0); + const single_core = (await this.readEfuse(loader, 3)) & (1 << 0); if (single_core != 0) { chip_desc[0] = "ESP32-S0WDQ6"; @@ -107,9 +107,9 @@ export class ESP32ROM extends ROM { return chip_name + " (revision " + chip_revision + ")"; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { const features = ["Wi-Fi"]; - const word3 = await this.read_efuse(loader, 3); + const word3 = await this.readEfuse(loader, 3); const chip_ver_dis_bt = word3 & (1 << 1); if (chip_ver_dis_bt === 0) { @@ -133,7 +133,7 @@ export class ESP32ROM extends ROM { } } - const pkg_version = await this.get_pkg_version(loader); + const pkg_version = await this.getPkgVersion(loader); if ([2, 4, 5, 6].indexOf(pkg_version) !== -1) { features.push(" Embedded Flash"); } @@ -142,7 +142,7 @@ export class ESP32ROM extends ROM { features.push(" Embedded PSRAM"); } - const word4 = await this.read_efuse(loader, 4); + const word4 = await this.readEfuse(loader, 4); const adc_vref = (word4 >> 8) & 0x1f; if (adc_vref !== 0) { features.push(" VRef calibration in efuse"); @@ -153,7 +153,7 @@ export class ESP32ROM extends ROM { features.push(" BLK3 partially reserved"); } - const word6 = await this.read_efuse(loader, 6); + const word6 = await this.readEfuse(loader, 6); const coding_scheme = word6 & 0x3; const coding_scheme_arr = ["None", "3/4", "Repeat (UNSUPPORTED)", "Invalid"]; features.push(" Coding Scheme " + coding_scheme_arr[coding_scheme]); @@ -161,7 +161,7 @@ export class ESP32ROM extends ROM { return features; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { const uart_div = (await loader.read_reg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; const ets_xtal = (loader.transport.baudrate * uart_div) / 1000000 / this.XTAL_CLK_DIVIDER; let norm_xtal; @@ -181,10 +181,10 @@ export class ESP32ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { - let mac0 = await this.read_efuse(loader, 1); + public async readMac(loader: ESPLoader) { + let mac0 = await this.readEfuse(loader, 1); mac0 = mac0 >>> 0; - let mac1 = await this.read_efuse(loader, 2); + let mac1 = await this.readEfuse(loader, 2); mac1 = mac1 >>> 0; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; diff --git a/src/targets/esp32c3.ts b/src/targets/esp32c3.ts index 0a3bc6c..98e9dca 100644 --- a/src/targets/esp32c3.ts +++ b/src/targets/esp32c3.ts @@ -36,7 +36,7 @@ export class ESP32C3ROM extends ROM { public ROM_DATA = ESP32C3_STUB.data; public ROM_TEXT = ESP32C3_STUB.text; - public async get_pkg_version(loader: ESPLoader) { + public async getPkgVersion(loader: ESPLoader): Promise { const num_word = 3; const block1_addr = this.EFUSE_BASE + 0x044; const addr = block1_addr + 4 * num_word; @@ -45,7 +45,7 @@ export class ESP32C3ROM extends ROM { return pkg_version; } - public async get_chip_revision(loader: ESPLoader) { + public async getChipRevision(loader: ESPLoader): Promise { const block1_addr = this.EFUSE_BASE + 0x044; const num_word = 3; const pos = 18; @@ -54,24 +54,24 @@ export class ESP32C3ROM extends ROM { return ret; } - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { let desc: string; - const pkg_ver = await this.get_pkg_version(loader); + const pkg_ver = await this.getPkgVersion(loader); if (pkg_ver === 0) { desc = "ESP32-C3"; } else { desc = "unknown ESP32-C3"; } - const chip_rev = await this.get_chip_revision(loader); + const chip_rev = await this.getChipRevision(loader); desc += " (revision " + chip_rev + ")"; return desc; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { return ["Wi-Fi"]; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { return 40; } @@ -80,7 +80,7 @@ export class ESP32C3ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { + public async readMac(loader: ESPLoader) { let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); @@ -108,7 +108,7 @@ export class ESP32C3ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp32c6.ts b/src/targets/esp32c6.ts index 514a325..c26463b 100644 --- a/src/targets/esp32c6.ts +++ b/src/targets/esp32c6.ts @@ -36,7 +36,7 @@ export class ESP32C6ROM extends ROM { public ROM_DATA = ESP32C6_STUB.data; public ROM_TEXT = ESP32C6_STUB.text; - public async get_pkg_version(loader: ESPLoader) { + public async getPkgVersion(loader: ESPLoader) { const num_word = 3; const block1_addr = this.EFUSE_BASE + 0x044; const addr = block1_addr + 4 * num_word; @@ -45,7 +45,7 @@ export class ESP32C6ROM extends ROM { return pkg_version; } - public async get_chip_revision(loader: ESPLoader) { + public async getChipRevision(loader: ESPLoader) { const block1_addr = this.EFUSE_BASE + 0x044; const num_word = 3; const pos = 18; @@ -54,24 +54,24 @@ export class ESP32C6ROM extends ROM { return ret; } - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { let desc: string; - const pkg_ver = await this.get_pkg_version(loader); + const pkg_ver = await this.getPkgVersion(loader); if (pkg_ver === 0) { desc = "ESP32-C6"; } else { desc = "unknown ESP32-C6"; } - const chip_rev = await this.get_chip_revision(loader); + const chip_rev = await this.getChipRevision(loader); desc += " (revision " + chip_rev + ")"; return desc; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { return ["Wi-Fi"]; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { return 40; } @@ -80,7 +80,7 @@ export class ESP32C6ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { + public async readMac(loader: ESPLoader) { let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); @@ -108,7 +108,7 @@ export class ESP32C6ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp32h2.ts b/src/targets/esp32h2.ts index cb9005e..6b466c4 100644 --- a/src/targets/esp32h2.ts +++ b/src/targets/esp32h2.ts @@ -40,15 +40,15 @@ export class ESP32H2ROM extends ROM { public ROM_DATA = ESP32H2_STUB.data; public ROM_TEXT = ESP32H2_STUB.text; - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { return this.CHIP_NAME; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { return ["BLE", "IEEE802.15.4"]; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { // ESP32H2 XTAL is fixed to 32MHz return 32; } @@ -58,7 +58,7 @@ export class ESP32H2ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async _post_connect(loader: ESPLoader) { + public async postConnect(loader: ESPLoader) { const buf_no = (await loader.read_reg(this.UARTDEV_BUF_NO)) & 0xff; loader.debug("In _post_connect " + buf_no); if (buf_no == this.UARTDEV_BUF_NO_USB) { @@ -66,7 +66,7 @@ export class ESP32H2ROM extends ROM { } } - public async read_mac(loader: ESPLoader) { + public async readMac(loader: ESPLoader) { let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); @@ -94,7 +94,7 @@ export class ESP32H2ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp32s2.ts b/src/targets/esp32s2.ts index f736e39..494b665 100644 --- a/src/targets/esp32s2.ts +++ b/src/targets/esp32s2.ts @@ -36,7 +36,7 @@ export class ESP32S2ROM extends ROM { public ROM_DATA = ESP32S2_STUB.data; public ROM_TEXT = ESP32S2_STUB.text; - public async get_pkg_version(loader: ESPLoader) { + public async getPkgVersion(loader: ESPLoader): Promise { const num_word = 3; const block1_addr = this.EFUSE_BASE + 0x044; const addr = block1_addr + 4 * num_word; @@ -45,9 +45,9 @@ export class ESP32S2ROM extends ROM { return pkg_version; } - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { const chip_desc = ["ESP32-S2", "ESP32-S2FH16", "ESP32-S2FH32"]; - const pkg_ver = await this.get_pkg_version(loader); + const pkg_ver = await this.getPkgVersion(loader); if (pkg_ver >= 0 && pkg_ver <= 2) { return chip_desc[pkg_ver]; } else { @@ -55,9 +55,9 @@ export class ESP32S2ROM extends ROM { } } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { const features = ["Wi-Fi"]; - const pkg_ver = await this.get_pkg_version(loader); + const pkg_ver = await this.getPkgVersion(loader); if (pkg_ver == 1) { features.push("Embedded 2MB Flash"); } else if (pkg_ver == 2) { @@ -75,14 +75,14 @@ export class ESP32S2ROM extends ROM { return features; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { return 40; } public _d2h(d: number) { const h = (+d).toString(16); return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { + public async readMac(loader: ESPLoader) { let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); @@ -110,7 +110,7 @@ export class ESP32S2ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp32s3.ts b/src/targets/esp32s3.ts index 6e6b3d6..66eff2a 100644 --- a/src/targets/esp32s3.ts +++ b/src/targets/esp32s3.ts @@ -40,13 +40,13 @@ export class ESP32S3ROM extends ROM { public ROM_DATA = ESP32S3_STUB.data; public ROM_TEXT = ESP32S3_STUB.text; - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { return "ESP32-S3"; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { return ["Wi-Fi", "BLE"]; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { return 40; } public _d2h(d: number) { @@ -54,7 +54,7 @@ export class ESP32S3ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async _post_connect(loader: ESPLoader) { + public async postConnect(loader: ESPLoader) { const buf_no = (await loader.read_reg(this.UARTDEV_BUF_NO)) & 0xff; loader.debug("In _post_connect " + buf_no); if (buf_no == this.UARTDEV_BUF_NO_USB) { @@ -62,7 +62,7 @@ export class ESP32S3ROM extends ROM { } } - public async read_mac(loader: ESPLoader) { + public async readMac(loader: ESPLoader) { let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); @@ -90,7 +90,7 @@ export class ESP32S3ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp8266.ts b/src/targets/esp8266.ts index 6f3389e..f786b17 100644 --- a/src/targets/esp8266.ts +++ b/src/targets/esp8266.ts @@ -42,27 +42,27 @@ export class ESP8266ROM extends ROM { public ROM_DATA = ESP8266_STUB.data; public ROM_TEXT = ESP8266_STUB.text; - public async read_efuse(loader: ESPLoader, offset: number) { + public async readEfuse(loader: ESPLoader, offset: number): Promise { const addr = this.EFUSE_RD_REG_BASE + 4 * offset; loader.debug("Read efuse " + addr); return await loader.read_reg(addr); } - public async get_chip_description(loader: ESPLoader) { - const efuse3 = await this.read_efuse(loader, 2); - const efuse0 = await this.read_efuse(loader, 0); + public async getChipDescription(loader: ESPLoader) { + const efuse3 = await this.readEfuse(loader, 2); + const efuse0 = await this.readEfuse(loader, 0); const is_8285 = ((efuse0 & (1 << 4)) | (efuse3 & (1 << 16))) != 0; // One or the other efuse bit is set for ESP8285 return is_8285 ? "ESP8285" : "ESP8266EX"; } - public get_chip_features = async (loader: ESPLoader) => { + public getChipFeatures = async (loader: ESPLoader) => { const features = ["WiFi"]; - if ((await this.get_chip_description(loader)) == "ESP8285") features.push("Embedded Flash"); + if ((await this.getChipDescription(loader)) == "ESP8285") features.push("Embedded Flash"); return features; }; - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { const uart_div = (await loader.read_reg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; const ets_xtal = (loader.transport.baudrate * uart_div) / 1000000 / this.XTAL_CLK_DIVIDER; let norm_xtal; @@ -88,12 +88,12 @@ export class ESP8266ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { - let mac0 = await this.read_efuse(loader, 0); + public async readMac(loader: ESPLoader) { + let mac0 = await this.readEfuse(loader, 0); mac0 = mac0 >>> 0; - let mac1 = await this.read_efuse(loader, 1); + let mac1 = await this.readEfuse(loader, 1); mac1 = mac1 >>> 0; - let mac3 = await this.read_efuse(loader, 3); + let mac3 = await this.readEfuse(loader, 3); mac3 = mac3 >>> 0; const mac = new Uint8Array(6); @@ -132,7 +132,7 @@ export class ESP8266ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/rom.ts b/src/targets/rom.ts index b055ed3..2591b6b 100644 --- a/src/targets/rom.ts +++ b/src/targets/rom.ts @@ -1,25 +1,77 @@ import { ESPLoader } from "../esploader"; +/** + * Represents a chip ROM with basic registers field and abstract functions. + */ export abstract class ROM { - // abstract read_efuse(loader: ESPLoader, offset: number): Promise; //esp32 + /** + * 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; - // abstract get_pkg_version(loader: ESPLoader): Promise; // not in esp32s3 + /** + * 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; - // abstract get_chip_revision(loader: ESPLoader): Promise; esp32 + /** + * 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; - abstract get_chip_description(loader: ESPLoader): Promise; - - abstract get_chip_features(loader: ESPLoader): Promise; - - abstract get_crystal_freq(loader: ESPLoader): Promise; + /** + * 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; + /** + * 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; + /** + * 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; + /** + * 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; - abstract read_mac(loader: ESPLoader): Promise; + /** + * 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; - _post_connect?(loader: ESPLoader): Promise; + /** + * Function to be executed after chip connection + * @param {ESPLoader} loader - Loader class to communicate with chip. + */ + postConnect?(loader: ESPLoader): Promise; - get_erase_size(offset: number, size: number) { + /** + * 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 { return size; } From 1ac5992774af1a8cffefc375d0e0ef2eff94f773 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Tue, 1 Aug 2023 22:16:20 +0800 Subject: [PATCH 2/9] finish init doc add typedoc to generate api doc --- .gitignore | 1 + package-lock.json | 762 +++++++++++++++++++++++++---------------- package.json | 4 +- src/esploader.ts | 515 ++++++++++++++++++++-------- src/index.ts | 4 +- src/reset.ts | 25 ++ src/targets/esp32.ts | 6 +- src/targets/esp32c3.ts | 8 +- src/targets/esp32c6.ts | 8 +- src/targets/esp32h2.ts | 6 +- src/targets/esp32s2.ts | 8 +- src/targets/esp32s3.ts | 6 +- src/targets/esp8266.ts | 4 +- src/webserial.ts | 89 ++++- tsconfig.json | 4 + 15 files changed, 972 insertions(+), 478 deletions(-) diff --git a/.gitignore b/.gitignore index 05532d3..b7fac20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules lib bundle.js +docs esptool-js-*.tgz .vscode/settings.json .parcel-cache diff --git a/package-lock.json b/package-lock.json index 248b348..a2a8ca4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "prettier": "^2.7.1", "rimraf": "^3.0.2", "rollup": "^3.3.0", + "typedoc": "^0.24.8", "typescript": "^4.8.4" } }, @@ -116,9 +117,9 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true, "bin": { @@ -160,9 +161,9 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true, "bin": { @@ -391,9 +392,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", "dev": true, "peer": true, "bin": { @@ -572,9 +573,9 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", @@ -810,12 +811,6 @@ } } }, - "node_modules/@rollup/pluginutils/node_modules/@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - }, "node_modules/@types/eslint": { "version": "8.4.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", @@ -839,9 +834,9 @@ } }, "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "dev": true }, "node_modules/@types/json-schema": { @@ -851,9 +846,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "version": "20.4.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", + "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", "dev": true, "peer": true }, @@ -1069,73 +1064,73 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "peer": true, "dependencies": { @@ -1143,9 +1138,9 @@ } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "peer": true, "dependencies": { @@ -1153,79 +1148,79 @@ } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.11.6", "@xtuc/long": "4.2.2" } }, @@ -1244,9 +1239,9 @@ "peer": true }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1256,9 +1251,9 @@ } }, "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, "peer": true, "peerDependencies": { @@ -1348,6 +1343,12 @@ "node": ">=8" } }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", + "dev": true + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1702,9 +1703,9 @@ "peer": true }, "node_modules/enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dev": true, "peer": true, "dependencies": { @@ -1716,9 +1717,9 @@ } }, "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", "dev": true, "peer": true }, @@ -2654,6 +2655,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2707,6 +2714,12 @@ "node": ">=10" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "node_modules/magic-string": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", @@ -2735,14 +2748,26 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3199,9 +3224,9 @@ "peer": true }, "node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "peer": true, "dependencies": { @@ -3233,9 +3258,9 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", "dev": true, "peer": true, "dependencies": { @@ -3263,6 +3288,18 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.3.tgz", + "integrity": "sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==", + "dev": true, + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -3378,13 +3415,13 @@ } }, "node_modules/terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "dev": true, "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -3396,17 +3433,17 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", "dev": true, "peer": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.14", + "@jridgewell/trace-mapping": "^0.3.17", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" }, "engines": { "node": ">= 10.13.0" @@ -3507,6 +3544,51 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typedoc": { + "version": "0.24.8", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", + "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.0", + "shiki": "^0.14.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", @@ -3556,6 +3638,18 @@ "punycode": "^2.1.0" } }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -3571,23 +3665,23 @@ } }, "node_modules/webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dev": true, "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", + "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -3596,9 +3690,9 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", + "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -3644,9 +3738,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3744,9 +3838,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true } @@ -3778,9 +3872,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true } @@ -3962,9 +4056,9 @@ } }, "@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", "dev": true, "peer": true }, @@ -4096,9 +4190,9 @@ "dev": true }, "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.3.0", @@ -4245,14 +4339,6 @@ "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^2.3.1" - }, - "dependencies": { - "@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - } } }, "@types/eslint": { @@ -4278,9 +4364,9 @@ } }, "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "dev": true }, "@types/json-schema": { @@ -4290,9 +4376,9 @@ "dev": true }, "@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "version": "20.4.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", + "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", "dev": true, "peer": true }, @@ -4419,73 +4505,73 @@ } }, "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "dev": true, "peer": true }, "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true, "peer": true }, "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", "dev": true, "peer": true }, "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "dev": true, "peer": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" } }, "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "peer": true, "requires": { @@ -4493,9 +4579,9 @@ } }, "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "peer": true, "requires": { @@ -4503,79 +4589,79 @@ } }, "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "dev": true, "peer": true }, "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" } }, "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" } }, "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.11.6", "@xtuc/long": "4.2.2" } }, @@ -4594,15 +4680,15 @@ "peer": true }, "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true }, "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, "peer": true, "requires": {} @@ -4669,6 +4755,12 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, + "ansi-sequence-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -4925,9 +5017,9 @@ "peer": true }, "enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dev": true, "peer": true, "requires": { @@ -4936,9 +5028,9 @@ } }, "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", "dev": true, "peer": true }, @@ -5631,6 +5723,12 @@ "dev": true, "peer": true }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5672,6 +5770,12 @@ "yallist": "^4.0.0" } }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "magic-string": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", @@ -5691,13 +5795,19 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, + "marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -6005,9 +6115,9 @@ "peer": true }, "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "peer": true, "requires": { @@ -6026,9 +6136,9 @@ } }, "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", "dev": true, "peer": true, "requires": { @@ -6050,6 +6160,18 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "shiki": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.3.tgz", + "integrity": "sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==", + "dev": true, + "requires": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6138,29 +6260,29 @@ "peer": true }, "terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "dev": true, "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" } }, "terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", "dev": true, "peer": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.14", + "@jridgewell/trace-mapping": "^0.3.17", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" } }, "text-table": { @@ -6221,6 +6343,38 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typedoc": { + "version": "0.24.8", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", + "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", + "dev": true, + "requires": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.0", + "shiki": "^0.14.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", @@ -6247,6 +6401,18 @@ "punycode": "^2.1.0" } }, + "vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, "watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -6259,23 +6425,23 @@ } }, "webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dev": true, "peer": true, "requires": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", + "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -6284,9 +6450,9 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", + "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" } @@ -6308,9 +6474,9 @@ } }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "wrappy": { diff --git a/package.json b/package.json index 2057ec2..60a9ba9 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,9 @@ ], "scripts": { "build": "npm run clean && tsc && rollup --config", - "clean": "rimraf lib bundle.js", + "clean": "rimraf docs lib bundle.js", "format": "prettier --write \"src/**/*.ts\"", + "genDocs": "npm run clean && typedoc", "lint": "eslint . --ext .ts", "lintAndFix": "eslint . --ext .ts --fix", "prepare": "npm run build", @@ -48,6 +49,7 @@ "prettier": "^2.7.1", "rimraf": "^3.0.2", "rollup": "^3.3.0", + "typedoc": "^0.24.8", "typescript": "^4.8.4" } } diff --git a/src/esploader.ts b/src/esploader.ts index 5e0e144..4e42d0b 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -4,34 +4,105 @@ import { Transport, SerialOptions } from "./webserial"; import { ROM } from "./targets/rom"; import { customReset, usbJTAGSerialReset } from "./reset"; +/** + * 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 initialize the ESPLoader class. - * { - * transport: A Transport class that provide serial communication to the chip - * baudrate: The baud rate used for connecting the device - * terminal?: A IEspLoaderTerminal wrapper interface to call the terminal - * romBaudrate: The baudrate described by the chip ROM class; - * debugLogging: Enable/Disable logging for debug - * } + * 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; - baudrate: number; + + /** + * 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; } @@ -82,6 +153,7 @@ async function magic2Chip(magic: number): Promise { * 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 { /** @@ -100,19 +172,6 @@ export interface IEspLoaderTerminal { write: (data: string) => void; } -/** - * An ESP loader class to perform serial communication - * such as read and write flash memory and registers. - * - * LoaderOptions: - * { - * transport: Transport; - * baudrate: number; - * terminal?: IEspLoaderTerminal; - * romBaudrate: number; - * debugLogging?: boolean; - * } - */ export class ESPLoader { ESP_RAM_BLOCK = 0x1800; ESP_FLASH_BEGIN = 0x02; @@ -186,22 +245,9 @@ export class ESPLoader { private debugLogging = false; /** - * Create a new ESPLoader instance using a LoaderOptions object. - * @param {LoaderOptions} options - Options for ESPLoader. - * - * { - * - * transport: Transport; - * - * baudrate: number; - * - * terminal?: IEspLoaderTerminal; - * - * romBaudrate: number; - * - * debugLogging?: boolean; - * - * } + * 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. */ constructor(options: LoaderOptions) { this.IS_STUB = false; @@ -227,7 +273,7 @@ export class ESPLoader { } this.info("esptool.js"); - this.info("Serial port " + this.transport.get_info()); + this.info("Serial port " + this.transport.getInfo()); } _sleep(ms: number) { @@ -373,7 +419,10 @@ export class ESPLoader { return u8_array; } - async flush_input() { + /** + * Flush the serial input by raw read with 200 ms timeout. + */ + async flushInput() { try { await this.transport.rawRead(200); } catch (e) { @@ -393,7 +442,7 @@ export class ESPLoader { if (op == null || op_ret == op) { return [val, data]; } else if (data[0] != 0 && data[1] == this.ROM_INVALID_RECV_MSG) { - await this.flush_input(); + await this.flushInput(); throw new ESPError("unsupported command error"); } } @@ -402,13 +451,13 @@ export class ESPLoader { } /** - * Run a serial command in the chip + * Write a serial command to the chip * @param {number} op - Operation number - * @param {string} data - Unsigned 8 bit array - * @param {number} chk - binary string input - * @param {boolean} waitResponse - binary string input - * @param {number} btimeoutStr - binary string input - * @returns {[number, Uint8Array]} Return a 8 bit unsigned integer array. + * @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. */ async command( op: number | null = null, @@ -442,12 +491,26 @@ export class ESPLoader { return this.read_packet(op, timeout); } - async read_reg(addr: number, timeout = 3000) { + /** + * Read a register from chip. + * @param {number} addr - Register address number + * @param {number} timeout - Timeout in milliseconds (Default: 3000ms) + * @returns {number} - Command number value + */ + async readReg(addr: number, timeout = 3000) { const pkt = this._intToByteArray(addr); const val = await this.command(this.ESP_READ_REG, pkt, undefined, undefined, timeout); return val[0]; } + /** + * 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} delay_us Delay number + * @param {number} delay_after_us Delay after previous delay + */ async write_reg(addr: number, value: number, mask = 0xffffffff, delay_us = 0, delay_after_us = 0) { let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(value)); pkt = this._appendArray(pkt, this._intToByteArray(mask)); @@ -460,9 +523,12 @@ export class ESPLoader { pkt = this._appendArray(pkt, this._intToByteArray(delay_after_us)); } - await this.check_command("write target memory", this.ESP_WRITE_REG, pkt); + await this.checkCommand("write target memory", this.ESP_WRITE_REG, pkt); } + /** + * Sync chip by sending sync command. + */ async sync() { this.debug("Sync"); const cmd = new Uint8Array(36); @@ -484,10 +550,16 @@ export class ESPLoader { } } - async _connect_attempt(mode = "default_reset", esp32r0_delay = false) { + /** + * 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} esp32r0_delay - Enable delay for ESP32 R0 + * @returns {string} - Returns 'success' or 'error' message. + */ + async _connectAttempt(mode = "default_reset", esp32r0_delay = false) { this.debug("_connect_attempt " + mode + " " + esp32r0_delay); if (mode !== "no_reset") { - if (this.transport.get_pid() === this.USB_JTAG_SERIAL_PID) { + if (this.transport.getPid() === this.USB_JTAG_SERIAL_PID) { // Custom reset sequence, which is required when the device // is connecting via its USB-JTAG-Serial peripheral await usbJTAGSerialReset(this.transport); @@ -532,17 +604,23 @@ export class ESPLoader { return "error"; } + /** + * Perform a connection to chip. + * @param mode - Reset mode to use. Example: 'default_reset' | 'no_reset' + * @param attempts - Number of connection attempts + * @param detecting - Detect the connected chip + */ async connect(mode = "default_reset", attempts = 7, detecting = false) { let i; let resp; this.info("Connecting...", false); await this.transport.connect(this.romBaudrate, this.serialOptions); for (i = 0; i < attempts; i++) { - resp = await this._connect_attempt(mode, false); + resp = await this._connectAttempt(mode, false); if (resp === "success") { break; } - resp = await this._connect_attempt(mode, true); + resp = await this._connectAttempt(mode, true); if (resp === "success") { break; } @@ -553,7 +631,7 @@ export class ESPLoader { this.info("\n\r", false); if (!detecting) { - const chip_magic_value = (await this.read_reg(0x40001000)) >>> 0; + const chip_magic_value = (await this.readReg(0x40001000)) >>> 0; this.debug("Chip Magic " + chip_magic_value.toString(16)); const chip = await magic2Chip(chip_magic_value); if (this.chip === null) { @@ -564,7 +642,11 @@ export class ESPLoader { } } - async detect_chip(mode = "default_reset") { + /** + * Connect and detect the existing chip. + * @param mode Reset mode to use for connection. + */ + async detectChip(mode = "default_reset") { await this.connect(mode); this.info("Detecting chip type... ", false); if (this.chip != null) { @@ -574,7 +656,16 @@ export class ESPLoader { } } - async check_command( + /** + * Execute the command and check the command response. + * @param {string} op_description 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 + */ + async checkCommand( op_description = "", op: number | null = null, data: Uint8Array = new Uint8Array(0), @@ -590,15 +681,27 @@ export class ESPLoader { } } - async mem_begin(size: number, blocks: number, blocksize: number, offset: number) { + /** + * 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 + */ + async memBegin(size: number, blocks: number, blocksize: number, offset: number) { /* XXX: Add check to ensure that STUB is not getting overwritten */ this.debug("mem_begin " + size + " " + blocks + " " + blocksize + " " + offset.toString(16)); let pkt = this._appendArray(this._intToByteArray(size), this._intToByteArray(blocks)); pkt = this._appendArray(pkt, this._intToByteArray(blocksize)); pkt = this._appendArray(pkt, this._intToByteArray(offset)); - await this.check_command("enter RAM download mode", this.ESP_MEM_BEGIN, pkt); + await this.checkCommand("enter RAM download mode", this.ESP_MEM_BEGIN, pkt); } + /** + * Get the checksum for given unsigned 8-bit array + * @param {Uint8Array} data Unsigned 8-bit integer array + * @returns - Array checksum + */ checksum = function (data: Uint8Array) { let i; let chk = 0xef; @@ -609,27 +712,46 @@ export class ESPLoader { return chk; }; - async mem_block(buffer: Uint8Array, seq: number) { + /** + * Send a block of image to RAM + * @param buffer Unsigned 8-bit array + * @param seq Sequence number + */ + async memBlock(buffer: Uint8Array, seq: number) { let pkt = this._appendArray(this._intToByteArray(buffer.length), this._intToByteArray(seq)); pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, buffer); const checksum = this.checksum(buffer); - await this.check_command("write to target RAM", this.ESP_MEM_DATA, pkt, checksum); + await this.checkCommand("write to target RAM", this.ESP_MEM_DATA, pkt, checksum); } - async mem_finish(entrypoint: number) { + /** + * Leave RAM download mode and run application + * @param {number} entrypoint - Entrypoint number + */ + async memFinish(entrypoint: number) { const is_entry = entrypoint === 0 ? 1 : 0; const pkt = this._appendArray(this._intToByteArray(is_entry), this._intToByteArray(entrypoint)); - await this.check_command("leave RAM download mode", this.ESP_MEM_END, pkt, undefined, 50); // XXX: handle non-stub with diff timeout + await this.checkCommand("leave RAM download mode", this.ESP_MEM_END, pkt, undefined, 50); // XXX: handle non-stub with diff timeout } - async flash_spi_attach(hspi_arg: number) { + /** + * Configure SPI flash pins + * @param {number} hspi_arg - Argument for SPI attachment + */ + async flashSpiAttach(hspi_arg: number) { const pkt = this._intToByteArray(hspi_arg); - await this.check_command("configure SPI flash pins", this.ESP_SPI_ATTACH, pkt); + await this.checkCommand("configure SPI flash pins", this.ESP_SPI_ATTACH, pkt); } - timeout_per_mb = function (seconds_per_mb: number, size_bytes: number) { + /** + * Scale timeouts which are size-specific. + * @param {number} seconds_per_mb Seconds per megabytes as number + * @param {number} size_bytes Size bytes number + * @returns {number} - Scaled timeout for specified size. + */ + timeoutPerMb = function (seconds_per_mb: number, size_bytes: number) { const result = seconds_per_mb * (size_bytes / 1000000); if (result < 3000) { return 3000; @@ -638,7 +760,13 @@ export class ESPLoader { } }; - async flash_begin(size: number, offset: 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. + */ + async flashBegin(size: number, offset: number) { const num_blocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); const erase_size = this.chip.getEraseSize(offset, size); @@ -647,7 +775,7 @@ export class ESPLoader { let timeout = 3000; if (this.IS_STUB == false) { - timeout = this.timeout_per_mb(this.ERASE_REGION_TIMEOUT_PER_MB, size); + timeout = this.timeoutPerMb(this.ERASE_REGION_TIMEOUT_PER_MB, size); } this.debug( @@ -660,7 +788,7 @@ export class ESPLoader { pkt = this._appendArray(pkt, this._intToByteArray(0)); // XXX: Support encrypted } - await this.check_command("enter Flash download mode", this.ESP_FLASH_BEGIN, pkt, undefined, timeout); + await this.checkCommand("enter Flash download mode", this.ESP_FLASH_BEGIN, pkt, undefined, timeout); const t2 = d.getTime(); if (size != 0 && this.IS_STUB == false) { @@ -669,7 +797,14 @@ export class ESPLoader { return num_blocks; } - async flash_defl_begin(size: number, compsize: number, offset: number) { + /** + * Start downloading compressed data to Flash (performs an erase) + * @param {number} size Write size + * @param {number} compsize Compressed size + * @param {number} offset + * @returns {number} Returns number of blocks (size self.FLASH_WRITE_SIZE) to write. + */ + async flashDeflBegin(size: number, compsize: number, offset: number) { const num_blocks = Math.floor((compsize + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); const erase_blocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); @@ -682,7 +817,7 @@ export class ESPLoader { timeout = 3000; } else { write_size = erase_blocks * this.FLASH_WRITE_SIZE; - timeout = this.timeout_per_mb(this.ERASE_REGION_TIMEOUT_PER_MB, write_size); + timeout = this.timeoutPerMb(this.ERASE_REGION_TIMEOUT_PER_MB, write_size); } this.info("Compressed " + size + " bytes to " + compsize + "..."); @@ -698,7 +833,7 @@ export class ESPLoader { ) { pkt = this._appendArray(pkt, this._intToByteArray(0)); } - await this.check_command("enter compressed flash mode", this.ESP_FLASH_DEFL_BEGIN, pkt, undefined, timeout); + await this.checkCommand("enter compressed flash mode", this.ESP_FLASH_DEFL_BEGIN, pkt, undefined, timeout); const t2 = d.getTime(); if (size != 0 && this.IS_STUB === false) { this.info("Took " + (t2 - t1) / 1000 + "." + ((t2 - t1) % 1000) + "s to erase flash block"); @@ -706,7 +841,13 @@ export class ESPLoader { return num_blocks; } - async flash_block(data: Uint8Array, seq: number, timeout: 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) + */ + async flashBlock(data: Uint8Array, seq: number, timeout: number) { let pkt = this._appendArray(this._intToByteArray(data.length), this._intToByteArray(seq)); pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, this._intToByteArray(0)); @@ -714,10 +855,16 @@ export class ESPLoader { const checksum = this.checksum(data); - await this.check_command("write to target Flash after seq " + seq, this.ESP_FLASH_DATA, pkt, checksum, timeout); + await this.checkCommand("write to target Flash after seq " + seq, this.ESP_FLASH_DATA, pkt, checksum, timeout); } - async flash_defl_block(data: Uint8Array, seq: number, timeout: number) { + /** + * 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) + */ + async flashDeflBlock(data: Uint8Array, seq: number, timeout: number) { let pkt = this._appendArray(this._intToByteArray(data.length), this._intToByteArray(seq)); pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, this._intToByteArray(0)); @@ -726,7 +873,7 @@ export class ESPLoader { const checksum = this.checksum(data); this.debug("flash_defl_block " + data[0].toString(16) + " " + data[1].toString(16)); - await this.check_command( + await this.checkCommand( "write compressed data to flash after seq " + seq, this.ESP_FLASH_DEFL_DATA, pkt, @@ -735,21 +882,44 @@ export class ESPLoader { ); } - async flash_finish(reboot = false) { + /** + * Leave flash mode and run/reboot + * @param {boolean} reboot Reboot after leaving flash mode ? + */ + async flashFinish(reboot = false) { const val = reboot ? 0 : 1; const pkt = this._intToByteArray(val); - await this.check_command("leave Flash mode", this.ESP_FLASH_END, pkt); + await this.checkCommand("leave Flash mode", this.ESP_FLASH_END, pkt); } - async flash_defl_finish(reboot = false) { + /** + * Leave compressed flash mode and run/reboot + * @param {boolean} reboot Reboot after leaving flash mode ? + */ + async flashDeflFinish(reboot = false) { const val = reboot ? 0 : 1; const pkt = this._intToByteArray(val); - await this.check_command("leave compressed flash mode", this.ESP_FLASH_DEFL_END, pkt); + await this.checkCommand("leave compressed flash mode", this.ESP_FLASH_DEFL_END, pkt); } - async run_spiflash_command(spiflash_command: number, data: Uint8Array, read_bits: number) { + /** + * 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 spiflash_command is an actual command + * byte, sent over the wire. + * + * After writing command byte, writes 'data' to MOSI and then + * reads back 'read_bits' of reply on MISO. Result is a number. + * @param {number} spiflash_command + * @param {Uint8Array} data + * @param {number} read_bits + * @returns {number} Register SPI_W0_REG value + */ + async runSpiflashCommand(spiflash_command: number, data: Uint8Array, read_bits: number) { // SPI_USR register flags const SPI_USR_COMMAND = 1 << 31; const SPI_USR_MISO = 1 << 28; @@ -797,8 +967,8 @@ export class ESPLoader { } const data_bits = data.length * 8; - const old_spi_usr = await this.read_reg(SPI_USR_REG); - const old_spi_usr2 = await this.read_reg(SPI_USR2_REG); + const old_spi_usr = await this.readReg(SPI_USR_REG); + const old_spi_usr2 = await this.readReg(SPI_USR2_REG); let flags = SPI_USR_COMMAND; let i; if (read_bits > 0) { @@ -827,7 +997,7 @@ export class ESPLoader { } await this.write_reg(SPI_CMD_REG, SPI_CMD_USR); for (i = 0; i < 10; i++) { - val = (await this.read_reg(SPI_CMD_REG)) & SPI_CMD_USR; + val = (await this.readReg(SPI_CMD_REG)) & SPI_CMD_USR; if (val == 0) { break; } @@ -835,23 +1005,31 @@ export class ESPLoader { if (i === 10) { throw new ESPError("SPI command did not complete in time"); } - const stat = await this.read_reg(SPI_W0_REG); + const stat = await this.readReg(SPI_W0_REG); await this.write_reg(SPI_USR_REG, old_spi_usr); await this.write_reg(SPI_USR2_REG, old_spi_usr2); return stat; } - async read_flash_id() { + /** + * Read flash id by executing the SPIFLASH_RDID flash command. + * @returns Register SPI_W0_REG value + */ + async readFlashId() { const SPIFLASH_RDID = 0x9f; const pkt = new Uint8Array(0); - return await this.run_spiflash_command(SPIFLASH_RDID, pkt, 24); + return await this.runSpiflashCommand(SPIFLASH_RDID, pkt, 24); } - async erase_flash() { + /** + * Execute the erase flash command + * @returns {Promise} Erase flash command result + */ + async eraseFlash(): Promise { this.info("Erasing flash (this may take a while)..."); let d = new Date(); const t1 = d.getTime(); - const ret = await this.check_command( + const ret = await this.checkCommand( "erase flash", this.ESP_ERASE_FLASH, undefined, @@ -864,17 +1042,28 @@ export class ESPLoader { return ret; } - toHex(buffer: 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 { return Array.prototype.map.call(buffer, (x) => ("00" + x.toString(16)).slice(-2)).join(""); } - async flash_md5sum(addr: number, size: number) { - const timeout = this.timeout_per_mb(this.MD5_TIMEOUT_PER_MB, size); + /** + * Calculate the MD5 Checksum command + * @param addr Address number + * @param size Package size + * @returns {string} MD5 Checksum string + */ + async flashMd5sum(addr: number, size: number): Promise { + const timeout = this.timeoutPerMb(this.MD5_TIMEOUT_PER_MB, size); let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(size)); pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, this._intToByteArray(0)); - let res = await this.check_command("calculate md5sum", this.ESP_SPI_FLASH_MD5, pkt, undefined, timeout); + let res = await this.checkCommand("calculate md5sum", this.ESP_SPI_FLASH_MD5, pkt, undefined, timeout); if (res instanceof Uint8Array && res.length > 16) { res = res.slice(0, 16); } @@ -887,7 +1076,7 @@ export class ESPLoader { pkt = this._appendArray(pkt, this._intToByteArray(0x1000)); pkt = this._appendArray(pkt, this._intToByteArray(1024)); - const res = await this.check_command("read flash", this.ESP_READ_FLASH, pkt); + const res = await this.checkCommand("read flash", this.ESP_READ_FLASH, pkt); if (res != 0) { throw new ESPError("Failed to read memory: " + res); @@ -914,16 +1103,20 @@ export class ESPLoader { return resp; } - async run_stub() { + /** + * Upload the flasher ROM bootloader (flasher stub) to the chip. + * @returns {ROM} The Chip ROM + */ + async runStub() { this.info("Uploading stub..."); - let decoded = atob(this.chip.ROM_TEXT); + let decoded = Buffer.from(this.chip.ROM_TEXT).toString("base64"); let chardata = decoded.split("").map(function (x) { return x.charCodeAt(0); }); const text = new Uint8Array(chardata); - decoded = atob(this.chip.ROM_DATA); + decoded = Buffer.from(this.chip.ROM_DATA).toString("base64"); chardata = decoded.split("").map(function (x) { return x.charCodeAt(0); }); @@ -932,23 +1125,23 @@ export class ESPLoader { let blocks = Math.floor((text.length + this.ESP_RAM_BLOCK - 1) / this.ESP_RAM_BLOCK); let i; - await this.mem_begin(text.length, blocks, this.ESP_RAM_BLOCK, this.chip.TEXT_START); + await this.memBegin(text.length, blocks, this.ESP_RAM_BLOCK, this.chip.TEXT_START); for (i = 0; i < blocks; i++) { const from_offs = i * this.ESP_RAM_BLOCK; const to_offs = from_offs + this.ESP_RAM_BLOCK; - await this.mem_block(text.slice(from_offs, to_offs), i); + await this.memBlock(text.slice(from_offs, to_offs), i); } blocks = Math.floor((data.length + this.ESP_RAM_BLOCK - 1) / this.ESP_RAM_BLOCK); - await this.mem_begin(data.length, blocks, this.ESP_RAM_BLOCK, this.chip.DATA_START); + await this.memBegin(data.length, blocks, this.ESP_RAM_BLOCK, this.chip.DATA_START); for (i = 0; i < blocks; i++) { const from_offs = i * this.ESP_RAM_BLOCK; const to_offs = from_offs + this.ESP_RAM_BLOCK; - await this.mem_block(data.slice(from_offs, to_offs), i); + await this.memBlock(data.slice(from_offs, to_offs), i); } this.info("Running stub..."); - await this.mem_finish(this.chip.ENTRY); + await this.memFinish(this.chip.ENTRY); // Check up-to next 100 packets to see if stub is running for (let i = 0; i < 100; i++) { @@ -963,7 +1156,10 @@ export class ESPLoader { throw new ESPError("Failed to start stub. Unexpected response"); } - async change_baud() { + /** + * Change the chip baudrate. + */ + async changeBaud() { this.info("Changing baudrate to " + this.baudrate); const second_arg = this.IS_STUB ? this.transport.baudrate : 0; const pkt = this._appendArray(this._intToByteArray(this.baudrate), this._intToByteArray(second_arg)); @@ -991,8 +1187,13 @@ export class ESPLoader { } } - async main_fn(mode = "default_reset") { - await this.detect_chip(mode); + /** + * Execute the main function of ESPLoader. + * @param {string} mode Reset mode to use + * @returns {ROM} chip ROM + */ + async main(mode = "default_reset") { + await this.detectChip(mode); const chip = await this.chip.getChipDescription(this); this.info("Chip is " + chip); @@ -1005,15 +1206,20 @@ export class ESPLoader { await this.chip.postConnect(this); } - await this.run_stub(); + await this.runStub(); if (this.romBaudrate !== this.baudrate) { - await this.change_baud(); + await this.changeBaud(); } return chip; } - flash_size_bytes = function (flash_size: string) { + /** + * Get flash size bytes from flash size string. + * @param flash_size Flash Size string + * @returns {number} Flash size bytes + */ + flashSizeBytes = function (flash_size: string) { let flash_size_b = -1; if (flash_size.indexOf("KB") !== -1) { flash_size_b = parseInt(flash_size.slice(0, flash_size.indexOf("KB"))) * 1024; @@ -1023,7 +1229,12 @@ export class ESPLoader { return flash_size_b; }; - parse_flash_size_arg(flsz: string) { + /** + * Parse a given flash size string to a number + * @param flsz Flash size to request + * @returns {number} Flash size number + */ + parseFlashSizeArg(flsz: string) { if (typeof this.chip.FLASH_SIZES[flsz] === "undefined") { throw new ESPError( "Flash size " + flsz + " is not supported by this chip type. Supported sizes: " + this.chip.FLASH_SIZES, @@ -1032,21 +1243,24 @@ export class ESPLoader { return this.chip.FLASH_SIZES[flsz]; } - _update_image_flash_params( - image: string, - address: number, - flash_size: string, - flash_mode: string, - flash_freq: string, - ) { - this.debug("_update_image_flash_params " + flash_size + " " + flash_mode + " " + flash_freq); + /** + * 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) { + this.debug("_update_image_flash_params " + flashSize + " " + flashMode + " " + flashFreq); if (image.length < 8) { return image; } if (address != this.chip.BOOTLOADER_FLASH_OFFSET) { return image; } - if (flash_size === "keep" && flash_mode === "keep" && flash_freq === "keep") { + if (flashSize === "keep" && flashMode === "keep" && flashFreq === "keep") { this.info("Not changing the image"); return image; } @@ -1065,18 +1279,18 @@ export class ESPLoader { /* XXX: Yet to implement actual image verification */ - if (flash_mode !== "keep") { + if (flashMode !== "keep") { const flash_modes: { [key: string]: number } = { qio: 0, qout: 1, dio: 2, dout: 3 }; - a_flash_mode = flash_modes[flash_mode]; + a_flash_mode = flash_modes[flashMode]; } let a_flash_freq = flash_size_freq & 0x0f; - if (flash_freq !== "keep") { + if (flashFreq !== "keep") { const flash_freqs: { [key: string]: number } = { "40m": 0, "26m": 1, "20m": 2, "80m": 0xf }; - a_flash_freq = flash_freqs[flash_freq]; + a_flash_freq = flash_freqs[flashFreq]; } let a_flash_size = flash_size_freq & 0xf0; - if (flash_size !== "keep") { - a_flash_size = this.parse_flash_size_arg(flash_size); + if (flashSize !== "keep") { + a_flash_size = this.parseFlashSizeArg(flashSize); } const flash_params = (a_flash_mode << 8) | (a_flash_freq + a_flash_size); @@ -1090,10 +1304,14 @@ export class ESPLoader { return image; } - async write_flash(options: FlashOptions) { + /** + * 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. + */ + async writeFlash(options: FlashOptions) { this.debug("EspLoader program"); if (options.flashSize !== "keep") { - const flash_end = this.flash_size_bytes(options.flashSize); + const flash_end = this.flashSizeBytes(options.flashSize); for (let i = 0; i < options.fileArray.length; i++) { if (options.fileArray[i].data.length + options.fileArray[i].address > flash_end) { throw new ESPError(`File ${i + 1} doesn't fit in the available flash`); @@ -1102,7 +1320,7 @@ export class ESPLoader { } if (this.IS_STUB === true && options.eraseAll === true) { - await this.erase_flash(); + await this.eraseFlash(); } let image: string, address: number; for (let i = 0; i < options.fileArray.length; i++) { @@ -1116,7 +1334,7 @@ export class ESPLoader { this.debug("Warning: File is empty"); continue; } - image = this._update_image_flash_params(image, address, options.flashSize, options.flashMode, options.flashFreq); + image = this._updateImageFlashParams(image, address, options.flashSize, options.flashMode, options.flashFreq); let calcmd5: string | null = null; if (options.calculateMD5Hash) { calcmd5 = options.calculateMD5Hash(image); @@ -1127,9 +1345,9 @@ export class ESPLoader { if (options.compress) { const uncimage = this.bstrToUi8(image); image = this.ui8ToBstr(deflate(uncimage, { level: 9 })); - blocks = await this.flash_defl_begin(uncsize, image.length, address); + blocks = await this.flashDeflBegin(uncsize, image.length, address); } else { - blocks = await this.flash_begin(uncsize, address); + blocks = await this.flashBegin(uncsize, address); } let seq = 0; let bytes_sent = 0; @@ -1163,14 +1381,14 @@ export class ESPLoader { inflate.push(block, false); const block_uncompressed = total_len_uncompressed - len_uncompressed_previous; let block_timeout = 3000; - if (this.timeout_per_mb(this.ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed) > 3000) { - block_timeout = this.timeout_per_mb(this.ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed); + if (this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed) > 3000) { + block_timeout = this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed); } if (this.IS_STUB === false) { // ROM code writes block to flash before ACKing timeout = block_timeout; } - await this.flash_defl_block(block, seq, timeout); + await this.flashDeflBlock(block, seq, timeout); if (this.IS_STUB) { // Stub ACKs when block is received, then writes to flash while receiving the block after it timeout = block_timeout; @@ -1184,7 +1402,7 @@ export class ESPLoader { if (options.reportProgress) options.reportProgress(i, bytes_sent, totalBytes); } if (this.IS_STUB) { - await this.read_reg(this.CHIP_DETECT_MAGIC_REG_ADDR, timeout); + await this.readReg(this.CHIP_DETECT_MAGIC_REG_ADDR, timeout); } d = new Date(); const t = d.getTime() - t1; @@ -1202,7 +1420,7 @@ export class ESPLoader { ); } if (calcmd5) { - const res = await this.flash_md5sum(address, uncsize); + const res = await this.flashMd5sum(address, uncsize); if (new String(res).valueOf() != new String(calcmd5).valueOf()) { this.info("File md5: " + calcmd5); this.info("Flash md5: " + res); @@ -1215,18 +1433,21 @@ export class ESPLoader { this.info("Leaving..."); if (this.IS_STUB) { - await this.flash_begin(0, 0); + await this.flashBegin(0, 0); if (options.compress) { - await this.flash_defl_finish(); + await this.flashDeflFinish(); } else { - await this.flash_finish(); + await this.flashFinish(); } } } - async flash_id() { + /** + * Read SPI flash manufacturer and device id. + */ + async flashId() { this.debug("flash_id"); - const flashid = await this.read_flash_id(); + const flashid = await this.readFlashId(); this.info("Manufacturer: " + (flashid & 0xff).toString(16)); const flid_lowbyte = (flashid >> 16) & 0xff; this.info("Device: " + ((flashid >> 8) & 0xff).toString(16) + flid_lowbyte.toString(16)); @@ -1235,22 +1456,28 @@ export class ESPLoader { async get_flash_size() { this.debug("flash_id"); - const flashid = await this.read_flash_id(); + const flashid = await this.readFlashId(); const flid_lowbyte = (flashid >> 16) & 0xff; return this.DETECTED_FLASH_SIZES_NUM[flid_lowbyte]; } - async hard_reset() { + /** + * Perform a chip hard reset by setting RTS to LOW and then HIGH. + */ + async hardReset() { await this.transport.setRTS(true); // EN->LOW await this._sleep(100); await this.transport.setRTS(false); } - async soft_reset() { + /** + * Soft reset the device chip. Soft reset with run user code is the closest. + */ + async softReset() { if (!this.IS_STUB) { // "run user code" is as close to a soft reset as we can do - await this.flash_begin(0, 0); - await this.flash_finish(false); + await this.flashBegin(0, 0); + await this.flashFinish(false); } else if (this.chip.CHIP_NAME != "ESP8266") { throw new ESPError("Soft resetting is currently only supported on ESP8266"); } else { diff --git a/src/index.ts b/src/index.ts index 66af3ec..2287878 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,4 @@ export { IEspLoaderTerminal, ESPLoader, FlashOptions, LoaderOptions } from "./esploader"; -export { Transport } from "./webserial"; +export { classicReset, customReset, hardReset, usbJTAGSerialReset, validateCustomResetStringSequence } from "./reset"; +export { ROM } from "./targets/rom"; +export { Transport, SerialOptions } from "./webserial"; diff --git a/src/reset.ts b/src/reset.ts index 030b128..e0bd3b3 100644 --- a/src/reset.ts +++ b/src/reset.ts @@ -2,6 +2,7 @@ import { Transport } from "./webserial"; const DEFAULT_RESET_DELAY = 50; +/** Sleep function helper */ function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } @@ -20,6 +21,8 @@ function sleep(ms: number): Promise { * 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: Transport, resetDelay = DEFAULT_RESET_DELAY) { await transport.setDTR(false); @@ -43,6 +46,7 @@ export async function classicReset(transport: Transport, resetDelay = DEFAULT_RE * 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: Transport) { await transport.setRTS(false); @@ -74,6 +78,8 @@ export async function usbJTAGSerialReset(transport: Transport) { * 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: Transport, usingUsbOtg = false) { if (usingUsbOtg) { @@ -92,6 +98,22 @@ type CmdsArgsTypes = { W: number; }; +/** + * 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 seqStr Sequence string to validate + * @returns {boolean} Is the sequence string valid ? + */ export function validateCustomResetStringSequence(seqStr: string): boolean { const commands: (keyof CmdsArgsTypes)[] = ["D", "R", "W"]; @@ -135,6 +157,9 @@ export function validateCustomResetStringSequence(seqStr: string): boolean { * 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: Transport, sequenceString: string) { const resetDictionary: { [K in keyof CmdsArgsTypes]: (arg: CmdsArgsTypes[K]) => Promise } = { diff --git a/src/targets/esp32.ts b/src/targets/esp32.ts index c4da962..c9da96e 100644 --- a/src/targets/esp32.ts +++ b/src/targets/esp32.ts @@ -40,7 +40,7 @@ export class ESP32ROM extends ROM { public async readEfuse(loader: ESPLoader, offset: number): Promise { const addr = this.EFUSE_RD_REG_BASE + 4 * offset; loader.debug("Read efuse " + addr); - return await loader.read_reg(addr); + return await loader.readReg(addr); } public async getPkgVersion(loader: ESPLoader): Promise { @@ -53,7 +53,7 @@ export class ESP32ROM extends ROM { public async getChipRevision(loader: ESPLoader): Promise { const word3 = await this.readEfuse(loader, 3); const word5 = await this.readEfuse(loader, 5); - const apb_ctl_date = await loader.read_reg(this.DR_REG_SYSCON_BASE + 0x7c); + const apb_ctl_date = await loader.readReg(this.DR_REG_SYSCON_BASE + 0x7c); const rev_bit0 = (word3 >> 15) & 0x1; const rev_bit1 = (word5 >> 20) & 0x1; @@ -162,7 +162,7 @@ export class ESP32ROM extends ROM { } public async getCrystalFreq(loader: ESPLoader) { - const uart_div = (await loader.read_reg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; + const uart_div = (await loader.readReg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; const ets_xtal = (loader.transport.baudrate * uart_div) / 1000000 / this.XTAL_CLK_DIVIDER; let norm_xtal; if (ets_xtal > 33) { diff --git a/src/targets/esp32c3.ts b/src/targets/esp32c3.ts index 98e9dca..7f51544 100644 --- a/src/targets/esp32c3.ts +++ b/src/targets/esp32c3.ts @@ -40,7 +40,7 @@ export class ESP32C3ROM extends ROM { const num_word = 3; const block1_addr = this.EFUSE_BASE + 0x044; const addr = block1_addr + 4 * num_word; - const word3 = await loader.read_reg(addr); + const word3 = await loader.readReg(addr); const pkg_version = (word3 >> 21) & 0x07; return pkg_version; } @@ -50,7 +50,7 @@ export class ESP32C3ROM extends ROM { const num_word = 3; const pos = 18; const addr = block1_addr + 4 * num_word; - const ret = ((await loader.read_reg(addr)) & (0x7 << pos)) >> pos; + const ret = ((await loader.readReg(addr)) & (0x7 << pos)) >> pos; return ret; } @@ -81,9 +81,9 @@ export class ESP32C3ROM extends ROM { } public async readMac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; diff --git a/src/targets/esp32c6.ts b/src/targets/esp32c6.ts index c26463b..9835bf6 100644 --- a/src/targets/esp32c6.ts +++ b/src/targets/esp32c6.ts @@ -40,7 +40,7 @@ export class ESP32C6ROM extends ROM { const num_word = 3; const block1_addr = this.EFUSE_BASE + 0x044; const addr = block1_addr + 4 * num_word; - const word3 = await loader.read_reg(addr); + const word3 = await loader.readReg(addr); const pkg_version = (word3 >> 21) & 0x07; return pkg_version; } @@ -50,7 +50,7 @@ export class ESP32C6ROM extends ROM { const num_word = 3; const pos = 18; const addr = block1_addr + 4 * num_word; - const ret = ((await loader.read_reg(addr)) & (0x7 << pos)) >> pos; + const ret = ((await loader.readReg(addr)) & (0x7 << pos)) >> pos; return ret; } @@ -81,9 +81,9 @@ export class ESP32C6ROM extends ROM { } public async readMac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; diff --git a/src/targets/esp32h2.ts b/src/targets/esp32h2.ts index 6b466c4..5b44d75 100644 --- a/src/targets/esp32h2.ts +++ b/src/targets/esp32h2.ts @@ -59,7 +59,7 @@ export class ESP32H2ROM extends ROM { } public async postConnect(loader: ESPLoader) { - const buf_no = (await loader.read_reg(this.UARTDEV_BUF_NO)) & 0xff; + const buf_no = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; loader.debug("In _post_connect " + buf_no); if (buf_no == this.UARTDEV_BUF_NO_USB) { loader.ESP_RAM_BLOCK = this.USB_RAM_BLOCK; @@ -67,9 +67,9 @@ export class ESP32H2ROM extends ROM { } public async readMac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; diff --git a/src/targets/esp32s2.ts b/src/targets/esp32s2.ts index 494b665..2b59052 100644 --- a/src/targets/esp32s2.ts +++ b/src/targets/esp32s2.ts @@ -40,7 +40,7 @@ export class ESP32S2ROM extends ROM { const num_word = 3; const block1_addr = this.EFUSE_BASE + 0x044; const addr = block1_addr + 4 * num_word; - const word3 = await loader.read_reg(addr); + const word3 = await loader.readReg(addr); const pkg_version = (word3 >> 21) & 0x0f; return pkg_version; } @@ -66,7 +66,7 @@ export class ESP32S2ROM extends ROM { const num_word = 4; const block2_addr = this.EFUSE_BASE + 0x05c; const addr = block2_addr + 4 * num_word; - const word4 = await loader.read_reg(addr); + const word4 = await loader.readReg(addr); const block2_ver = (word4 >> 4) & 0x07; if (block2_ver == 1) { @@ -83,9 +83,9 @@ export class ESP32S2ROM extends ROM { return h.length === 1 ? "0" + h : h; } public async readMac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; diff --git a/src/targets/esp32s3.ts b/src/targets/esp32s3.ts index 66eff2a..53b3719 100644 --- a/src/targets/esp32s3.ts +++ b/src/targets/esp32s3.ts @@ -55,7 +55,7 @@ export class ESP32S3ROM extends ROM { } public async postConnect(loader: ESPLoader) { - const buf_no = (await loader.read_reg(this.UARTDEV_BUF_NO)) & 0xff; + const buf_no = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; loader.debug("In _post_connect " + buf_no); if (buf_no == this.UARTDEV_BUF_NO_USB) { loader.ESP_RAM_BLOCK = this.USB_RAM_BLOCK; @@ -63,9 +63,9 @@ export class ESP32S3ROM extends ROM { } public async readMac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; diff --git a/src/targets/esp8266.ts b/src/targets/esp8266.ts index f786b17..be56348 100644 --- a/src/targets/esp8266.ts +++ b/src/targets/esp8266.ts @@ -45,7 +45,7 @@ export class ESP8266ROM extends ROM { public async readEfuse(loader: ESPLoader, offset: number): Promise { const addr = this.EFUSE_RD_REG_BASE + 4 * offset; loader.debug("Read efuse " + addr); - return await loader.read_reg(addr); + return await loader.readReg(addr); } public async getChipDescription(loader: ESPLoader) { @@ -63,7 +63,7 @@ export class ESP8266ROM extends ROM { }; public async getCrystalFreq(loader: ESPLoader) { - const uart_div = (await loader.read_reg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; + const uart_div = (await loader.readReg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; const ets_xtal = (loader.transport.baudrate * uart_div) / 1000000 / this.XTAL_CLK_DIVIDER; let norm_xtal; if (ets_xtal > 33) { diff --git a/src/webserial.ts b/src/webserial.ts index acd5759..9785ad1 100644 --- a/src/webserial.ts +++ b/src/webserial.ts @@ -13,6 +13,14 @@ export interface SerialOptions { bufferSize?: number | undefined; flowControl?: FlowControlType | undefined; } + +/** + * Wrapper class around Webserial API to communicate with the serial device. + * + * @param {SerialPort} device - Requested device prompted by the browser. + * + * const port = await navigator.serial.requestPort(); + */ class Transport { public slip_reader_enabled = false; public left_over = new Uint8Array(0); @@ -20,18 +28,31 @@ class Transport { constructor(public device: SerialPort) {} - get_info() { + /** + * 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)}` : ""; } - get_pid() { + /** + * Request the serial device product id from SerialPortInfo. + * @returns {string} Return the product ID. + */ + getPid() { return this.device.getInfo().usbProductId; } - slip_writer(data: 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: Uint8Array) { let count_esc = 0; let i = 0, j = 0; @@ -62,8 +83,12 @@ class Transport { return out_data; } + /** + * Write binary data to device using the WebSerial device writable stream. + * @param data 8 bit unsigned data array to write to device. + */ async write(data: Uint8Array) { - const out_data = this.slip_writer(data); + const out_data = this.slipWriter(data); if (this.device.writable) { const writer = this.device.writable.getWriter(); @@ -72,6 +97,12 @@ class Transport { } } + /** + * 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) { const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); tmp.set(new Uint8Array(buffer1), 0); @@ -79,9 +110,13 @@ class Transport { return tmp.buffer; } - /* this function expects complete packet (hence reader reads for atleast 8 bytes. This function is - * stateless and returns the first wellformed packet only after replacing escape sequence */ - slip_reader(data: Uint8Array) { + /** + * Take a data array and return the first well formed packet after + * replacing the escape sequence. Reads at least 8 bytes. + * @param data Unsigned 8 bit array from the device read stream. + * @returns {Uint8Array} + */ + slipReader(data: Uint8Array) { let i = 0; let data_start = 0, data_end = 0; @@ -125,12 +160,18 @@ class Transport { return packet; } - async read(timeout = 0, min_data = 12) { + /** + * Read from serial device using the device ReadableStream. + * @param timeout Read timeout number + * @param 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.left_over; this.left_over = new Uint8Array(0); if (this.slip_reader_enabled) { - const val_final = this.slip_reader(packet); + const val_final = this.slipReader(packet); if (val_final.length > 0) { return val_final; } @@ -156,7 +197,7 @@ class Transport { } const p = new Uint8Array(this._appendBuffer(packet.buffer, value.buffer)); packet = p; - } while (packet.length < min_data); + } while (packet.length < minData); } finally { if (timeout > 0) { clearTimeout(t); @@ -164,11 +205,16 @@ class Transport { reader.releaseLock(); } if (this.slip_reader_enabled) { - return this.slip_reader(packet); + return this.slipReader(packet); } return packet; } + /** + * Read from serial device without slip formatting. + * @param timeout Read timeout in milliseconds (ms) + * @returns {Uint8Array} 8 bit unsigned data array read from device. + */ async rawRead(timeout = 0) { if (this.left_over.length != 0) { const p = this.left_over; @@ -200,6 +246,11 @@ class Transport { } _DTR_state = false; + /** + * 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: boolean) { await this.device.setSignals({ requestToSend: state }); // # Work-around for adapters on Windows using the usbser.sys driver: @@ -209,11 +260,20 @@ class Transport { 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: boolean) { 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. + */ async connect(baud = 115200, serialOptions: SerialOptions = {}) { await this.device.open({ baudRate: baud, @@ -231,6 +291,10 @@ class Transport { 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: number) { while ( (this.device.readable && this.device.readable.locked) || @@ -240,6 +304,9 @@ class Transport { } } + /** + * Disconnect from serial device by running SerialPort.close() after streams unlock. + */ async disconnect() { await this.waitForUnlock(400); await this.device.close(); diff --git a/tsconfig.json b/tsconfig.json index ff66898..c6fc028 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,5 +15,9 @@ "resolveJsonModule": true, "strict": true }, + "typedocOptions": { + "entryPoints": ["src/index.ts"], + "out": "docs" + }, "include": ["src/**/*"] } From cfce4f5a5c74d743390411186feb7f5da9158c47 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Tue, 1 Aug 2023 22:21:00 +0800 Subject: [PATCH 3/9] fix lint errors --- src/esploader.ts | 1 + src/webserial.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/esploader.ts b/src/esploader.ts index 4e42d0b..054ae0b 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -528,6 +528,7 @@ export class ESPLoader { /** * Sync chip by sending sync command. + * @returns {[number, Uint8Array]} Command result */ async sync() { this.debug("Sync"); diff --git a/src/webserial.ts b/src/webserial.ts index 9785ad1..a97a3e9 100644 --- a/src/webserial.ts +++ b/src/webserial.ts @@ -113,7 +113,7 @@ class Transport { /** * Take a data array and return the first well formed packet after * replacing the escape sequence. Reads at least 8 bytes. - * @param data Unsigned 8 bit array from the device read stream. + * @param {Uint8Array} data Unsigned 8 bit array from the device read stream. * @returns {Uint8Array} */ slipReader(data: Uint8Array) { @@ -162,8 +162,8 @@ class Transport { /** * Read from serial device using the device ReadableStream. - * @param timeout Read timeout number - * @param minData Minimum packet array length + * @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) { From 10628937de5a7be230176f218d0a138862426ca9 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Wed, 2 Aug 2023 20:15:33 +0800 Subject: [PATCH 4/9] add docs to gh pages fix lint --- .github/workflows/pages.yml | 4 +- examples/typescript/src/index.html | 3 ++ examples/typescript/src/index.ts | 40 +++++++++++--- package-lock.json | 87 ++++++++++++++++++++++++++++++ package.json | 3 +- src/esploader.ts | 55 ++++++++++--------- src/reset.ts | 10 ++-- src/webserial.ts | 11 ++-- 8 files changed, 169 insertions(+), 44 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 54d52e2..d5badff 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -33,12 +33,14 @@ jobs: - name: Install Node modules run: | npm install - - name: Build project + - name: Build example project and copy docs run: | npm run build + npm run genDocs cd examples/typescript npm install npm run build + cp -r ../../docs dist - name: Setup Pages uses: actions/configure-pages@v2 - name: Upload artifact diff --git a/examples/typescript/src/index.html b/examples/typescript/src/index.html index 6ac92f5..4910600 100644 --- a/examples/typescript/src/index.html +++ b/examples/typescript/src/index.html @@ -20,6 +20,9 @@

A Serial Flasher utility for Espressif chips

+

diff --git a/examples/typescript/src/index.ts b/examples/typescript/src/index.ts index 751e399..69e4ddc 100644 --- a/examples/typescript/src/index.ts +++ b/examples/typescript/src/index.ts @@ -38,6 +38,16 @@ eraseButton.style.display = "none"; consoleStopButton.style.display = "none"; filesDiv.style.display = "none"; +/** + * The built in Event object. + * @external Event + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Event} + */ + +/** + * File reader handler to read given local file. + * @param {Event} evt File Select event + */ function handleFileSelect(evt) { const file = evt.target.files[0]; @@ -78,7 +88,7 @@ connectButton.onclick = async () => { } as LoaderOptions; esploader = new ESPLoader(flashOptions); - chip = await esploader.main_fn(); + chip = await esploader.main(); // Temporarily broken // await esploader.flash_id(); @@ -113,7 +123,7 @@ resetButton.onclick = async () => { eraseButton.onclick = async () => { eraseButton.disabled = true; try { - await esploader.erase_flash(); + await esploader.eraseFlash(); } catch (e) { console.error(e); term.writeln(`Error: ${e.message}`); @@ -166,12 +176,24 @@ addFileButton.onclick = () => { } }; -function removeRow(row) { +/** + * The built in HTMLTableRowElement object. + * @external HTMLTableRowElement + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement} + */ + +/** + * Remove file row from HTML Table + * @param {HTMLTableRowElement} row Table row element to remove + */ +function removeRow(row: HTMLTableRowElement) { const rowIndex = Array.from(table.rows).indexOf(row); table.deleteRow(rowIndex); } -// to be called on disconnect - remove any stale references of older connections if any +/** + * Clean devices variables on chip disconnect. Remove stale references if any. + */ function cleanUp() { device = null; transport = null; @@ -228,7 +250,11 @@ consoleStopButton.onclick = async () => { programDiv.style.display = "initial"; }; -function validate_program_inputs() { +/** + * Validate the provided files images and offset to see if they're valid. + * @returns {string} Program input validation result + */ +function validateProgramInputs() { const offsetArr = []; const rowCount = table.rows.length; let row; @@ -258,7 +284,7 @@ function validate_program_inputs() { programButton.onclick = async () => { const alertMsg = document.getElementById("alertmsg"); - const err = validate_program_inputs(); + const err = validateProgramInputs(); if (err != "success") { alertMsg.innerHTML = "" + err + ""; @@ -301,7 +327,7 @@ programButton.onclick = async () => { }, calculateMD5Hash: (image) => CryptoJS.MD5(CryptoJS.enc.Latin1.parse(image)), } as FlashOptions; - await esploader.write_flash(flashOptions); + await esploader.writeFlash(flashOptions); } catch (e) { console.error(e); term.writeln(`Error: ${e.message}`); diff --git a/package-lock.json b/package-lock.json index a2a8ca4..bafc88e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/parser": "^5.43.0", "babel-loader": "^9.1.0", + "buffer": "^5.7.1", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-jsdoc": "^46.4.5", @@ -1464,6 +1465,26 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1515,6 +1536,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2392,6 +2437,26 @@ "node": ">=8" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -4845,6 +4910,12 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4877,6 +4948,16 @@ "update-browserslist-db": "^1.0.9" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -5526,6 +5607,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", diff --git a/package.json b/package.json index 60a9ba9..db4a841 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "build": "npm run clean && tsc && rollup --config", "clean": "rimraf docs lib bundle.js", "format": "prettier --write \"src/**/*.ts\"", - "genDocs": "npm run clean && typedoc", + "genDocs": "rimraf docs && typedoc", "lint": "eslint . --ext .ts", "lintAndFix": "eslint . --ext .ts --fix", "prepare": "npm run build", @@ -42,6 +42,7 @@ "@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/parser": "^5.43.0", "babel-loader": "^9.1.0", + "buffer": "^5.7.1", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-jsdoc": "^46.4.5", diff --git a/src/esploader.ts b/src/esploader.ts index 054ae0b..c3873ee 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -248,6 +248,9 @@ export class ESPLoader { * 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. + * ```ts + * const myLoader = new ESPLoader({transport: Transport, baudrate: number, terminal?: IEspLoaderTerminal }); + * ``` */ constructor(options: LoaderOptions) { this.IS_STUB = false; @@ -607,9 +610,9 @@ export class ESPLoader { /** * Perform a connection to chip. - * @param mode - Reset mode to use. Example: 'default_reset' | 'no_reset' - * @param attempts - Number of connection attempts - * @param detecting - Detect the connected 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 */ async connect(mode = "default_reset", attempts = 7, detecting = false) { let i; @@ -645,7 +648,7 @@ export class ESPLoader { /** * Connect and detect the existing chip. - * @param mode Reset mode to use for connection. + * @param {string} mode Reset mode to use for connection. */ async detectChip(mode = "default_reset") { await this.connect(mode); @@ -701,7 +704,7 @@ export class ESPLoader { /** * Get the checksum for given unsigned 8-bit array * @param {Uint8Array} data Unsigned 8-bit integer array - * @returns - Array checksum + * @returns {number} - Array checksum */ checksum = function (data: Uint8Array) { let i; @@ -715,8 +718,8 @@ export class ESPLoader { /** * Send a block of image to RAM - * @param buffer Unsigned 8-bit array - * @param seq Sequence number + * @param {Uint8Array} buffer Unsigned 8-bit array + * @param {number} seq Sequence number */ async memBlock(buffer: Uint8Array, seq: number) { let pkt = this._appendArray(this._intToByteArray(buffer.length), this._intToByteArray(seq)); @@ -802,7 +805,7 @@ export class ESPLoader { * Start downloading compressed data to Flash (performs an erase) * @param {number} size Write size * @param {number} compsize Compressed size - * @param {number} offset + * @param {number} offset Offset for write * @returns {number} Returns number of blocks (size self.FLASH_WRITE_SIZE) to write. */ async flashDeflBegin(size: number, compsize: number, offset: number) { @@ -915,12 +918,12 @@ export class ESPLoader { * * After writing command byte, writes 'data' to MOSI and then * reads back 'read_bits' of reply on MISO. Result is a number. - * @param {number} spiflash_command - * @param {Uint8Array} data - * @param {number} read_bits + * @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 */ - async runSpiflashCommand(spiflash_command: number, data: Uint8Array, read_bits: number) { + async runSpiflashCommand(spiflashCommand: number, data: Uint8Array, readBits: number) { // SPI_USR register flags const SPI_USR_COMMAND = 1 << 31; const SPI_USR_MISO = 1 << 28; @@ -960,7 +963,7 @@ export class ESPLoader { const SPI_CMD_USR = 1 << 18; const SPI_USR2_COMMAND_LEN_SHIFT = 28; - if (read_bits > 32) { + if (readBits > 32) { throw new ESPError("Reading more than 32 bits back from a SPI flash operation is unsupported"); } if (data.length > 64) { @@ -972,15 +975,15 @@ export class ESPLoader { const old_spi_usr2 = await this.readReg(SPI_USR2_REG); let flags = SPI_USR_COMMAND; let i; - if (read_bits > 0) { + if (readBits > 0) { flags |= SPI_USR_MISO; } if (data_bits > 0) { flags |= SPI_USR_MOSI; } - await set_data_lengths(data_bits, read_bits); + await set_data_lengths(data_bits, readBits); await this.write_reg(SPI_USR_REG, flags); - let val = (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflash_command; + let val = (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand; await this.write_reg(SPI_USR2_REG, val); if (data_bits == 0) { await this.write_reg(SPI_W0_REG, 0); @@ -1014,7 +1017,7 @@ export class ESPLoader { /** * Read flash id by executing the SPIFLASH_RDID flash command. - * @returns Register SPI_W0_REG value + * @returns {Promise} Register SPI_W0_REG value */ async readFlashId() { const SPIFLASH_RDID = 0x9f; @@ -1054,8 +1057,8 @@ export class ESPLoader { /** * Calculate the MD5 Checksum command - * @param addr Address number - * @param size Package size + * @param {number} addr Address number + * @param {number} size Package size * @returns {string} MD5 Checksum string */ async flashMd5sum(addr: number, size: number): Promise { @@ -1217,22 +1220,22 @@ export class ESPLoader { /** * Get flash size bytes from flash size string. - * @param flash_size Flash Size string + * @param {string} flashSize Flash Size string * @returns {number} Flash size bytes */ - flashSizeBytes = function (flash_size: string) { + flashSizeBytes = function (flashSize: string) { let flash_size_b = -1; - if (flash_size.indexOf("KB") !== -1) { - flash_size_b = parseInt(flash_size.slice(0, flash_size.indexOf("KB"))) * 1024; - } else if (flash_size.indexOf("MB") !== -1) { - flash_size_b = parseInt(flash_size.slice(0, flash_size.indexOf("MB"))) * 1024 * 1024; + if (flashSize.indexOf("KB") !== -1) { + flash_size_b = parseInt(flashSize.slice(0, flashSize.indexOf("KB"))) * 1024; + } else if (flashSize.indexOf("MB") !== -1) { + flash_size_b = parseInt(flashSize.slice(0, flashSize.indexOf("MB"))) * 1024 * 1024; } return flash_size_b; }; /** * Parse a given flash size string to a number - * @param flsz Flash size to request + * @param {string} flsz Flash size to request * @returns {number} Flash size number */ parseFlashSizeArg(flsz: string) { diff --git a/src/reset.ts b/src/reset.ts index e0bd3b3..267e666 100644 --- a/src/reset.ts +++ b/src/reset.ts @@ -2,7 +2,11 @@ import { Transport } from "./webserial"; const DEFAULT_RESET_DELAY = 50; -/** Sleep function helper */ +/** + * Sleep for ms milliseconds + * @param {number} ms Milliseconds to wait + * @returns {Promise} + */ function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } @@ -110,8 +114,7 @@ type CmdsArgsTypes = { * R: setRTS - 1=True / 0=False * * W: Wait (time delay) - positive integer number (miliseconds) - * - * @param seqStr Sequence string to validate + * @param {string} seqStr Sequence string to validate * @returns {boolean} Is the sequence string valid ? */ export function validateCustomResetStringSequence(seqStr: string): boolean { @@ -157,7 +160,6 @@ export function validateCustomResetStringSequence(seqStr: string): boolean { * 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 */ diff --git a/src/webserial.ts b/src/webserial.ts index a97a3e9..c8c564e 100644 --- a/src/webserial.ts +++ b/src/webserial.ts @@ -1,3 +1,5 @@ +/* global SerialPort */ + export interface SerialOptions { /* Note: According to the documentation of the Web Serial API, 'baudRate' is a @@ -16,8 +18,7 @@ export interface SerialOptions { /** * Wrapper class around Webserial API to communicate with the serial device. - * - * @param {SerialPort} device - Requested device prompted by the browser. + * @param {typeof import("w3c-web-serial").SerialPort} device - Requested device prompted by the browser. * * const port = await navigator.serial.requestPort(); */ @@ -85,7 +86,7 @@ class Transport { /** * Write binary data to device using the WebSerial device writable stream. - * @param data 8 bit unsigned data array to write to device. + * @param {Uint8Array} data 8 bit unsigned data array to write to device. */ async write(data: Uint8Array) { const out_data = this.slipWriter(data); @@ -114,7 +115,7 @@ class Transport { * 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} + * @returns {Uint8Array} Formatted packet using SLIP escape sequences. */ slipReader(data: Uint8Array) { let i = 0; @@ -212,7 +213,7 @@ class Transport { /** * Read from serial device without slip formatting. - * @param timeout Read timeout in milliseconds (ms) + * @param {number} timeout Read timeout in milliseconds (ms) * @returns {Uint8Array} 8 bit unsigned data array read from device. */ async rawRead(timeout = 0) { From acdfb7db861aac565aed98d7320936d4350293f1 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Mon, 9 Oct 2023 17:51:17 +0200 Subject: [PATCH 5/9] update docs dir output path --- .github/workflows/pages.yml | 1 - examples/typescript/README.md | 15 ++++++++++++-- examples/typescript/package.json | 7 ++++--- package-lock.json | 34 ++++++++++++++++---------------- package.json | 6 +++--- 5 files changed, 37 insertions(+), 26 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index d5badff..37c2c0d 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -40,7 +40,6 @@ jobs: cd examples/typescript npm install npm run build - cp -r ../../docs dist - name: Setup Pages uses: actions/configure-pages@v2 - name: Upload artifact diff --git a/examples/typescript/README.md b/examples/typescript/README.md index 05a6ecb..2dea2d9 100644 --- a/examples/typescript/README.md +++ b/examples/typescript/README.md @@ -1,6 +1,8 @@ # Using Esptool-JS in a Typescript environment -This example has example code in `src/index.ts` which is called in the `index.html`. We are using Parcel to do bundle mechanism for the resulting JavaScript for simplicity here. +This example has example code in `src/index.ts` which is called in the `index.html`. We are using Parcel to bundle resulting files for simplicity here. + +**NOTE:** This example is linked to the documentation generated from the source code. You could remove such dependency if necessary by remove `./docs/index.html` from `src/index.html` if you need so. NPM commands used below will generate documentation as well. ## Testing it locally @@ -9,4 +11,13 @@ npm install npm run dev ``` -Then open http://localhost:1234 in Chrome or Edge. The `npm run dev` step will call Parcel which start a local http server serving `index.html` with compiled `index.ts`. \ No newline at end of file +Then open http://localhost:1234 in Chrome or Edge. The `npm run dev` step will call Parcel which start a local http server serving `index.html` with compiled `index.ts`. + +## Generate build to publish + +``` +npm install +npm run build +``` + +Copy the content of `dist` to your static pages service like Github pages. \ No newline at end of file diff --git a/examples/typescript/package.json b/examples/typescript/package.json index 190bf6f..f59a220 100644 --- a/examples/typescript/package.json +++ b/examples/typescript/package.json @@ -4,9 +4,10 @@ "description": "This an example of using esptool-js with parcel and typescript", "source": "src/index.html", "scripts": { - "dev": "parcel src/index.html", - "build": "npm run clean && parcel build src/index.html --no-optimize --public-url ./", - "clean": "rimraf dist .parcel-cache", + "dev": "npm run genDocs && parcel src/index.html", + "genDocs": "cd ../.. && npm run build && npm run genDocs", + "build": "npm run clean && npm run genDocs && parcel build src/index.html --no-optimize --public-url ./", + "clean": "rimraf src/docs dist .parcel-cache", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", diff --git a/package-lock.json b/package-lock.json index bafc88e..7ca8cab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "prettier": "^2.7.1", "rimraf": "^3.0.2", "rollup": "^3.3.0", - "typedoc": "^0.24.8", + "typedoc": "^0.25.2", "typescript": "^4.8.4" } }, @@ -3354,9 +3354,9 @@ } }, "node_modules/shiki": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.3.tgz", - "integrity": "sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==", + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz", + "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==", "dev": true, "dependencies": { "ansi-sequence-parser": "^1.1.0", @@ -3610,24 +3610,24 @@ } }, "node_modules/typedoc": { - "version": "0.24.8", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", - "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.2.tgz", + "integrity": "sha512-286F7BeATBiWe/qC4PCOCKlSTwfnsLbC/4cZ68oGBbvAqb9vV33quEOXx7q176OXotD+JdEerdQ1OZGJ818lnA==", "dev": true, "dependencies": { "lunr": "^2.3.9", "marked": "^4.3.0", - "minimatch": "^9.0.0", + "minimatch": "^9.0.3", "shiki": "^0.14.1" }, "bin": { "typedoc": "bin/typedoc" }, "engines": { - "node": ">= 14.14" + "node": ">= 16" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x" } }, "node_modules/typedoc/node_modules/brace-expansion": { @@ -6248,9 +6248,9 @@ "dev": true }, "shiki": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.3.tgz", - "integrity": "sha512-U3S/a+b0KS+UkTyMjoNojvTgrBHjgp7L6ovhFVZsXmBGnVdQ4K4U9oK0z63w538S91ATngv1vXigHCSWOwnr+g==", + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz", + "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==", "dev": true, "requires": { "ansi-sequence-parser": "^1.1.0", @@ -6431,14 +6431,14 @@ "dev": true }, "typedoc": { - "version": "0.24.8", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", - "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.2.tgz", + "integrity": "sha512-286F7BeATBiWe/qC4PCOCKlSTwfnsLbC/4cZ68oGBbvAqb9vV33quEOXx7q176OXotD+JdEerdQ1OZGJ818lnA==", "dev": true, "requires": { "lunr": "^2.3.9", "marked": "^4.3.0", - "minimatch": "^9.0.0", + "minimatch": "^9.0.3", "shiki": "^0.14.1" }, "dependencies": { diff --git a/package.json b/package.json index db4a841..d785b06 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,9 @@ ], "scripts": { "build": "npm run clean && tsc && rollup --config", - "clean": "rimraf docs lib bundle.js", + "clean": "rimraf lib bundle.js .parcel-cache", "format": "prettier --write \"src/**/*.ts\"", - "genDocs": "rimraf docs && typedoc", + "genDocs": "rimraf examples/typescript/src/docs && typedoc --out examples/typescript/src/docs", "lint": "eslint . --ext .ts", "lintAndFix": "eslint . --ext .ts --fix", "prepare": "npm run build", @@ -50,7 +50,7 @@ "prettier": "^2.7.1", "rimraf": "^3.0.2", "rollup": "^3.3.0", - "typedoc": "^0.24.8", + "typedoc": "^0.25.2", "typescript": "^4.8.4" } } From e893504cb27f5c5666f2f9d3c39ac4e9b277040e Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Tue, 10 Oct 2023 12:23:06 +0200 Subject: [PATCH 6/9] fix doc generate --- examples/typescript/.parcelrc | 7 +++++++ examples/typescript/README.md | 2 +- examples/typescript/package.json | 8 ++++++-- package.json | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 examples/typescript/.parcelrc diff --git a/examples/typescript/.parcelrc b/examples/typescript/.parcelrc new file mode 100644 index 0000000..853a724 --- /dev/null +++ b/examples/typescript/.parcelrc @@ -0,0 +1,7 @@ +{ + "extends": "@parcel/config-default", + "resolvers": [ + "parcel-resolver-ignore", + "..." + ] + } \ No newline at end of file diff --git a/examples/typescript/README.md b/examples/typescript/README.md index 2dea2d9..4627d85 100644 --- a/examples/typescript/README.md +++ b/examples/typescript/README.md @@ -2,7 +2,7 @@ This example has example code in `src/index.ts` which is called in the `index.html`. We are using Parcel to bundle resulting files for simplicity here. -**NOTE:** This example is linked to the documentation generated from the source code. You could remove such dependency if necessary by remove `./docs/index.html` from `src/index.html` if you need so. NPM commands used below will generate documentation as well. +**NOTE:** This example is linked to the documentation generated from the source code. You could remove such dependency if necessary by remove `./docs/index.html` from `src/index.html` if you need so. NPM commands used below will generate documentation as well. ## Testing it locally diff --git a/examples/typescript/package.json b/examples/typescript/package.json index f59a220..1b17df5 100644 --- a/examples/typescript/package.json +++ b/examples/typescript/package.json @@ -4,16 +4,20 @@ "description": "This an example of using esptool-js with parcel and typescript", "source": "src/index.html", "scripts": { + "genDocs": "cd ../.. && npm run genDocs && mkdir -p examples/typescript/dist && cp -r docs examples/typescript/dist && cd examples/typescript", "dev": "npm run genDocs && parcel src/index.html", - "genDocs": "cd ../.. && npm run build && npm run genDocs", "build": "npm run clean && npm run genDocs && parcel build src/index.html --no-optimize --public-url ./", - "clean": "rimraf src/docs dist .parcel-cache", + "clean": "rimraf dist .parcel-cache", "test": "echo \"Error: no test specified\" && exit 1" }, + "parcelIgnore": [ + "./docs/.+" + ], "author": "", "license": "ISC", "devDependencies": { "parcel": "^2.8.3", + "parcel-resolver-ignore": "^2.1.5", "rimraf": "^4.1.2", "typescript": "^4.9.4" } diff --git a/package.json b/package.json index d785b06..7c6279a 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "build": "npm run clean && tsc && rollup --config", "clean": "rimraf lib bundle.js .parcel-cache", "format": "prettier --write \"src/**/*.ts\"", - "genDocs": "rimraf examples/typescript/src/docs && typedoc --out examples/typescript/src/docs", + "genDocs": "rimraf docs && typedoc", "lint": "eslint . --ext .ts", "lintAndFix": "eslint . --ext .ts --fix", "prepare": "npm run build", From 252a37bcc9d71769ec803ba165febe4118a96e96 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Thu, 2 Nov 2023 16:10:14 +0800 Subject: [PATCH 7/9] from snake case to camel case --- examples/typescript/src/index.ts | 2 +- src/esploader.ts | 270 +++++++++++++++---------------- src/targets/esp32.ts | 102 ++++++------ src/targets/esp32c3.ts | 20 +-- src/targets/esp32c6.ts | 24 +-- src/targets/esp32h2.ts | 6 +- src/targets/esp32s2.ts | 34 ++-- src/targets/esp32s3.ts | 6 +- src/targets/esp8266.ts | 24 +-- src/webserial.ts | 87 +++++----- 10 files changed, 288 insertions(+), 287 deletions(-) diff --git a/examples/typescript/src/index.ts b/examples/typescript/src/index.ts index 69e4ddc..b5979bb 100644 --- a/examples/typescript/src/index.ts +++ b/examples/typescript/src/index.ts @@ -91,7 +91,7 @@ connectButton.onclick = async () => { chip = await esploader.main(); // Temporarily broken - // await esploader.flash_id(); + // await esploader.flashId(); } catch (e) { console.error(e); term.writeln(`Error: ${e.message}`); diff --git a/src/esploader.ts b/src/esploader.ts index c3873ee..f1b58f4 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -4,6 +4,8 @@ import { Transport, SerialOptions } from "./webserial"; import { ROM } from "./targets/rom"; import { customReset, usbJTAGSerialReset } from "./reset"; +/* global SerialPort */ + /** * Options for flashing a device with firmware. * @interface FlashOptions @@ -354,7 +356,7 @@ export class ESPLoader { * @param {number} j - Number to convert. * @returns {number} Return a short integer number. */ - _bytearray_to_short(i: number, j: number) { + _byteArrayToShort(i: number, j: number) { return i | (j >> 8); } @@ -366,7 +368,7 @@ export class ESPLoader { * @param {number} l - Number to convert. * @returns {number} Return a integer number. */ - _bytearray_to_int(i: number, j: number, k: number, l: number) { + _byteArrayToInt(i: number, j: number, k: number, l: number) { return i | (j << 8) | (k << 16) | (l << 24); } @@ -402,11 +404,11 @@ export class ESPLoader { * @returns {string} Return the equivalent string. */ ui8ToBstr(u8Array: Uint8Array) { - let b_str = ""; + let bStr = ""; for (let i = 0; i < u8Array.length; i++) { - b_str += String.fromCharCode(u8Array[i]); + bStr += String.fromCharCode(u8Array[i]); } - return b_str; + return bStr; } /** @@ -415,11 +417,11 @@ export class ESPLoader { * @returns {Uint8Array} Return a 8 bit unsigned integer array. */ bstrToUi8(bStr: string) { - const u8_array = new Uint8Array(bStr.length); + const u8Array = new Uint8Array(bStr.length); for (let i = 0; i < bStr.length; i++) { - u8_array[i] = bStr.charCodeAt(i); + u8Array[i] = bStr.charCodeAt(i); } - return u8_array; + return u8Array; } /** @@ -433,16 +435,16 @@ export class ESPLoader { } } - async read_packet(op: number | null = null, timeout = 3000): Promise<[number, Uint8Array]> { + async readPacket(op: number | null = null, timeout = 3000): Promise<[number, Uint8Array]> { // Check up-to next 100 packets for valid response packet for (let i = 0; i < 100; i++) { const p = await this.transport.read(timeout); const resp = p[0]; - const op_ret = p[1]; - const val = this._bytearray_to_int(p[4], p[5], p[6], p[7]); + const opRet = p[1]; + const val = this._byteArrayToInt(p[4], p[5], p[6], p[7]); const data = p.slice(8); if (resp == 1) { - if (op == null || op_ret == op) { + if (op == null || opRet == op) { return [val, data]; } else if (data[0] != 0 && data[1] == this.ROM_INVALID_RECV_MSG) { await this.flushInput(); @@ -491,7 +493,7 @@ export class ESPLoader { return [0, new Uint8Array(0)]; } - return this.read_packet(op, timeout); + return this.readPacket(op, timeout); } /** @@ -511,19 +513,19 @@ export class ESPLoader { * @param {number} addr - Register address number * @param {number} value - Number value to write in register * @param {number} mask - Hex number for mask - * @param {number} delay_us Delay number - * @param {number} delay_after_us Delay after previous delay + * @param {number} delayUs Delay number + * @param {number} delayAfterUs Delay after previous delay */ - async write_reg(addr: number, value: number, mask = 0xffffffff, delay_us = 0, delay_after_us = 0) { + async writeReg(addr: number, value: number, mask = 0xffffffff, delayUs = 0, delayAfterUs = 0) { let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(value)); pkt = this._appendArray(pkt, this._intToByteArray(mask)); - pkt = this._appendArray(pkt, this._intToByteArray(delay_us)); + pkt = this._appendArray(pkt, this._intToByteArray(delayUs)); - if (delay_after_us > 0) { + if (delayAfterUs > 0) { pkt = this._appendArray(pkt, this._intToByteArray(this.chip.UART_DATE_REG_ADDR)); pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, this._intToByteArray(0)); - pkt = this._appendArray(pkt, this._intToByteArray(delay_after_us)); + pkt = this._appendArray(pkt, this._intToByteArray(delayAfterUs)); } await this.checkCommand("write target memory", this.ESP_WRITE_REG, pkt); @@ -557,18 +559,18 @@ export class ESPLoader { /** * 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} esp32r0_delay - Enable delay for ESP32 R0 + * @param {boolean} esp32r0Delay - Enable delay for ESP32 R0 * @returns {string} - Returns 'success' or 'error' message. */ - async _connectAttempt(mode = "default_reset", esp32r0_delay = false) { - this.debug("_connect_attempt " + mode + " " + esp32r0_delay); + async _connectAttempt(mode = "default_reset", esp32r0Delay = false) { + this.debug("_connect_attempt " + mode + " " + esp32r0Delay); if (mode !== "no_reset") { if (this.transport.getPid() === this.USB_JTAG_SERIAL_PID) { // Custom reset sequence, which is required when the device // is connecting via its USB-JTAG-Serial peripheral await usbJTAGSerialReset(this.transport); } else { - const strSequence = esp32r0_delay ? "D0|R1|W100|W2000|D1|R0|W50|D0" : "D0|R1|W100|D1|R0|W50|D0"; + const strSequence = esp32r0Delay ? "D0|R1|W100|W2000|D1|R0|W50|D0" : "D0|R1|W100|D1|R0|W50|D0"; await customReset(this.transport, strSequence); } } @@ -587,7 +589,7 @@ export class ESPLoader { } await this._sleep(50); } - this.transport.slip_reader_enabled = true; + this.transport.slipReaderEnabled = true; i = 7; while (i--) { try { @@ -596,7 +598,7 @@ export class ESPLoader { return "success"; } catch (error) { if (error instanceof Error) { - if (esp32r0_delay) { + if (esp32r0Delay) { this.info("_", false); } else { this.info(".", false); @@ -635,11 +637,11 @@ export class ESPLoader { this.info("\n\r", false); if (!detecting) { - const chip_magic_value = (await this.readReg(0x40001000)) >>> 0; - this.debug("Chip Magic " + chip_magic_value.toString(16)); - const chip = await magic2Chip(chip_magic_value); + const chipMagicValue = (await this.readReg(0x40001000)) >>> 0; + this.debug("Chip Magic " + chipMagicValue.toString(16)); + const chip = await magic2Chip(chipMagicValue); if (this.chip === null) { - throw new ESPError(`Unexpected CHIP magic value ${chip_magic_value}. Failed to autodetect chip type.`); + throw new ESPError(`Unexpected CHIP magic value ${chipMagicValue}. Failed to autodetect chip type.`); } else { this.chip = chip as ROM; } @@ -662,7 +664,7 @@ export class ESPLoader { /** * Execute the command and check the command response. - * @param {string} op_description Command operation description. + * @param {string} opDescription Command operation description. * @param {number} op Command operation number * @param {Uint8Array} data Command value * @param {number} chk Checksum to use @@ -670,13 +672,13 @@ export class ESPLoader { * @returns {number} Command result */ async checkCommand( - op_description = "", + opDescription = "", op: number | null = null, data: Uint8Array = new Uint8Array(0), chk = 0, timeout = 3000, ) { - this.debug("check_command " + op_description); + this.debug("check_command " + opDescription); const resp = await this.command(op, data, chk, undefined, timeout); if (resp[1].length > 4) { return resp[1]; @@ -735,28 +737,28 @@ export class ESPLoader { * @param {number} entrypoint - Entrypoint number */ async memFinish(entrypoint: number) { - const is_entry = entrypoint === 0 ? 1 : 0; - const pkt = this._appendArray(this._intToByteArray(is_entry), this._intToByteArray(entrypoint)); + const isEntry = entrypoint === 0 ? 1 : 0; + const pkt = this._appendArray(this._intToByteArray(isEntry), this._intToByteArray(entrypoint)); await this.checkCommand("leave RAM download mode", this.ESP_MEM_END, pkt, undefined, 50); // XXX: handle non-stub with diff timeout } /** * Configure SPI flash pins - * @param {number} hspi_arg - Argument for SPI attachment + * @param {number} hspiArg - Argument for SPI attachment */ - async flashSpiAttach(hspi_arg: number) { - const pkt = this._intToByteArray(hspi_arg); + async flashSpiAttach(hspiArg: number) { + const pkt = this._intToByteArray(hspiArg); await this.checkCommand("configure SPI flash pins", this.ESP_SPI_ATTACH, pkt); } /** * Scale timeouts which are size-specific. - * @param {number} seconds_per_mb Seconds per megabytes as number - * @param {number} size_bytes Size bytes number + * @param {number} secondsPerMb Seconds per megabytes as number + * @param {number} sizeBytes Size bytes number * @returns {number} - Scaled timeout for specified size. */ - timeoutPerMb = function (seconds_per_mb: number, size_bytes: number) { - const result = seconds_per_mb * (size_bytes / 1000000); + timeoutPerMb = function (secondsPerMb: number, sizeBytes: number) { + const result = secondsPerMb * (sizeBytes / 1000000); if (result < 3000) { return 3000; } else { @@ -771,8 +773,8 @@ export class ESPLoader { * @returns {number} Number of blocks (of size self.FLASH_WRITE_SIZE) to write. */ async flashBegin(size: number, offset: number) { - const num_blocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); - const erase_size = this.chip.getEraseSize(offset, size); + const numBlocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); + const eraseSize = this.chip.getEraseSize(offset, size); const d = new Date(); const t1 = d.getTime(); @@ -782,10 +784,8 @@ export class ESPLoader { timeout = this.timeoutPerMb(this.ERASE_REGION_TIMEOUT_PER_MB, size); } - this.debug( - "flash begin " + erase_size + " " + num_blocks + " " + this.FLASH_WRITE_SIZE + " " + offset + " " + size, - ); - let pkt = this._appendArray(this._intToByteArray(erase_size), this._intToByteArray(num_blocks)); + this.debug("flash begin " + eraseSize + " " + numBlocks + " " + this.FLASH_WRITE_SIZE + " " + offset + " " + size); + let pkt = this._appendArray(this._intToByteArray(eraseSize), this._intToByteArray(numBlocks)); pkt = this._appendArray(pkt, this._intToByteArray(this.FLASH_WRITE_SIZE)); pkt = this._appendArray(pkt, this._intToByteArray(offset)); if (this.IS_STUB == false) { @@ -798,7 +798,7 @@ export class ESPLoader { if (size != 0 && this.IS_STUB == false) { this.info("Took " + (t2 - t1) / 1000 + "." + ((t2 - t1) % 1000) + "s to erase flash block"); } - return num_blocks; + return numBlocks; } /** @@ -809,23 +809,23 @@ export class ESPLoader { * @returns {number} Returns number of blocks (size self.FLASH_WRITE_SIZE) to write. */ async flashDeflBegin(size: number, compsize: number, offset: number) { - const num_blocks = Math.floor((compsize + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); - const erase_blocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); + const numBlocks = Math.floor((compsize + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); + const eraseBlocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); const d = new Date(); const t1 = d.getTime(); - let write_size, timeout; + let writeSize, timeout; if (this.IS_STUB) { - write_size = size; + writeSize = size; timeout = 3000; } else { - write_size = erase_blocks * this.FLASH_WRITE_SIZE; - timeout = this.timeoutPerMb(this.ERASE_REGION_TIMEOUT_PER_MB, write_size); + writeSize = eraseBlocks * this.FLASH_WRITE_SIZE; + timeout = this.timeoutPerMb(this.ERASE_REGION_TIMEOUT_PER_MB, writeSize); } this.info("Compressed " + size + " bytes to " + compsize + "..."); - let pkt = this._appendArray(this._intToByteArray(write_size), this._intToByteArray(num_blocks)); + let pkt = this._appendArray(this._intToByteArray(writeSize), this._intToByteArray(numBlocks)); pkt = this._appendArray(pkt, this._intToByteArray(this.FLASH_WRITE_SIZE)); pkt = this._appendArray(pkt, this._intToByteArray(offset)); @@ -842,7 +842,7 @@ export class ESPLoader { if (size != 0 && this.IS_STUB === false) { this.info("Took " + (t2 - t1) / 1000 + "." + ((t2 - t1) % 1000) + "s to erase flash block"); } - return num_blocks; + return numBlocks; } /** @@ -913,11 +913,11 @@ export class ESPLoader { * * This function uses the "USR_COMMAND" functionality in the ESP * SPI hardware, rather than the precanned commands supported by - * hardware. So the value of spiflash_command is an actual command + * 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 'read_bits' of reply on MISO. Result is a number. + * 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 @@ -937,27 +937,27 @@ export class ESPLoader { const SPI_USR2_REG = base + this.chip.SPI_USR2_OFFS; const SPI_W0_REG = base + this.chip.SPI_W0_OFFS; - let set_data_lengths; + let setDataLengths; if (this.chip.SPI_MOSI_DLEN_OFFS != null) { - set_data_lengths = async (mosi_bits: number, miso_bits: number) => { + setDataLengths = async (mosiBits: number, misoBits: number) => { const SPI_MOSI_DLEN_REG = base + this.chip.SPI_MOSI_DLEN_OFFS; const SPI_MISO_DLEN_REG = base + this.chip.SPI_MISO_DLEN_OFFS; - if (mosi_bits > 0) { - await this.write_reg(SPI_MOSI_DLEN_REG, mosi_bits - 1); + if (mosiBits > 0) { + await this.writeReg(SPI_MOSI_DLEN_REG, mosiBits - 1); } - if (miso_bits > 0) { - await this.write_reg(SPI_MISO_DLEN_REG, miso_bits - 1); + if (misoBits > 0) { + await this.writeReg(SPI_MISO_DLEN_REG, misoBits - 1); } }; } else { - set_data_lengths = async (mosi_bits: number, miso_bits: number) => { + setDataLengths = async (mosiBits: number, misoBits: number) => { const SPI_DATA_LEN_REG = SPI_USR1_REG; const SPI_MOSI_BITLEN_S = 17; const SPI_MISO_BITLEN_S = 8; - const mosi_mask = mosi_bits === 0 ? 0 : mosi_bits - 1; - const miso_mask = miso_bits === 0 ? 0 : miso_bits - 1; - const val = (miso_mask << SPI_MISO_BITLEN_S) | (mosi_mask << SPI_MOSI_BITLEN_S); - await this.write_reg(SPI_DATA_LEN_REG, val); + const mosiMask = mosiBits === 0 ? 0 : mosiBits - 1; + const misoMask = misoBits === 0 ? 0 : misoBits - 1; + const val = (misoMask << SPI_MISO_BITLEN_S) | (mosiMask << SPI_MOSI_BITLEN_S); + await this.writeReg(SPI_DATA_LEN_REG, val); }; } @@ -970,36 +970,36 @@ export class ESPLoader { throw new ESPError("Writing more than 64 bytes of data with one SPI command is unsupported"); } - const data_bits = data.length * 8; - const old_spi_usr = await this.readReg(SPI_USR_REG); - const old_spi_usr2 = await this.readReg(SPI_USR2_REG); + const dataBits = data.length * 8; + const oldSpiUsr = await this.readReg(SPI_USR_REG); + const oldSpiUsr2 = await this.readReg(SPI_USR2_REG); let flags = SPI_USR_COMMAND; let i; if (readBits > 0) { flags |= SPI_USR_MISO; } - if (data_bits > 0) { + if (dataBits > 0) { flags |= SPI_USR_MOSI; } - await set_data_lengths(data_bits, readBits); - await this.write_reg(SPI_USR_REG, flags); + await setDataLengths(dataBits, readBits); + await this.writeReg(SPI_USR_REG, flags); let val = (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand; - await this.write_reg(SPI_USR2_REG, val); - if (data_bits == 0) { - await this.write_reg(SPI_W0_REG, 0); + await this.writeReg(SPI_USR2_REG, val); + if (dataBits == 0) { + await this.writeReg(SPI_W0_REG, 0); } else { if (data.length % 4 != 0) { const padding = new Uint8Array(data.length % 4); data = this._appendArray(data, padding); } - let next_reg = SPI_W0_REG; + let nextReg = SPI_W0_REG; for (i = 0; i < data.length - 4; i += 4) { - val = this._bytearray_to_int(data[i], data[i + 1], data[i + 2], data[i + 3]); - await this.write_reg(next_reg, val); - next_reg += 4; + val = this._byteArrayToInt(data[i], data[i + 1], data[i + 2], data[i + 3]); + await this.writeReg(nextReg, val); + nextReg += 4; } } - await this.write_reg(SPI_CMD_REG, SPI_CMD_USR); + await this.writeReg(SPI_CMD_REG, SPI_CMD_USR); for (i = 0; i < 10; i++) { val = (await this.readReg(SPI_CMD_REG)) & SPI_CMD_USR; if (val == 0) { @@ -1010,8 +1010,8 @@ export class ESPLoader { throw new ESPError("SPI command did not complete in time"); } const stat = await this.readReg(SPI_W0_REG); - await this.write_reg(SPI_USR_REG, old_spi_usr); - await this.write_reg(SPI_USR2_REG, old_spi_usr2); + await this.writeReg(SPI_USR_REG, oldSpiUsr); + await this.writeReg(SPI_USR2_REG, oldSpiUsr2); return stat; } @@ -1075,7 +1075,7 @@ export class ESPLoader { return strmd5; } - async read_flash(addr: number, size: number, onPacketReceived: FlashReadCallback = null) { + async readFlash(addr: number, size: number, onPacketReceived: FlashReadCallback = null) { let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(size)); pkt = this._appendArray(pkt, this._intToByteArray(0x1000)); pkt = this._appendArray(pkt, this._intToByteArray(1024)); @@ -1131,17 +1131,17 @@ export class ESPLoader { await this.memBegin(text.length, blocks, this.ESP_RAM_BLOCK, this.chip.TEXT_START); for (i = 0; i < blocks; i++) { - const from_offs = i * this.ESP_RAM_BLOCK; - const to_offs = from_offs + this.ESP_RAM_BLOCK; - await this.memBlock(text.slice(from_offs, to_offs), i); + const fromOffs = i * this.ESP_RAM_BLOCK; + const toOffs = fromOffs + this.ESP_RAM_BLOCK; + await this.memBlock(text.slice(fromOffs, toOffs), i); } blocks = Math.floor((data.length + this.ESP_RAM_BLOCK - 1) / this.ESP_RAM_BLOCK); await this.memBegin(data.length, blocks, this.ESP_RAM_BLOCK, this.chip.DATA_START); for (i = 0; i < blocks; i++) { - const from_offs = i * this.ESP_RAM_BLOCK; - const to_offs = from_offs + this.ESP_RAM_BLOCK; - await this.memBlock(data.slice(from_offs, to_offs), i); + const fromOffs = i * this.ESP_RAM_BLOCK; + const toOffs = fromOffs + this.ESP_RAM_BLOCK; + await this.memBlock(data.slice(fromOffs, toOffs), i); } this.info("Running stub..."); @@ -1165,8 +1165,8 @@ export class ESPLoader { */ async changeBaud() { this.info("Changing baudrate to " + this.baudrate); - const second_arg = this.IS_STUB ? this.transport.baudrate : 0; - const pkt = this._appendArray(this._intToByteArray(this.baudrate), this._intToByteArray(second_arg)); + const secondArg = this.IS_STUB ? this.transport.baudrate : 0; + const pkt = this._appendArray(this._intToByteArray(this.baudrate), this._intToByteArray(secondArg)); const resp = await this.command(this.ESP_CHANGE_BAUDRATE, pkt); this.debug(resp[0].toString()); this.info("Changed"); @@ -1224,13 +1224,13 @@ export class ESPLoader { * @returns {number} Flash size bytes */ flashSizeBytes = function (flashSize: string) { - let flash_size_b = -1; + let flashSizeB = -1; if (flashSize.indexOf("KB") !== -1) { - flash_size_b = parseInt(flashSize.slice(0, flashSize.indexOf("KB"))) * 1024; + flashSizeB = parseInt(flashSize.slice(0, flashSize.indexOf("KB"))) * 1024; } else if (flashSize.indexOf("MB") !== -1) { - flash_size_b = parseInt(flashSize.slice(0, flashSize.indexOf("MB"))) * 1024 * 1024; + flashSizeB = parseInt(flashSize.slice(0, flashSize.indexOf("MB"))) * 1024 * 1024; } - return flash_size_b; + return flashSizeB; }; /** @@ -1270,8 +1270,8 @@ export class ESPLoader { } const magic = parseInt(image[0]); - let a_flash_mode = parseInt(image[2]); - const flash_size_freq = parseInt(image[3]); + let aFlashMode = parseInt(image[2]); + const flashSizeFreq = parseInt(image[3]); if (magic !== this.ESP_IMAGE_MAGIC) { this.info( "Warning: Image file at 0x" + @@ -1284,26 +1284,26 @@ export class ESPLoader { /* XXX: Yet to implement actual image verification */ if (flashMode !== "keep") { - const flash_modes: { [key: string]: number } = { qio: 0, qout: 1, dio: 2, dout: 3 }; - a_flash_mode = flash_modes[flashMode]; + const flashModes: { [key: string]: number } = { qio: 0, qout: 1, dio: 2, dout: 3 }; + aFlashMode = flashModes[flashMode]; } - let a_flash_freq = flash_size_freq & 0x0f; + let aFlashFreq = flashSizeFreq & 0x0f; if (flashFreq !== "keep") { - const flash_freqs: { [key: string]: number } = { "40m": 0, "26m": 1, "20m": 2, "80m": 0xf }; - a_flash_freq = flash_freqs[flashFreq]; + const flashFreqs: { [key: string]: number } = { "40m": 0, "26m": 1, "20m": 2, "80m": 0xf }; + aFlashFreq = flashFreqs[flashFreq]; } - let a_flash_size = flash_size_freq & 0xf0; + let aFlashSize = flashSizeFreq & 0xf0; if (flashSize !== "keep") { - a_flash_size = this.parseFlashSizeArg(flashSize); + aFlashSize = this.parseFlashSizeArg(flashSize); } - const flash_params = (a_flash_mode << 8) | (a_flash_freq + a_flash_size); - this.info("Flash params set to " + flash_params.toString(16)); - if (parseInt(image[2]) !== a_flash_mode << 8) { - image = image.substring(0, 2) + (a_flash_mode << 8).toString() + image.substring(2 + 1); + const flashParams = (aFlashMode << 8) | (aFlashFreq + aFlashSize); + this.info("Flash params set to " + flashParams.toString(16)); + if (parseInt(image[2]) !== aFlashMode << 8) { + image = image.substring(0, 2) + (aFlashMode << 8).toString() + image.substring(2 + 1); } - if (parseInt(image[3]) !== a_flash_freq + a_flash_size) { - image = image.substring(0, 3) + (a_flash_freq + a_flash_size).toString() + image.substring(3 + 1); + if (parseInt(image[3]) !== aFlashFreq + aFlashSize) { + image = image.substring(0, 3) + (aFlashFreq + aFlashSize).toString() + image.substring(3 + 1); } return image; } @@ -1315,9 +1315,9 @@ export class ESPLoader { async writeFlash(options: FlashOptions) { this.debug("EspLoader program"); if (options.flashSize !== "keep") { - const flash_end = this.flashSizeBytes(options.flashSize); + const flashEnd = this.flashSizeBytes(options.flashSize); for (let i = 0; i < options.fileArray.length; i++) { - if (options.fileArray[i].data.length + options.fileArray[i].address > flash_end) { + if (options.fileArray[i].data.length + options.fileArray[i].address > flashEnd) { throw new ESPError(`File ${i + 1} doesn't fit in the available flash`); } } @@ -1354,7 +1354,7 @@ export class ESPLoader { blocks = await this.flashBegin(uncsize, address); } let seq = 0; - let bytes_sent = 0; + let bytesSent = 0; const totalBytes = image.length; if (options.reportProgress) options.reportProgress(i, 0, totalBytes); @@ -1365,15 +1365,15 @@ export class ESPLoader { // Create a decompressor to keep track of the size of uncompressed data // to be written in each chunk. const inflate = new Inflate({ chunkSize: 1 }); - let total_len_uncompressed = 0; + let totalLenUncompressed = 0; inflate.onData = function (chunk: Data): void { - total_len_uncompressed += chunk.byteLength; + totalLenUncompressed += chunk.byteLength; }; while (image.length > 0) { this.debug("Write loop " + address + " " + seq + " " + blocks); this.info( "Writing at 0x" + - (address + total_len_uncompressed).toString(16) + + (address + totalLenUncompressed).toString(16) + "... (" + Math.floor((100 * (seq + 1)) / blocks) + "%)", @@ -1381,29 +1381,29 @@ export class ESPLoader { const block = this.bstrToUi8(image.slice(0, this.FLASH_WRITE_SIZE)); if (options.compress) { - const len_uncompressed_previous = total_len_uncompressed; + const lenUncompressedPrevious = totalLenUncompressed; inflate.push(block, false); - const block_uncompressed = total_len_uncompressed - len_uncompressed_previous; - let block_timeout = 3000; - if (this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed) > 3000) { - block_timeout = this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed); + const blockUncompressed = totalLenUncompressed - lenUncompressedPrevious; + let blockTimeout = 3000; + if (this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, blockUncompressed) > 3000) { + blockTimeout = this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, blockUncompressed); } if (this.IS_STUB === false) { // ROM code writes block to flash before ACKing - timeout = block_timeout; + timeout = blockTimeout; } await this.flashDeflBlock(block, seq, timeout); if (this.IS_STUB) { // Stub ACKs when block is received, then writes to flash while receiving the block after it - timeout = block_timeout; + timeout = blockTimeout; } } else { throw new ESPError("Yet to handle Non Compressed writes"); } - bytes_sent += block.length; + bytesSent += block.length; image = image.slice(this.FLASH_WRITE_SIZE, image.length); seq++; - if (options.reportProgress) options.reportProgress(i, bytes_sent, totalBytes); + if (options.reportProgress) options.reportProgress(i, bytesSent, totalBytes); } if (this.IS_STUB) { await this.readReg(this.CHIP_DETECT_MAGIC_REG_ADDR, timeout); @@ -1415,7 +1415,7 @@ export class ESPLoader { "Wrote " + uncsize + " bytes (" + - bytes_sent + + bytesSent + " compressed) at 0x" + address.toString(16) + " in " + @@ -1453,16 +1453,16 @@ export class ESPLoader { this.debug("flash_id"); const flashid = await this.readFlashId(); this.info("Manufacturer: " + (flashid & 0xff).toString(16)); - const flid_lowbyte = (flashid >> 16) & 0xff; - this.info("Device: " + ((flashid >> 8) & 0xff).toString(16) + flid_lowbyte.toString(16)); - this.info("Detected flash size: " + this.DETECTED_FLASH_SIZES[flid_lowbyte]); + const flidLowbyte = (flashid >> 16) & 0xff; + this.info("Device: " + ((flashid >> 8) & 0xff).toString(16) + flidLowbyte.toString(16)); + this.info("Detected flash size: " + this.DETECTED_FLASH_SIZES[flidLowbyte]); } - async get_flash_size() { + async getFlashSize() { this.debug("flash_id"); const flashid = await this.readFlashId(); - const flid_lowbyte = (flashid >> 16) & 0xff; - return this.DETECTED_FLASH_SIZES_NUM[flid_lowbyte]; + const flidLowbyte = (flashid >> 16) & 0xff; + return this.DETECTED_FLASH_SIZES_NUM[flidLowbyte]; } /** diff --git a/src/targets/esp32.ts b/src/targets/esp32.ts index c9da96e..a1b7593 100644 --- a/src/targets/esp32.ts +++ b/src/targets/esp32.ts @@ -45,22 +45,22 @@ export class ESP32ROM extends ROM { public async getPkgVersion(loader: ESPLoader): Promise { const word3 = await this.readEfuse(loader, 3); - let pkg_version = (word3 >> 9) & 0x07; - pkg_version += ((word3 >> 2) & 0x1) << 3; - return pkg_version; + let pkgVersion = (word3 >> 9) & 0x07; + pkgVersion += ((word3 >> 2) & 0x1) << 3; + return pkgVersion; } public async getChipRevision(loader: ESPLoader): Promise { const word3 = await this.readEfuse(loader, 3); const word5 = await this.readEfuse(loader, 5); - const apb_ctl_date = await loader.readReg(this.DR_REG_SYSCON_BASE + 0x7c); - - const rev_bit0 = (word3 >> 15) & 0x1; - const rev_bit1 = (word5 >> 20) & 0x1; - const rev_bit2 = (apb_ctl_date >> 31) & 0x1; - if (rev_bit0 != 0) { - if (rev_bit1 != 0) { - if (rev_bit2 != 0) { + 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; @@ -73,7 +73,7 @@ export class ESP32ROM extends ROM { } public async getChipDescription(loader: ESPLoader) { - const chip_desc = [ + const chipDesc = [ "ESP32-D0WDQ6", "ESP32-D0WD", "ESP32-D2WD", @@ -82,98 +82,98 @@ export class ESP32ROM extends ROM { "ESP32-PICO-D4", "ESP32-PICO-V3-02", ]; - let chip_name = ""; - const pkg_version = await this.getPkgVersion(loader); - const chip_revision = await this.getChipRevision(loader); - const rev3 = chip_revision == 3; + 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) { - chip_desc[0] = "ESP32-S0WDQ6"; - chip_desc[1] = "ESP32-S0WD"; + chipDesc[0] = "ESP32-S0WDQ6"; + chipDesc[1] = "ESP32-S0WD"; } if (rev3) { - chip_desc[5] = "ESP32-PICO-V3"; + chipDesc[5] = "ESP32-PICO-V3"; } - if (pkg_version >= 0 && pkg_version <= 6) { - chip_name = chip_desc[pkg_version]; + if (pkgVersion >= 0 && pkgVersion <= 6) { + chipName = chipDesc[pkgVersion]; } else { - chip_name = "Unknown ESP32"; + chipName = "Unknown ESP32"; } - if (rev3 && (pkg_version === 0 || pkg_version === 1)) { - chip_name += "-V3"; + if (rev3 && (pkgVersion === 0 || pkgVersion === 1)) { + chipName += "-V3"; } - return chip_name + " (revision " + chip_revision + ")"; + return chipName + " (revision " + chipRevision + ")"; } public async getChipFeatures(loader: ESPLoader) { const features = ["Wi-Fi"]; const word3 = await this.readEfuse(loader, 3); - const chip_ver_dis_bt = word3 & (1 << 1); - if (chip_ver_dis_bt === 0) { + const chipVerDisBt = word3 & (1 << 1); + if (chipVerDisBt === 0) { features.push(" BT"); } - const chip_ver_dis_app_cpu = word3 & (1 << 0); - if (chip_ver_dis_app_cpu !== 0) { + const chipVerDisAppCpu = word3 & (1 << 0); + if (chipVerDisAppCpu !== 0) { features.push(" Single Core"); } else { features.push(" Dual Core"); } - const chip_cpu_freq_rated = word3 & (1 << 13); - if (chip_cpu_freq_rated !== 0) { - const chip_cpu_freq_low = word3 & (1 << 12); - if (chip_cpu_freq_low !== 0) { + const chipCpuFreqRated = word3 & (1 << 13); + if (chipCpuFreqRated !== 0) { + const chipCpuFreqLow = word3 & (1 << 12); + if (chipCpuFreqLow !== 0) { features.push(" 160MHz"); } else { features.push(" 240MHz"); } } - const pkg_version = await this.getPkgVersion(loader); - if ([2, 4, 5, 6].indexOf(pkg_version) !== -1) { + const pkgVersion = await this.getPkgVersion(loader); + if ([2, 4, 5, 6].indexOf(pkgVersion) !== -1) { features.push(" Embedded Flash"); } - if (pkg_version === 6) { + if (pkgVersion === 6) { features.push(" Embedded PSRAM"); } const word4 = await this.readEfuse(loader, 4); - const adc_vref = (word4 >> 8) & 0x1f; - if (adc_vref !== 0) { + const adcVref = (word4 >> 8) & 0x1f; + if (adcVref !== 0) { features.push(" VRef calibration in efuse"); } - const blk3_part_res = (word3 >> 14) & 0x1; - if (blk3_part_res !== 0) { + const blk3PartRes = (word3 >> 14) & 0x1; + if (blk3PartRes !== 0) { features.push(" BLK3 partially reserved"); } const word6 = await this.readEfuse(loader, 6); - const coding_scheme = word6 & 0x3; - const coding_scheme_arr = ["None", "3/4", "Repeat (UNSUPPORTED)", "Invalid"]; - features.push(" Coding Scheme " + coding_scheme_arr[coding_scheme]); + const codingScheme = word6 & 0x3; + const codingSchemeArr = ["None", "3/4", "Repeat (UNSUPPORTED)", "Invalid"]; + features.push(" Coding Scheme " + codingSchemeArr[codingScheme]); return features; } public async getCrystalFreq(loader: ESPLoader) { - const uart_div = (await loader.readReg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; - const ets_xtal = (loader.transport.baudrate * uart_div) / 1000000 / this.XTAL_CLK_DIVIDER; - let norm_xtal; - if (ets_xtal > 33) { - norm_xtal = 40; + 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 { - norm_xtal = 26; + normXtal = 26; } - if (Math.abs(norm_xtal - ets_xtal) > 1) { + if (Math.abs(normXtal - etsXtal) > 1) { loader.info("WARNING: Unsupported crystal in use"); } - return norm_xtal; + return normXtal; } public _d2h(d: number) { diff --git a/src/targets/esp32c3.ts b/src/targets/esp32c3.ts index 7f51544..1f281ef 100644 --- a/src/targets/esp32c3.ts +++ b/src/targets/esp32c3.ts @@ -37,27 +37,27 @@ export class ESP32C3ROM extends ROM { public ROM_TEXT = ESP32C3_STUB.text; public async getPkgVersion(loader: ESPLoader): Promise { - const num_word = 3; - const block1_addr = this.EFUSE_BASE + 0x044; - const addr = block1_addr + 4 * num_word; + const numWord = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const addr = block1Addr + 4 * numWord; const word3 = await loader.readReg(addr); - const pkg_version = (word3 >> 21) & 0x07; - return pkg_version; + const pkgVersion = (word3 >> 21) & 0x07; + return pkgVersion; } public async getChipRevision(loader: ESPLoader): Promise { - const block1_addr = this.EFUSE_BASE + 0x044; - const num_word = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const numWord = 3; const pos = 18; - const addr = block1_addr + 4 * num_word; + const addr = block1Addr + 4 * numWord; const ret = ((await loader.readReg(addr)) & (0x7 << pos)) >> pos; return ret; } public async getChipDescription(loader: ESPLoader) { let desc: string; - const pkg_ver = await this.getPkgVersion(loader); - if (pkg_ver === 0) { + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer === 0) { desc = "ESP32-C3"; } else { desc = "unknown ESP32-C3"; diff --git a/src/targets/esp32c6.ts b/src/targets/esp32c6.ts index 9835bf6..8480e15 100644 --- a/src/targets/esp32c6.ts +++ b/src/targets/esp32c6.ts @@ -37,33 +37,33 @@ export class ESP32C6ROM extends ROM { public ROM_TEXT = ESP32C6_STUB.text; public async getPkgVersion(loader: ESPLoader) { - const num_word = 3; - const block1_addr = this.EFUSE_BASE + 0x044; - const addr = block1_addr + 4 * num_word; + const numWord = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const addr = block1Addr + 4 * numWord; const word3 = await loader.readReg(addr); - const pkg_version = (word3 >> 21) & 0x07; - return pkg_version; + const pkgVersion = (word3 >> 21) & 0x07; + return pkgVersion; } public async getChipRevision(loader: ESPLoader) { - const block1_addr = this.EFUSE_BASE + 0x044; - const num_word = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const numWord = 3; const pos = 18; - const addr = block1_addr + 4 * num_word; + const addr = block1Addr + 4 * numWord; const ret = ((await loader.readReg(addr)) & (0x7 << pos)) >> pos; return ret; } public async getChipDescription(loader: ESPLoader) { let desc: string; - const pkg_ver = await this.getPkgVersion(loader); - if (pkg_ver === 0) { + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer === 0) { desc = "ESP32-C6"; } else { desc = "unknown ESP32-C6"; } - const chip_rev = await this.getChipRevision(loader); - desc += " (revision " + chip_rev + ")"; + const chipRev = await this.getChipRevision(loader); + desc += " (revision " + chipRev + ")"; return desc; } diff --git a/src/targets/esp32h2.ts b/src/targets/esp32h2.ts index 5b44d75..294d3ab 100644 --- a/src/targets/esp32h2.ts +++ b/src/targets/esp32h2.ts @@ -59,9 +59,9 @@ export class ESP32H2ROM extends ROM { } public async postConnect(loader: ESPLoader) { - const buf_no = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; - loader.debug("In _post_connect " + buf_no); - if (buf_no == this.UARTDEV_BUF_NO_USB) { + 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; } } diff --git a/src/targets/esp32s2.ts b/src/targets/esp32s2.ts index 2b59052..1d7f2c4 100644 --- a/src/targets/esp32s2.ts +++ b/src/targets/esp32s2.ts @@ -37,19 +37,19 @@ export class ESP32S2ROM extends ROM { public ROM_TEXT = ESP32S2_STUB.text; public async getPkgVersion(loader: ESPLoader): Promise { - const num_word = 3; - const block1_addr = this.EFUSE_BASE + 0x044; - const addr = block1_addr + 4 * num_word; + const numWord = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const addr = block1Addr + 4 * numWord; const word3 = await loader.readReg(addr); - const pkg_version = (word3 >> 21) & 0x0f; - return pkg_version; + const pkgVersion = (word3 >> 21) & 0x0f; + return pkgVersion; } public async getChipDescription(loader: ESPLoader) { - const chip_desc = ["ESP32-S2", "ESP32-S2FH16", "ESP32-S2FH32"]; - const pkg_ver = await this.getPkgVersion(loader); - if (pkg_ver >= 0 && pkg_ver <= 2) { - return chip_desc[pkg_ver]; + 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"; } @@ -57,19 +57,19 @@ export class ESP32S2ROM extends ROM { public async getChipFeatures(loader: ESPLoader) { const features = ["Wi-Fi"]; - const pkg_ver = await this.getPkgVersion(loader); - if (pkg_ver == 1) { + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer == 1) { features.push("Embedded 2MB Flash"); - } else if (pkg_ver == 2) { + } else if (pkgVer == 2) { features.push("Embedded 4MB Flash"); } - const num_word = 4; - const block2_addr = this.EFUSE_BASE + 0x05c; - const addr = block2_addr + 4 * num_word; + const numWord = 4; + const block2Addr = this.EFUSE_BASE + 0x05c; + const addr = block2Addr + 4 * numWord; const word4 = await loader.readReg(addr); - const block2_ver = (word4 >> 4) & 0x07; + const block2Ver = (word4 >> 4) & 0x07; - if (block2_ver == 1) { + if (block2Ver == 1) { features.push("ADC and temperature sensor calibration in BLK2 of efuse"); } return features; diff --git a/src/targets/esp32s3.ts b/src/targets/esp32s3.ts index 53b3719..4749243 100644 --- a/src/targets/esp32s3.ts +++ b/src/targets/esp32s3.ts @@ -55,9 +55,9 @@ export class ESP32S3ROM extends ROM { } public async postConnect(loader: ESPLoader) { - const buf_no = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; - loader.debug("In _post_connect " + buf_no); - if (buf_no == this.UARTDEV_BUF_NO_USB) { + 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; } } diff --git a/src/targets/esp8266.ts b/src/targets/esp8266.ts index be56348..e446118 100644 --- a/src/targets/esp8266.ts +++ b/src/targets/esp8266.ts @@ -52,8 +52,8 @@ export class ESP8266ROM extends ROM { const efuse3 = await this.readEfuse(loader, 2); const efuse0 = await this.readEfuse(loader, 0); - const is_8285 = ((efuse0 & (1 << 4)) | (efuse3 & (1 << 16))) != 0; // One or the other efuse bit is set for ESP8285 - return is_8285 ? "ESP8285" : "ESP8266EX"; + const is8285 = ((efuse0 & (1 << 4)) | (efuse3 & (1 << 16))) != 0; // One or the other efuse bit is set for ESP8285 + return is8285 ? "ESP8285" : "ESP8266EX"; } public getChipFeatures = async (loader: ESPLoader) => { @@ -63,24 +63,24 @@ export class ESP8266ROM extends ROM { }; public async getCrystalFreq(loader: ESPLoader) { - const uart_div = (await loader.readReg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; - const ets_xtal = (loader.transport.baudrate * uart_div) / 1000000 / this.XTAL_CLK_DIVIDER; - let norm_xtal; - if (ets_xtal > 33) { - norm_xtal = 40; + 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 { - norm_xtal = 26; + normXtal = 26; } - if (Math.abs(norm_xtal - ets_xtal) > 1) { + if (Math.abs(normXtal - etsXtal) > 1) { loader.info( "WARNING: Detected crystal freq " + - ets_xtal + + etsXtal + "MHz is quite different to normalized freq " + - norm_xtal + + normXtal + "MHz. Unsupported crystal in use?", ); } - return norm_xtal; + return normXtal; } public _d2h(d: number) { diff --git a/src/webserial.ts b/src/webserial.ts index c8c564e..4a443fc 100644 --- a/src/webserial.ts +++ b/src/webserial.ts @@ -23,8 +23,8 @@ export interface SerialOptions { * const port = await navigator.serial.requestPort(); */ class Transport { - public slip_reader_enabled = false; - public left_over = new Uint8Array(0); + public slipReaderEnabled = false; + public leftOver = new Uint8Array(0); public baudrate = 0; constructor(public device: SerialPort) {} @@ -54,34 +54,34 @@ class Transport { * @returns {Uint8Array} Formatted unsigned 8 bit data array. */ slipWriter(data: Uint8Array) { - let count_esc = 0; + let countEsc = 0; let i = 0, j = 0; for (i = 0; i < data.length; i++) { if (data[i] === 0xc0 || data[i] === 0xdb) { - count_esc++; + countEsc++; } } - const out_data = new Uint8Array(2 + count_esc + data.length); - out_data[0] = 0xc0; + const outData = new Uint8Array(2 + countEsc + data.length); + outData[0] = 0xc0; j = 1; for (i = 0; i < data.length; i++, j++) { if (data[i] === 0xc0) { - out_data[j++] = 0xdb; - out_data[j] = 0xdc; + outData[j++] = 0xdb; + outData[j] = 0xdc; continue; } if (data[i] === 0xdb) { - out_data[j++] = 0xdb; - out_data[j] = 0xdd; + outData[j++] = 0xdb; + outData[j] = 0xdd; continue; } - out_data[j] = data[i]; + outData[j] = data[i]; } - out_data[j] = 0xc0; - return out_data; + outData[j] = 0xc0; + return outData; } /** @@ -89,11 +89,11 @@ class Transport { * @param {Uint8Array} data 8 bit unsigned data array to write to device. */ async write(data: Uint8Array) { - const out_data = this.slipWriter(data); + const outData = this.slipWriter(data); if (this.device.writable) { const writer = this.device.writable.getWriter(); - await writer.write(out_data); + await writer.write(outData); writer.releaseLock(); } } @@ -119,45 +119,45 @@ class Transport { */ slipReader(data: Uint8Array) { let i = 0; - let data_start = 0, - data_end = 0; + let dataStart = 0, + dataEnd = 0; let state = "init"; while (i < data.length) { if (state === "init" && data[i] == 0xc0) { - data_start = i + 1; + dataStart = i + 1; state = "valid_data"; i++; continue; } if (state === "valid_data" && data[i] == 0xc0) { - data_end = i - 1; + dataEnd = i - 1; state = "packet_complete"; break; } i++; } if (state !== "packet_complete") { - this.left_over = data; + this.leftOver = data; return new Uint8Array(0); } - this.left_over = data.slice(data_end + 2); - const temp_pkt = new Uint8Array(data_end - data_start + 1); + this.leftOver = data.slice(dataEnd + 2); + const tempPkt = new Uint8Array(dataEnd - dataStart + 1); let j = 0; - for (i = data_start; i <= data_end; i++, j++) { + for (i = dataStart; i <= dataEnd; i++, j++) { if (data[i] === 0xdb && data[i + 1] === 0xdc) { - temp_pkt[j] = 0xc0; + tempPkt[j] = 0xc0; i++; continue; } if (data[i] === 0xdb && data[i + 1] === 0xdd) { - temp_pkt[j] = 0xdb; + tempPkt[j] = 0xdb; i++; continue; } - temp_pkt[j] = data[i]; + tempPkt[j] = data[i]; } - const packet = temp_pkt.slice(0, j); /* Remove unused bytes due to escape seq */ + const packet = tempPkt.slice(0, j); /* Remove unused bytes due to escape seq */ return packet; } @@ -169,18 +169,18 @@ class Transport { */ async read(timeout = 0, minData = 12) { let t; - let packet = this.left_over; - this.left_over = new Uint8Array(0); - if (this.slip_reader_enabled) { - const val_final = this.slipReader(packet); - if (val_final.length > 0) { - return val_final; + 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.left_over; - this.left_over = new Uint8Array(0); + packet = this.leftOver; + this.leftOver = new Uint8Array(0); } if (this.device.readable == null) { - return this.left_over; + return this.leftOver; } const reader = this.device.readable.getReader(); @@ -193,7 +193,7 @@ class Transport { do { const { value, done } = await reader.read(); if (done) { - this.left_over = packet; + this.leftOver = packet; throw new Error("Timeout"); } const p = new Uint8Array(this._appendBuffer(packet.buffer, value.buffer)); @@ -205,7 +205,7 @@ class Transport { } reader.releaseLock(); } - if (this.slip_reader_enabled) { + if (this.slipReaderEnabled) { return this.slipReader(packet); } return packet; @@ -217,13 +217,13 @@ class Transport { * @returns {Uint8Array} 8 bit unsigned data array read from device. */ async rawRead(timeout = 0) { - if (this.left_over.length != 0) { - const p = this.left_over; - this.left_over = new Uint8Array(0); + if (this.leftOver.length != 0) { + const p = this.leftOver; + this.leftOver = new Uint8Array(0); return p; } if (!this.device.readable) { - return this.left_over; + return this.leftOver; } const reader = this.device.readable.getReader(); let t; @@ -274,6 +274,7 @@ class Transport { /** * 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: SerialOptions = {}) { await this.device.open({ @@ -285,7 +286,7 @@ class Transport { flowControl: serialOptions?.flowControl, }); this.baudrate = baud; - this.left_over = new Uint8Array(0); + this.leftOver = new Uint8Array(0); } async sleep(ms: number) { From 6b1d0b9d518b63a2276ca1952e8fe202a7b91a22 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Thu, 2 Nov 2023 20:02:56 +0800 Subject: [PATCH 8/9] add jsdocs for serial options --- src/esploader.ts | 10 ++++++++-- src/webserial.ts | 48 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/esploader.ts b/src/esploader.ts index f1b58f4..368e62c 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -250,8 +250,8 @@ export class ESPLoader { * 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. - * ```ts - * const myLoader = new ESPLoader({transport: Transport, baudrate: number, terminal?: IEspLoaderTerminal }); + * ``` + * const myLoader = new ESPLoader({ transport: Transport, baudrate: number, terminal?: IEspLoaderTerminal }); * ``` */ constructor(options: LoaderOptions) { @@ -435,6 +435,12 @@ export class ESPLoader { } } + /** + * Use the device serial port read function with given timeout to create a valid packet. + * @param op Operation number + * @param timeout timeout number in milliseconds + * @returns {[number, Uint8Array]} valid response packet. + */ async readPacket(op: number | null = null, timeout = 3000): Promise<[number, Uint8Array]> { // Check up-to next 100 packets for valid response packet for (let i = 0; i < 100; i++) { diff --git a/src/webserial.ts b/src/webserial.ts index 4a443fc..48ddcb9 100644 --- a/src/webserial.ts +++ b/src/webserial.ts @@ -1,18 +1,50 @@ /* global SerialPort */ +/** + * 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 { - /* - 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. - */ + /** + * 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; } @@ -20,7 +52,9 @@ export interface SerialOptions { * 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 { public slipReaderEnabled = false; From b5da6b80361fac5dbf418d49bd037f225bf37d64 Mon Sep 17 00:00:00 2001 From: Brian Ignacio Date: Fri, 3 Nov 2023 15:10:42 +0800 Subject: [PATCH 9/9] fix lint --- src/esploader.ts | 4 ++-- src/webserial.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/esploader.ts b/src/esploader.ts index 368e62c..255d9d1 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -437,8 +437,8 @@ export class ESPLoader { /** * Use the device serial port read function with given timeout to create a valid packet. - * @param op Operation number - * @param timeout timeout number in milliseconds + * @param {number} op Operation number + * @param {number} timeout timeout number in milliseconds * @returns {[number, Uint8Array]} valid response packet. */ async readPacket(op: number | null = null, timeout = 3000): Promise<[number, Uint8Array]> { diff --git a/src/webserial.ts b/src/webserial.ts index 48ddcb9..f4b16d7 100644 --- a/src/webserial.ts +++ b/src/webserial.ts @@ -1,9 +1,9 @@ -/* global SerialPort */ +/* global SerialPort, ParityType, FlowControlType */ /** * 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