From 7705fc1da5610be025acca824d0ed9d055c5947c Mon Sep 17 00:00:00 2001 From: Guillaume Jenkins Date: Fri, 14 Sep 2018 11:25:53 -0400 Subject: [PATCH] Pair device dialog (#1217) * WebUSB E2E experience * Design feedback * adding docs * remove i got it * bring back download again * updated pair dialog wording * tweak style * make drive name strong * fix isAvailable -> isEnabled * upgrading pxt reference * fixed typo * bump pxt --- docs/SUMMARY.md | 3 +- docs/device/usb/webusb.md | 31 ++++ docs/device/usb/windows-chrome.md | 8 + docs/static/download/firmware.png | Bin 15815 -> 15178 bytes docs/static/download/pair.png | Bin 0 -> 15344 bytes editor/extension.ts | 233 +++++++++++++++++++++--------- package.json | 2 +- pxtarget.json | 3 +- theme/style.less | 6 + 9 files changed, 215 insertions(+), 71 deletions(-) create mode 100644 docs/device/usb/webusb.md create mode 100644 docs/static/download/pair.png diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 2f955c58..fb7cd1b9 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -352,6 +352,7 @@ * [Serial](/device/serial) * [Servo](/device/servo) * [Simulator](/device/simulator) - * [Usb](/device/usb) + * [USB](/device/usb) + * [WebUSB](/device/usb/webusb) * [Flashing via HID (CMSIS-DAP)](/hidflash) diff --git a/docs/device/usb/webusb.md b/docs/device/usb/webusb.md new file mode 100644 index 00000000..5d82ce5f --- /dev/null +++ b/docs/device/usb/webusb.md @@ -0,0 +1,31 @@ +# WebUSB + +WebUSB is an emerging web standard that allows to access USB devices from web pages. +It allows for a **one-click download** without installing any additional app or software! It also allows to receive data from the @boardname@. + +## Support + +* Chrome 65+ for Android, Chrome OS, Linux, macOS and Windows 10. + +## Upgrade your Firmware + +Make sure that your @boardname@ is running version **0248** or above of the firmware. Upgrading is as easy as dragging a file and it takes a few seconds to get it done. + +[Check out the instructions to check and upgrade your @boardname@.](https://support.microbit.org/support/solutions/articles/19000084059-beta-testing-web-usb) + +## Pair your device + +To get started with WebUSB, + +* connect your @boardname@ to your computer with the microUSB cable +* open a script +* open the gearwheel menu and select **Pair device** +* click on the **Pair device** button and select your @boardname@ in the list + +## One-click Download + +Once your @boardname@ is paired, MakeCode will use WebUSB to transfer the code without having to drag and drop. Happy coding! + +## Console output + +MakeCode will be able to "listen" to your @boardname@ and display the console output, generated by ``console.log`` for example. diff --git a/docs/device/usb/windows-chrome.md b/docs/device/usb/windows-chrome.md index 1c53186b..156830f4 100644 --- a/docs/device/usb/windows-chrome.md +++ b/docs/device/usb/windows-chrome.md @@ -1,5 +1,13 @@ # Uploading from Chrome for Windows +## ~ hint + +Starting with Chrome 65 on Windows 10, +you can use **WebUSB** to download with one-click. +[Learn more about WebUSB...](/device/usb/webusb). + +## ~ + While you're writing and testing your programs, you'll mostly be [running them in the simulator](/device/simulator), but once you've finished your program you can **compile** it and run it on your micro:bit. diff --git a/docs/static/download/firmware.png b/docs/static/download/firmware.png index fb557176306c2b1eac99020e3bb79d1159c12aac..c2280fb2c8e0e2e82cf8b86a9d62c7974237ab0f 100644 GIT binary patch literal 15178 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 literal 15815 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 C@C%Co literal 0 HcmV?d00001 diff --git a/editor/extension.ts b/editor/extension.ts index b4b4a8bb..33971031 100644 --- a/editor/extension.ts +++ b/editor/extension.ts @@ -432,39 +432,12 @@ namespace pxt.editor { }); } - function getFlashChecksumsAsync(wrap: DAPWrapper) { - log("getting existing flash checksums") - let pages = numPages - return wrap.cortexM.runCode(computeChecksums2, loadAddr, loadAddr + 1, 0xffffffff, stackAddr, true, - dataAddr, 0, pageSize, pages) - .then(() => wrap.cortexM.memory.readBlock(dataAddr, pages * 2, pageSize)) - } - - function onlyChanged(blocks: UF2.Block[], checksums: Uint8Array) { - return blocks.filter(b => { - let idx = b.targetAddr / pageSize - U.assert((idx | 0) == idx) - U.assert(b.data.length == pageSize) - if (idx * 8 + 8 > checksums.length) - return true // out of range? - let c0 = HF2.read32(checksums, idx * 8) - let c1 = HF2.read32(checksums, idx * 8 + 4) - let ch = murmur3_core(b.data) - if (c0 == ch[0] && c1 == ch[1]) - return false - return true - }) - } - - export function deployCoreAsync(resp: pxtc.CompileResult, d: pxt.commands.DeployOptions = {}): Promise { - let saveHexAsync = () => { - return pxt.commands.saveOnlyAsync(resp) - } - + function flashAsync(resp: pxtc.CompileResult, d: pxt.commands.DeployOptions = {}): Promise { startTime = 0 let wrap: DAPWrapper log("init") + d.showNotification(U.lf("Downloading...")); pxt.tickEvent("hid.flash.start"); return Promise.resolve() .then(() => { @@ -508,7 +481,7 @@ namespace pxt.editor { .then(() => { return resp.confirmAsync({ header: lf("Something went wrong..."), - body: lf("Flashing your {0} took too long. Please disconnect your {0} from your computer and reconnect it, then flash using drag and drop.", pxt.appTarget.appTheme.boardName || lf("device")), + body: lf("One-click download took too long. Please disconnect your {0} from your computer and reconnect it, then manually download your program using drag and drop.", pxt.appTarget.appTheme.boardName || lf("device")), disagreeLbl: lf("Ok"), hideAgree: true }); @@ -516,21 +489,75 @@ namespace pxt.editor { .then(() => { return pxt.commands.saveOnlyAsync(resp); }); + } else if (e.isUserError) { + d.reportError(e.message); + return Promise.resolve(); } else { pxt.tickEvent("hid.flash.unknownerror"); return resp.confirmAsync({ - header: U.lf("We cannot flash your program..."), - body: U.lf("Please flash your device using drag and drop this time. Automatic flashing might work afterwards."), + header: U.lf("Something went wrong..."), + body: U.lf("Please manually download your program to your device using drag and drop. One-click download might work afterwards."), disagreeLbl: lf("Ok"), hideAgree: true }) .then(() => { - return saveHexAsync(); + return pxt.commands.saveOnlyAsync(resp); }); } }); } + function getFlashChecksumsAsync(wrap: DAPWrapper) { + log("getting existing flash checksums") + let pages = numPages + return wrap.cortexM.runCode(computeChecksums2, loadAddr, loadAddr + 1, 0xffffffff, stackAddr, true, + dataAddr, 0, pageSize, pages) + .then(() => wrap.cortexM.memory.readBlock(dataAddr, pages * 2, pageSize)) + } + + function onlyChanged(blocks: UF2.Block[], checksums: Uint8Array) { + return blocks.filter(b => { + let idx = b.targetAddr / pageSize + U.assert((idx | 0) == idx) + U.assert(b.data.length == pageSize) + if (idx * 8 + 8 > checksums.length) + return true // out of range? + let c0 = HF2.read32(checksums, idx * 8) + let c1 = HF2.read32(checksums, idx * 8 + 4) + let ch = murmur3_core(b.data) + if (c0 == ch[0] && c1 == ch[1]) + return false + return true + }) + } + + export function deployCoreAsync(resp: pxtc.CompileResult, d: pxt.commands.DeployOptions = {}): Promise { + const saveHexAsync = () => { + return pxt.commands.saveOnlyAsync(resp); + }; + return Promise.resolve() + .then(() => { + const isUwp = !!(window as any).Windows; + if (isUwp) { + // Go straight to flashing + return flashAsync(resp, d); + } + if (!pxt.usb.isEnabled) { + return saveHexAsync(); + } + return pxt.usb.isPairedAsync() + .then((isPaired) => { + if (isPaired) { + // Already paired from earlier in the session or from previous session + return flashAsync(resp, d); + } + + // No device paired, prompt user + return saveHexAsync(); + }); + }) + } + /** * FALSE @@ -798,6 +825,7 @@ namespace pxt.editor { res.blocklyPatch = patchBlocks; res.showUploadInstructionsAsync = showUploadInstructionsAsync; + res.webUsbPairDialogAsync = webUsbPairDialogAsync; return Promise.resolve(res); } @@ -832,29 +860,96 @@ namespace pxt.editor { valueNode.appendChild(s); } - function showUploadInstructionsAsync(fn: string, url: string, confirmAsync: (options: any) => Promise) { + function webUsbPairDialogAsync(confirmAsync: (options: any) => Promise): Promise { const boardName = pxt.appTarget.appTheme.boardName || "???"; - const boardDriveName = pxt.appTarget.appTheme.driveDisplayName || pxt.appTarget.compile.driveName || "???"; - const canWebusb = pxt.usb.isEnabled; - - // https://msdn.microsoft.com/en-us/library/cc848897.aspx - // "For security reasons, data URIs are restricted to downloaded resources. - // Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements" - const downloadAgain = false // !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge(); - const docUrl = pxt.appTarget.appTheme.usbDocs; - const columns = canWebusb ? "eleven" : "sixteen"; - const htmlBody = `
- ${canWebusb ? `
-
${lf("One click download?")}
- ${lf("Pair your device to download instantly.")} +
` : ''} -
+
+
+
+
+
+
+
+
+
+ +
+
+
+ 1 + ${lf("Connect the {0} to your computer with a USB cable", boardName)} +
+ ${lf("Use the microUSB port on the top of the {0}", boardName)} +
+
+
+
+
+
+
+ +
+
+
+ 2 + ${lf("Pair your {0}", boardName)} +
+ ${lf("Click 'Pair device' below and select BBC micro:bit CMSIS-DAP or DAPLink CMSIS-DAP from the list")} +
+
+
+
+
+
+
+
+
+
`; + + const buttons: any[] = []; + const docUrl = pxt.appTarget.appTheme.usbDocs; + if (docUrl) { + buttons.push({ + label: lf("Help"), + icon: "help", + className: "lightgrey", + url: `${docUrl}/webusb` + }); + } + + return confirmAsync({ + header: lf("Pair device for one-click downloads"), + htmlBody, + hasCloseIcon: true, + agreeLbl: lf("Pair device"), + agreeIcon: "usb", + hideCancel: true, + className: 'downloaddialog', + buttons + }); + } + + function showUploadInstructionsAsync(fn: string, url: string, confirmAsync: (options: any) => Promise) { + const boardName = pxt.appTarget.appTheme.boardName || "???"; + const boardDriveName = pxt.appTarget.appTheme.driveDisplayName || pxt.appTarget.compile.driveName || "???"; + + // https://msdn.microsoft.com/en-us/library/cc848897.aspx + // "For security reasons, data URIs are restricted to downloaded resources. + // Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements" + const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge(); + const docUrl = pxt.appTarget.appTheme.usbDocs; + + const htmlBody = ` +
+
@@ -884,7 +979,7 @@ namespace pxt.editor { 2 ${lf("Move the .hex file to the {0}", boardName)}
- ${lf("Locate the downloaded .hex file and drag it to the {0} drive", boardDriveName)} + ${lf("Locate the downloaded .hex file and drag it to the {0} drive", boardDriveName)}
@@ -896,33 +991,35 @@ namespace pxt.editor {
`; - return confirmAsync({ - header: lf("Download to your micro:bit"), - htmlBody, - hasCloseIcon: true, - hideCancel: true, - hideAgree: false, - agreeLbl: lf("I got it"), - className: 'downloaddialog', - buttons: [downloadAgain ? { + const buttons: any[] = []; + + if (downloadAgain) { + buttons.push({ label: fn, icon: "download", className: "lightgrey focused", url, fileName: fn - } : undefined, canWebusb ? { - label: lf("Pair device"), - icon: "usb", - className: "lightgrey focused", - onclick: () => { - pxt.usb.pairAsync().done(); - } - } : undefined, docUrl ? { + }); + } + + if (docUrl) { + buttons.push({ label: lf("Help"), icon: "help", className: "lightgrey", url: docUrl - } : undefined] + }); + } + + return confirmAsync({ + header: lf("Download to your {0}", pxt.appTarget.appTheme.boardName), + htmlBody, + hasCloseIcon: true, + hideCancel: true, + hideAgree: true, + className: 'downloaddialog', + buttons //timeout: 20000 }).then(() => { }); } diff --git a/package.json b/package.json index f0465373..b3b10577 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,6 @@ }, "dependencies": { "pxt-common-packages": "0.23.53", - "pxt-core": "3.22.18" + "pxt-core": "3.22.20" } } diff --git a/pxtarget.json b/pxtarget.json index 216c8b9c..3ed06d04 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -90,7 +90,8 @@ "vid": "0x0d28", "pid": "0x0204" } - ] + ], + "webUSB": true }, "runtime": { "mathBlocks": true, diff --git a/theme/style.less b/theme/style.less index e458a8d6..6aaebb94 100644 --- a/theme/style.less +++ b/theme/style.less @@ -79,3 +79,9 @@ /* Large Monitor */ @media only screen and (min-width: @largeMonitorBreakpoint) { } + + +/* Download dialog */ +.ui.downloaddialog.modal>.content { + padding: 1rem; +}