diff --git a/cmds/cmds.ts b/cmds/cmds.ts
index bec3277e..a39d285a 100644
--- a/cmds/cmds.ts
+++ b/cmds/cmds.ts
@@ -1,6 +1,8 @@
///
///
+import * as fs from 'fs';
+
require("./editor")
declare namespace pxt.editor {
@@ -9,4 +11,9 @@ declare namespace pxt.editor {
export function deployCoreAsync(resp: pxtc.CompileResult) {
return pxt.editor.deployCoreAsync(resp, process.env["PXT_SERIAL"] ? false : true)
+ .then(() => {
+ fs.writeFileSync("built/full-" + pxtc.BINARY_UF2, resp.outfiles[pxtc.BINARY_UF2], {
+ encoding: "base64"
+ })
+ })
}
diff --git a/editor/extension.ts b/editor/extension.ts
index dd65cf74..e00cd2d4 100644
--- a/editor/extension.ts
+++ b/editor/extension.ts
@@ -7,6 +7,8 @@ namespace pxt {
eval("if (typeof process === 'object' && process + '' === '[object process]') pxt = global.pxt")
namespace pxt.editor {
+ import UF2 = pxtc.UF2;
+
// this comes from aux/pxt.lms
const rbfTemplate = `
4c45474f580000006d000100000000001c000000000000000e000000821b038405018130813e8053
@@ -22,12 +24,15 @@ namespace pxt.editor {
})
}
+ let noHID = false
+
let initPromise: Promise
function initAsync() {
if (!initPromise)
initPromise = hf2Async()
.catch(err => {
initPromise = null
+ noHID = true
return Promise.reject(err)
})
return initPromise
@@ -35,34 +40,73 @@ namespace pxt.editor {
export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
let w: Ev3Wrapper
- let elfPath = "../prjs/BrkProg_SAVE/binary.elf"
- let rbfPath = "../prjs/BrkProg_SAVE/pxt0.rbf"
+
+ let filename = resp.downloadFileBaseName
+
+ let fspath = "../prjs/BrkProg_SAVE/"
+
+ let elfPath = fspath + filename + ".elf"
+ let rbfPath = fspath + filename + ".rbf"
+
+ let rbfHex = rbfTemplate
+ .replace(/\s+/g, "")
+ .replace("XX", U.toHex(U.stringToUint8Array(elfPath)))
+ let rbfBIN = U.fromHex(rbfHex)
+ HF2.write16(rbfBIN, 4, rbfBIN.length)
+
+ let origElfUF2 = UF2.parseFile(U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()])))
+
+ let mkFile = (ext: string, data: Uint8Array = null) => {
+ let f = UF2.newBlockFile()
+ f.filename = "Projects/" + filename + ext
+ if (data)
+ UF2.writeBytes(f, 0, data)
+ return f
+ }
+
+ let elfUF2 = mkFile(".elf")
+ for (let b of origElfUF2) {
+ UF2.writeBytes(elfUF2, b.targetAddr, b.data)
+ }
+
+ let r = UF2.concatFiles([elfUF2, mkFile(".rbf", rbfBIN)])
+ let data = UF2.serializeFile(r)
+
+ resp.outfiles[pxtc.BINARY_UF2] = btoa(data)
+
+ let saveUF2Async = () => {
+ if (isCli || !pxt.commands.saveOnlyAsync) {
+ return Promise.resolve()
+ } else {
+ return pxt.commands.saveOnlyAsync(resp)
+ }
+ }
+
+ if (noHID) return saveUF2Async()
+
return initAsync()
.then(w_ => {
w = w_
if (w.isStreaming)
U.userError("please stop the program first")
return w.stopAsync()
- }).then(() => {
- return w.rmAsync(elfPath)
- }).then(() => {
- let f = U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()]))
- return w.flashAsync(elfPath, f)
- }).then(() => {
- let rbfHex = rbfTemplate
- .replace(/\s+/g, "")
- .replace("XX", U.toHex(U.stringToUint8Array(elfPath)))
- let rbf = U.fromHex(rbfHex)
- HF2.write16(rbf, 4, rbf.length)
- return w.flashAsync(rbfPath, rbf)
- }).then(() => {
- return w.runAsync(rbfPath)
- }).then(() => {
+ })
+ .then(() => w.rmAsync(elfPath))
+ .then(() => w.flashAsync(elfPath, UF2.readBytes(origElfUF2, 0, origElfUF2.length * 256)))
+ .then(() => w.flashAsync(rbfPath, rbfBIN))
+ .then(() => w.runAsync(rbfPath))
+ .then(() => {
if (isCli)
return w.disconnectAsync()
else
return Promise.resolve()
- //return Promise.delay(1000).then(() => w.dmesgAsync())
+ //return Promise.delay(1000).then(() => w.dmesgAsync())
+ }).catch(e => {
+ // if we failed to initalize, retry
+ if (noHID)
+ return saveUF2Async()
+ else
+ return Promise.reject(e)
})
}
diff --git a/pxtarget.json b/pxtarget.json
index 3da4de30..5cc36a87 100644
--- a/pxtarget.json
+++ b/pxtarget.json
@@ -33,6 +33,7 @@
},
"compile": {
"isNative": true,
+ "useUF2": true,
"useELF": true,
"hasHex": true,
"deployDrives": ".*",