in editor/flash.ts [375:438]
private fullVendorCommandFlashAsync(resp: pxtc.CompileResult): Promise<void> {
log("full flash")
pxt.tickEvent("hid.flash.full.start");
const chunkSize = 62;
let sentPages = 0;
return pxt.Util.promiseTimeout(
FULL_FLASH_TIMEOUT,
Promise.resolve()
.then(() => this.dapCmdNums(0x8A /* DAPLinkFlash.OPEN */, 1))
.then((res) => {
log(`daplinkflash open: ${pxt.U.toHex(res)}`)
if (res[1] !== 0) {
pxt.tickEvent('hid.flash.full.error.open', { res: res[1] })
throw new Error(lf("Download failed, please try again"));
}
const binFile = resp.outfiles[this.binName];
log(`bin file ${this.binName} in ${Object.keys(resp.outfiles).join(', ')}, ${binFile?.length || -1}b`)
const hexUint8 = pxt.U.stringToUint8Array(binFile);
log(`hex ${hexUint8?.byteLength || -1}b, ~${(hexUint8.byteLength / chunkSize) | 0} chunks of ${chunkSize}b`)
const sendPages = (offset: number = 0): Promise<void> => {
const end = Math.min(hexUint8.length, offset + chunkSize);
const nextPageData = hexUint8.slice(offset, end);
const cmdData = new Uint8Array(2 + nextPageData.length)
cmdData[0] = 0x8C /* DAPLinkFlash.WRITE */
cmdData[1] = nextPageData.length
cmdData.set(nextPageData, 2)
if (sentPages % 128 == 0) // reduce logging
log(`next page ${sentPages}: [${offset.toString(16)}, ${end.toString(16)}] (${Math.ceil((hexUint8.length - end) / 1000)}kb left)`)
return this.dapCmd(cmdData)
.then(() => {
this.checkAborted()
if (end < hexUint8.length) {
sentPages++;
return sendPages(end);
}
return Promise.resolve()
});
}
return sendPages();
})
.then(() => {
log(`close`)
return this.dapCmdNums(0x8B /* DAPLinkFlash.CLOSE */);
})
.then(res => {
log(`daplinkclose: ${pxt.U.toHex(res)}`)
return this.dapCmdNums(0x89 /* DAPLinkFlash.RESET */);
})
.then((res) => {
log(`daplinkreset: ${pxt.U.toHex(res)}`)
log(`full flash done`);
pxt.tickEvent("hid.flash.full.success");
}),
timeoutMessage
).catch((e) => {
log(`error: abort`)
pxt.tickEvent("hid.flash.full.error");
this.flashAborted = true;
return this.resetAndThrowAsync(e);
});
}