Unzipping and Flashing now working
This commit is contained in:
parent
af54b570bb
commit
00d234801e
6 changed files with 210 additions and 178 deletions
56
Gemfile.lock
56
Gemfile.lock
|
|
@ -1,79 +1,83 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
addressable (2.8.1)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
colorator (1.1.0)
|
||||
concurrent-ruby (1.1.9)
|
||||
deep_merge (1.2.1)
|
||||
concurrent-ruby (1.1.10)
|
||||
deep_merge (1.2.2)
|
||||
em-websocket (0.5.3)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0)
|
||||
eventmachine (1.2.7)
|
||||
ffi (1.15.5)
|
||||
forwardable-extended (2.6.0)
|
||||
google-protobuf (3.21.12)
|
||||
google-protobuf (3.21.12-x86_64-linux)
|
||||
http_parser.rb (0.8.0)
|
||||
i18n (1.8.11)
|
||||
i18n (1.12.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
image_processing (1.12.2)
|
||||
mini_magick (>= 4.9.5, < 5)
|
||||
ruby-vips (>= 2.0.17, < 3)
|
||||
jekyll (4.2.1)
|
||||
jekyll (4.3.1)
|
||||
addressable (~> 2.4)
|
||||
colorator (~> 1.0)
|
||||
em-websocket (~> 0.5)
|
||||
i18n (~> 1.0)
|
||||
jekyll-sass-converter (~> 2.0)
|
||||
jekyll-sass-converter (>= 2.0, < 4.0)
|
||||
jekyll-watch (~> 2.0)
|
||||
kramdown (~> 2.3)
|
||||
kramdown (~> 2.3, >= 2.3.1)
|
||||
kramdown-parser-gfm (~> 1.0)
|
||||
liquid (~> 4.0)
|
||||
mercenary (~> 0.4.0)
|
||||
mercenary (>= 0.3.6, < 0.5)
|
||||
pathutil (~> 0.9)
|
||||
rouge (~> 3.0)
|
||||
rouge (>= 3.0, < 5.0)
|
||||
safe_yaml (~> 1.0)
|
||||
terminal-table (~> 2.0)
|
||||
terminal-table (>= 1.8, < 4.0)
|
||||
webrick (~> 1.7)
|
||||
jekyll-get-json (1.0.0)
|
||||
deep_merge (~> 1.2)
|
||||
jekyll (>= 3.0)
|
||||
jekyll-paginate (1.1.0)
|
||||
jekyll-redirect-from (0.16.0)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-sass-converter (2.1.0)
|
||||
sassc (> 2.0.1, < 3.0)
|
||||
jekyll-seo-tag (2.7.1)
|
||||
jekyll-sass-converter (3.0.0)
|
||||
sass-embedded (~> 1.54)
|
||||
jekyll-seo-tag (2.8.0)
|
||||
jekyll (>= 3.8, < 5.0)
|
||||
jekyll-sitemap (1.4.0)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-watch (2.2.1)
|
||||
listen (~> 3.0)
|
||||
kramdown (2.3.1)
|
||||
kramdown (2.4.0)
|
||||
rexml
|
||||
kramdown-parser-gfm (1.1.0)
|
||||
kramdown (~> 2.0)
|
||||
liquid (4.0.3)
|
||||
listen (3.7.0)
|
||||
liquid (4.0.4)
|
||||
listen (3.8.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.4.0)
|
||||
mini_magick (4.11.0)
|
||||
mini_magick (4.12.0)
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
public_suffix (4.0.6)
|
||||
public_suffix (5.0.1)
|
||||
rake (13.0.6)
|
||||
rb-fsevent (0.11.0)
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.2.5)
|
||||
rouge (3.26.1)
|
||||
rouge (4.0.1)
|
||||
ruby-vips (2.1.4)
|
||||
ffi (~> 1.12)
|
||||
safe_yaml (1.0.5)
|
||||
sassc (2.4.0)
|
||||
ffi (~> 1.9)
|
||||
terminal-table (2.0.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
unicode-display_width (1.8.0)
|
||||
sass-embedded (1.54.6)
|
||||
google-protobuf (~> 3.19)
|
||||
rake (>= 10.0.0)
|
||||
terminal-table (3.0.2)
|
||||
unicode-display_width (>= 1.1.1, < 3)
|
||||
unicode-display_width (2.4.2)
|
||||
webrick (1.7.0)
|
||||
|
||||
PLATFORMS
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
"version": "v3.14.0"
|
||||
},
|
||||
"esp32s2": {
|
||||
"version": "0.11.0"
|
||||
"version": "0.12.0"
|
||||
},
|
||||
"esp32s3": {
|
||||
"version": "0.11.0"
|
||||
"version": "0.12.0"
|
||||
},
|
||||
"esp32c3": {},
|
||||
"esp32": {},
|
||||
|
|
|
|||
|
|
@ -117,7 +117,9 @@
|
|||
{% if page.family == 'esp32s2' or page.family == 'esp32c3' or page.family == 'esp32s3' or page.family == 'esp32' %}
|
||||
<button is="cp-install-button" class="installer-button" boardname="{{ page.name }}" boardid="{{ board_id }}"
|
||||
{% for extension in version.extensions %}
|
||||
{{ extension }}file="{{ board_url }}/en_US/adafruit-circuitpython-{{ board_id }}-en_US-{{ version.version }}.{{ extension }}"
|
||||
{% comment %}
|
||||
{{ extension }}file="{{ board_url }}/en_US/adafruit-circuitpython-{{ board_id }}-en_US-{{ version.version }}.{{ extension }}"
|
||||
{% endcomment %}
|
||||
{% endfor %}
|
||||
{% if bootloader_version and bootloader_id %}
|
||||
bootloader="https://github.com/adafruit/tinyuf2/releases/download/{{ bootloader_version }}/tinyuf2-{{ bootloader_id }}-{{ bootloader_version }}.zip"
|
||||
|
|
|
|||
BIN
bin/tinyuf2-adafruit_feather_esp32s3_tft-0.12.0.zip
Normal file
BIN
bin/tinyuf2-adafruit_feather_esp32s3_tft-0.12.0.zip
Normal file
Binary file not shown.
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
import {html, render} from 'https://unpkg.com/lit-html?module';
|
||||
import { html } from 'https://unpkg.com/lit-html?module';
|
||||
import * as zip from "https://deno.land/x/zipjs/index.js";
|
||||
import * as esptoolPackage from "https://unpkg.com/esp-web-flasher@5.1.2/dist/web/index.js?module"
|
||||
import { InstallButton } from "./installer.js";
|
||||
|
||||
|
|
@ -62,12 +63,15 @@ export class CPInstallButton extends InstallButton {
|
|||
|
||||
// If this is empty, it's a problem
|
||||
this.boardId = this.getAttribute("boardid");
|
||||
this.releaseVersion = this.getAttribute("version");
|
||||
|
||||
// We need either the bootloader and uf2 or bin file to continue
|
||||
this.bootloaderUrl = this.getAttribute("bootloader");
|
||||
if (this.bootloaderUrl) {
|
||||
this.bootloaderUrl = `/bin/${this.bootloaderUrl.split("/").pop()}`;
|
||||
}
|
||||
this.uf2FileUrl = this.getAttribute("uf2file");
|
||||
this.binFileUrl = this.getAttribute("binfile");
|
||||
this.releaseVersion = this.getAttribute("version");
|
||||
|
||||
// Nice to have for now
|
||||
this.chipFamily = this.getAttribute("chipfamily");
|
||||
|
|
@ -104,6 +108,7 @@ export class CPInstallButton extends InstallButton {
|
|||
// This is the data for the dialogs
|
||||
cpDialogs = {
|
||||
serialConnect: {
|
||||
closeable: true,
|
||||
template: (data) => html`
|
||||
<p>
|
||||
Welcome to the CircuitPython Installer. This tool will install CircuitPython on your ${data.boardName}.
|
||||
|
|
@ -148,24 +153,21 @@ export class CPInstallButton extends InstallButton {
|
|||
<p class="centered">Erasing Flash...</p>
|
||||
<div class="loader"><div></div><div></div><div></div><div></div></div>
|
||||
`,
|
||||
closeable: false,
|
||||
buttons: [],
|
||||
},
|
||||
flash: {
|
||||
template: (data) => html`
|
||||
<p class="centered">Flashing ${data.contents}...</p>
|
||||
<progress id="flashProgress" max="100" value="${data.percentage}"> ${data.percentage}% </progress>
|
||||
<p class="centered">${data.action} ${data.file}...</p>
|
||||
<progress id="flashProgress" max="100" value="0"></progress>
|
||||
`,
|
||||
closeable: false,
|
||||
buttons: [this.nextButton],
|
||||
buttons: [],
|
||||
},
|
||||
// We may have a waiting for Bootloader to start dialog
|
||||
copyUf2: {
|
||||
template: (data) => html`
|
||||
<p class="centered">Copying ${data.uf2file}...</p>
|
||||
<progress id="copyProgress" max="100" value="${data.percentage}"> ${data.percentage}% </progress>
|
||||
<p class="centered">Copying ${data.file}...</p>
|
||||
<progress id="copyProgress" max="100" value="0"></progress>
|
||||
`,
|
||||
closeable: false,
|
||||
buttons: [this.nextButton],
|
||||
},
|
||||
credentials: {
|
||||
|
|
@ -200,12 +202,14 @@ export class CPInstallButton extends InstallButton {
|
|||
`,
|
||||
},
|
||||
success: {
|
||||
closeable: true,
|
||||
template: (data) => html`
|
||||
<p>Successfully Completed Installation</p>
|
||||
`,
|
||||
buttons: [this.closeButton],
|
||||
},
|
||||
error: {
|
||||
closeable: true,
|
||||
template: (data) => html`
|
||||
<p>Installation Error: ${data.message}</p>
|
||||
`,
|
||||
|
|
@ -254,11 +258,10 @@ export class CPInstallButton extends InstallButton {
|
|||
});
|
||||
|
||||
await this.setBaudRateIfChipSupports(esploader.chipFamily, PREFERRED_BAUDRATE);
|
||||
console.log("Done");
|
||||
return
|
||||
}
|
||||
|
||||
// can't use it so disconnect now
|
||||
// Can't use it so disconnect now
|
||||
this.errorMsg("Oops, this is the wrong firmware for your board.")
|
||||
await this.disconnect()
|
||||
|
||||
|
|
@ -271,17 +274,17 @@ export class CPInstallButton extends InstallButton {
|
|||
}
|
||||
|
||||
async stepSerialConnect() {
|
||||
// Display Serial Connect Text
|
||||
// Display Serial Connect Dialog
|
||||
this.showDialog(this.dialogs.serialConnect, {boardName: this.boardName});
|
||||
}
|
||||
|
||||
async stepConfirm() {
|
||||
// Display Confirm Step
|
||||
// Display Confirm Dialog
|
||||
this.showDialog(this.dialogs.confirm, {boardName: this.boardName});
|
||||
}
|
||||
|
||||
async stepEraseAll() {
|
||||
// Display EraseAll Step
|
||||
// Display Erase Dialog
|
||||
this.showDialog(this.dialogs.erase);
|
||||
try {
|
||||
await this.espStub.eraseFlash();
|
||||
|
|
@ -292,40 +295,45 @@ export class CPInstallButton extends InstallButton {
|
|||
}
|
||||
|
||||
async stepFlashBin() {
|
||||
// Display FlashBin Step
|
||||
this.showDialog(this.dialogs.flash, {contents: "Bin File"});
|
||||
if (!this.binFileUrl) {
|
||||
// We shouldn't be able to get here, but just in case
|
||||
this.errorMsg("Missing bin file URL. Please make sure the installer button has this specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: This should go to the next step automatically when finished
|
||||
await this.downloadAndInstall(this.binFileUrl);
|
||||
await this.nextStep();
|
||||
}
|
||||
|
||||
async stepBootloader() {
|
||||
// Display Bootloader Step
|
||||
this.showDialog(this.dialogs.flash, {contents: "Bootloader"});
|
||||
// TODO:
|
||||
// Download zip file (this may need to come from Amazon S3)
|
||||
// Unzip file
|
||||
// Program combined.bin
|
||||
// Reboot
|
||||
// Go to next step
|
||||
if (!this.bootloaderUrl) {
|
||||
// We shouldn't be able to get here, but just in case
|
||||
this.errorMsg("Missing bootloader file URL. Please make sure the installer button has this specified.");
|
||||
return;
|
||||
}
|
||||
// Display Bootloader Dialog
|
||||
await this.downloadAndInstall(this.bootloaderUrl, 'combined.bin');
|
||||
// TODO: Reboot into bootloader
|
||||
await this.nextStep();
|
||||
}
|
||||
|
||||
async stepCopyUf2() {
|
||||
// Display CopyUf2 Step
|
||||
this.showDialog(this.dialogs.copyUf2);
|
||||
// Display CopyUf2 Dialog
|
||||
this.showDialog(this.dialogs.copyUf2, {file: this.uf2FileUrl});
|
||||
}
|
||||
|
||||
async stepSettings() {
|
||||
// Display Settings Step
|
||||
// Display Settings Dialog
|
||||
this.showDialog(this.dialogs.settings);
|
||||
}
|
||||
|
||||
async stepCredentials() {
|
||||
// Display Credentials Step
|
||||
// Display Credentials Request Dialog
|
||||
this.showDialog(this.dialogs.credentials);
|
||||
}
|
||||
|
||||
async stepSuccess() {
|
||||
// Display Success Step
|
||||
// Display Success Dialog
|
||||
this.showDialog(this.dialogs.success);
|
||||
}
|
||||
|
||||
|
|
@ -339,24 +347,120 @@ export class CPInstallButton extends InstallButton {
|
|||
// We may also want to have it return the version number and return null if not detected
|
||||
return false;
|
||||
}
|
||||
|
||||
async downloadFile(url, progressElement) {
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(url, {mode: "cors"});
|
||||
} catch (err) {
|
||||
this.errorMsg("Unable to download file: " + url);
|
||||
return null;
|
||||
}
|
||||
|
||||
const body = response.body;
|
||||
const reader = body.getReader();
|
||||
const contentLength = +response.headers.get('Content-Length');
|
||||
let receivedLength = 0;
|
||||
let chunks = [];
|
||||
while(true) {
|
||||
const {done, value} = await reader.read();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
chunks.push(value);
|
||||
receivedLength += value.length;
|
||||
progressElement.value = Math.round(receivedLength / contentLength) * 100;
|
||||
console.log(`Received ${receivedLength} of ${contentLength}`)
|
||||
}
|
||||
let chunksAll = new Uint8Array(receivedLength);
|
||||
let position = 0;
|
||||
for(let chunk of chunks) {
|
||||
chunksAll.set(chunk, position);
|
||||
position += chunk.length;
|
||||
}
|
||||
|
||||
let result = new Blob([chunksAll]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async downloadAndInstall(url, fileToExtract = null) {
|
||||
// Display Flash Dialog
|
||||
let filename = url.split("/").pop();
|
||||
|
||||
this.showDialog(this.dialogs.flash, {
|
||||
action: "Downloading",
|
||||
file: filename,
|
||||
});
|
||||
|
||||
const progressElement = this.currentDialogElement.querySelector("#flashProgress");
|
||||
|
||||
// Download the file at the url updating the progress in the process
|
||||
let fileContents = await this.downloadFile(url, progressElement);
|
||||
|
||||
// If the file is a zip file, unzip and find the file to extract
|
||||
if (filename.endsWith(".zip") && fileToExtract) {
|
||||
let foundFile;
|
||||
console.log("Extracting step");
|
||||
// Update the flash dialog
|
||||
this.showDialog(this.dialogs.flash, {
|
||||
action: "Extracting",
|
||||
file: fileToExtract,
|
||||
});
|
||||
|
||||
// Set that to the current file to flash
|
||||
[foundFile, fileContents] = await this.findAndExtractFromZip(fileContents, fileToExtract);
|
||||
if (!fileContents) {
|
||||
this.errorMsg("Unable to find " + fileToExtract + " in " + filename);
|
||||
return;
|
||||
}
|
||||
filename = foundFile;
|
||||
}
|
||||
|
||||
// Update the flash dialog
|
||||
if (fileContents) {
|
||||
console.log("Flash step");
|
||||
let lastPercent = 0;
|
||||
this.showDialog(this.dialogs.flash, {
|
||||
action: "Flashing",
|
||||
file: filename,
|
||||
});
|
||||
try {
|
||||
await this.espStub.flashData(fileContents, (bytesWritten, totalBytes) => {
|
||||
let percentage = Math.floor((bytesWritten / totalBytes) * 100);
|
||||
if (percentage != lastPercent) {
|
||||
progressElement.value = percentage;
|
||||
this.logMsg(`${percentage}% (${bytesWritten}/${totalBytes})...`);
|
||||
lastPercent = percentage;
|
||||
}
|
||||
}, 0, 0);
|
||||
} catch (err) {
|
||||
this.errorMsg("Unable to flash file: " + filename);
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async findAndExtractFromZip(zipBlob, filename) {
|
||||
const reader = new zip.ZipReader(new zip.BlobReader(zipBlob));
|
||||
|
||||
// unzip into local file cache
|
||||
let zipContents = await reader.getEntries();
|
||||
|
||||
for(const zipEntry of zipContents) {
|
||||
console.log(filename, zipEntry.filename, zipEntry.filename.localeCompare(filename));
|
||||
if (zipEntry.filename.localeCompare(filename) === 0) {
|
||||
const extractedFile = await zipEntry.getData(new zip.Uint8ArrayWriter());
|
||||
return [zipEntry.filename, extractedFile.buffer]; // ESPTool wants an ArrayBuffer
|
||||
}
|
||||
}
|
||||
|
||||
return [null, null];
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('cp-install-button', CPInstallButton, {extends: "button"});
|
||||
|
||||
// Wizard screens
|
||||
// - Menu
|
||||
// - Verify user wants to install
|
||||
// - erase flash
|
||||
// - if esp32 or c3 flash bin
|
||||
// - if s2 or s3, flash bootloader
|
||||
// - if s2 or s3, copy uf2 (May need to use File System Access API)
|
||||
// - request wifi credentials (skip, connect buttons) and AP password
|
||||
// - generate and program settings.toml via REPL
|
||||
// - install complete
|
||||
|
||||
// So we will have a couple of wizard flows and we'll need to associate the flow with the board
|
||||
// We should add the info to the board's page in the boards folder
|
||||
|
||||
// Changes to make:
|
||||
// Hide the log and make it accessible via the menu (future feature, console.log for now)
|
||||
// Generate dialogs on the fly
|
||||
|
|
@ -548,32 +652,7 @@ function updateObject(obj, path, value) {
|
|||
}
|
||||
|
||||
|
||||
let chipFiles
|
||||
async function fetchFirmwareForSelectedBoard() {
|
||||
const firmware = lookupFirmwareByBinSelector()
|
||||
|
||||
this.logMsg(`Fetching latest firmware...`)
|
||||
const response = await fetch(`${FIRMWARE_API}/wipper_releases/${firmware.id}`, {
|
||||
headers: { Accept: 'application/octet-stream' }
|
||||
})
|
||||
|
||||
// Zip stuff
|
||||
this.logMsg("Unzipping firmware bundle...")
|
||||
const blob = await response.blob()
|
||||
const reader = new zip.ZipReader(new zip.BlobReader(blob));
|
||||
|
||||
// unzip into local file cache
|
||||
chipFiles = await reader.getEntries();
|
||||
}
|
||||
|
||||
function findInZip(filename) {
|
||||
const regex = RegExp(filename.replace("VERSION", "(.*)"))
|
||||
for (let i = 0; i < chipFiles.length; i++) {
|
||||
if (chipFiles[i].filename.match(regex)) {
|
||||
return chipFiles[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function mergeSettings() {
|
||||
const { settings } = lookupFirmwareByBinSelector()
|
||||
|
|
@ -767,67 +846,4 @@ async function programScript(stages) {
|
|||
this.logMsg("To run the new firmware, please reset your device.");
|
||||
showStep(6);
|
||||
}
|
||||
|
||||
function getValidFields() {
|
||||
// Validate user inputs
|
||||
const validFields = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const { id, value } = partitionData[i]
|
||||
// password & brightness can be blank, the rest must have some value
|
||||
if (id === "network_type_wifi.network_password" ||
|
||||
value.length > 0) {
|
||||
validFields.push(i);
|
||||
}
|
||||
}
|
||||
return validFields;
|
||||
}
|
||||
|
||||
async function checkProgrammable() {
|
||||
if (getValidFields().length < 5) {
|
||||
hideStep(4)
|
||||
} else {
|
||||
showStep(4, { dimLowerSteps: false })
|
||||
}
|
||||
}
|
||||
|
||||
async function clickClear() {
|
||||
reset();
|
||||
}
|
||||
|
||||
function loadAllSettings() {
|
||||
// Load all saved settings or defaults
|
||||
//autoscroll.checked = loadSetting("autoscroll", true);
|
||||
//baudRate.value = loadSetting("baudrate", this.baudRates[0]);
|
||||
showConsole = loadSetting('showConsole', false);
|
||||
toggleConsole(showConsole);
|
||||
}
|
||||
|
||||
function loadSetting(setting, defaultValue) {
|
||||
return JSON.parse(window.localStorage.getItem(setting)) || defaultValue;
|
||||
}
|
||||
|
||||
function saveSetting(setting, value) {
|
||||
window.localStorage.setItem(setting, JSON.stringify(value));
|
||||
}
|
||||
|
||||
async function getFirmware(filename) {
|
||||
const file = findInZip(filename)
|
||||
|
||||
if (!file) {
|
||||
const msg = `No firmware file name ${filename} found in the zip!`
|
||||
this.errorMsg(msg)
|
||||
throw new Error(msg)
|
||||
}
|
||||
|
||||
this.logMsg(`Unzipping ${filename.replace('VERSION', semver)}...`)
|
||||
const firmwareFile = await file.getData(new zip.Uint8ArrayWriter())
|
||||
|
||||
return firmwareFile.buffer // ESPTool wants an ArrayBuffer
|
||||
}
|
||||
|
||||
async function getFileText(path) {
|
||||
let response = await fetch(path);
|
||||
let contents = await response.text();
|
||||
return contents;
|
||||
}
|
||||
*/
|
||||
|
|
@ -83,6 +83,7 @@ export class InstallButton extends HTMLButtonElement {
|
|||
dialogs = {
|
||||
notSupported: {
|
||||
preload: false,
|
||||
closeable: true,
|
||||
template: (data) => html`
|
||||
Sorry, <b>Web Serial</b> is not supported on your browser at this time. Browsers we expect to work:
|
||||
<ul>
|
||||
|
|
@ -94,6 +95,7 @@ export class InstallButton extends HTMLButtonElement {
|
|||
buttons: [this.closeButton],
|
||||
},
|
||||
menu: {
|
||||
closeable: true,
|
||||
template: (data) => html`
|
||||
<p>CircuitPython Installer for ${data.boardName}</p>
|
||||
<ul class="flow-menu">
|
||||
|
|
@ -109,22 +111,22 @@ export class InstallButton extends HTMLButtonElement {
|
|||
|
||||
baudRates = [
|
||||
115200,
|
||||
128000,
|
||||
153600,
|
||||
230400,
|
||||
460800,
|
||||
921600,
|
||||
1500000,
|
||||
2000000,
|
||||
];
|
||||
|
||||
connectedCallback() {
|
||||
if (!InstallButton.isSupported || !InstallButton.isAllowed) {
|
||||
if (InstallButton.isSupported && InstallButton.isAllowed) {
|
||||
this.toggleAttribute("install-supported", true);
|
||||
} else {
|
||||
this.toggleAttribute("install-unsupported", true);
|
||||
this.innerHTML = !InstallButton.isAllowed
|
||||
? "<slot name='not-allowed'>You can only install ESP devices on HTTPS websites or on the localhost.</slot>"
|
||||
: "<slot name='unsupported'>Your browser does not support installing things on ESP devices. Use Google Chrome or Microsoft Edge.</slot>";
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggleAttribute("install-supported", true);
|
||||
|
||||
this.addEventListener("click", async (e) => {
|
||||
e.preventDefault();
|
||||
// WebSerial feature detection
|
||||
|
|
@ -136,7 +138,20 @@ export class InstallButton extends HTMLButtonElement {
|
|||
});
|
||||
}
|
||||
|
||||
enabledFlowCount() {
|
||||
let enabledFlowCount = 0;
|
||||
for (const [flowId, flow] of Object.entries(this.flows)) {
|
||||
if (flow.isEnabled()) {
|
||||
enabledFlowCount++;
|
||||
}
|
||||
}
|
||||
return enabledFlowCount;
|
||||
}
|
||||
|
||||
* generateMenu(templateFunc) {
|
||||
if (this.enabledFlowCount() == 0) {
|
||||
yield html`<li>No installable options for this board.</li>`;
|
||||
}
|
||||
for (const [flowId, flow] of Object.entries(this.flows)) {
|
||||
if (flow.isEnabled()) {
|
||||
yield templateFunc(flowId, flow);
|
||||
|
|
@ -254,10 +269,6 @@ export class InstallButton extends HTMLButtonElement {
|
|||
}
|
||||
|
||||
showDialog(dialog, templateData = {}) {
|
||||
let dialogButtons;
|
||||
|
||||
// TODO: Add ability to stack dialogs by making this.currentDialogElement work as an array
|
||||
// We also may want to make it so we just get the top step type dialog
|
||||
if (this.currentDialogElement) {
|
||||
this.closeDialog();
|
||||
}
|
||||
|
|
@ -274,16 +285,15 @@ export class InstallButton extends HTMLButtonElement {
|
|||
}
|
||||
|
||||
// Close button should probably hide during certain steps such as flashing and erasing
|
||||
if ("closeable" in dialog && !dialog.closeable) {
|
||||
this.currentDialogElement.querySelector(".close-button").style.display = "none";
|
||||
} else {
|
||||
if ("closeable" in dialog && dialog.closeable) {
|
||||
this.currentDialogElement.querySelector(".close-button").style.display = "block";
|
||||
} else {
|
||||
this.currentDialogElement.querySelector(".close-button").style.display = "none";
|
||||
}
|
||||
|
||||
let dialogButtons = this.defaultButtons;
|
||||
if ('buttons' in dialog) {
|
||||
dialogButtons = dialog.buttons;
|
||||
} else {
|
||||
dialogButtons = this.defaultButtons;
|
||||
}
|
||||
|
||||
this.updateButtons();
|
||||
|
|
|
|||
Loading…
Reference in a new issue