pxt-microbit 5.1.35 → 5.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/built/editor.js CHANGED
@@ -3219,17 +3219,15 @@ class DAPWrapper {
3219
3219
  this.xchgAddr = null;
3220
3220
  this.sendQ = [];
3221
3221
  this.familyID = 0x0D28; // this is the microbit vendor id, not quite UF2 family id
3222
- this.io.onDeviceConnectionChanged = (connect) => {
3222
+ this.io.onDeviceConnectionChanged = async (connect) => {
3223
3223
  log(`device connection changed`);
3224
- this.disconnectAsync()
3225
- .then(() => {
3226
- // we don't know what's being connected
3227
- this.usesCODAL = undefined;
3228
- this.jacdacInHex = undefined;
3229
- if (!connect)
3230
- return;
3231
- this.reconnectAsync();
3232
- });
3224
+ await this.disconnectAsync();
3225
+ // we don't know what's being connected
3226
+ this.usesCODAL = undefined;
3227
+ this.jacdacInHex = undefined;
3228
+ if (!connect)
3229
+ return;
3230
+ await this.reconnectAsync();
3233
3231
  };
3234
3232
  this.io.onData = buf => {
3235
3233
  // console.log("RD: " + pxt.Util.toHex(buf))
@@ -3469,14 +3467,14 @@ class DAPWrapper {
3469
3467
  if (this.flashAborted)
3470
3468
  throw new Error(lf("Download cancelled"));
3471
3469
  }
3472
- disconnectAsync() {
3470
+ async disconnectAsync() {
3473
3471
  log(`disconnect`);
3474
3472
  this.flashAborted = true;
3475
3473
  this.initialized = false;
3476
- return this.stopReadersAsync()
3477
- .then(() => this.io.disconnectAsync());
3474
+ await this.stopReadersAsync();
3475
+ await this.io.disconnectAsync();
3478
3476
  }
3479
- reflashAsync(resp, progressCallback) {
3477
+ async reflashAsync(resp, progressCallback) {
3480
3478
  var _a, _b;
3481
3479
  pxt.tickEvent("hid.flash.start");
3482
3480
  log("reflash");
@@ -3485,32 +3483,34 @@ class DAPWrapper {
3485
3483
  const codalJson = resp.outfiles["codal.json"];
3486
3484
  this.jacdacInHex = codalJson && !!((_b = (_a = pxt.Util.jsonTryParse(codalJson)) === null || _a === void 0 ? void 0 : _a.definitions) === null || _b === void 0 ? void 0 : _b.JACDAC_WEBUSB);
3487
3485
  this.flashAborted = false;
3488
- return (this.io.isConnected() ? Promise.resolve() : this.io.reconnectAsync())
3489
- .then(() => this.stopReadersAsync())
3490
- .then(() => this.cortexM.init())
3491
- .then(() => this.cortexM.reset(true))
3492
- .then(() => this.checkStateAsync())
3493
- .then(() => this.readUICR())
3494
- .then(uicr => {
3495
- pxt.tickEvent("hid.flash.uicr", { uicr });
3496
- // shortcut, do a full flash
3497
- if (uicr != 0 || this.forceFullFlash) {
3498
- pxt.tickEvent("hid.flash.uicrfail");
3499
- return this.fullVendorCommandFlashAsync(resp, progressCallback);
3500
- }
3486
+ if (!this.io.isConnected()) {
3487
+ await this.io.reconnectAsync();
3488
+ }
3489
+ await this.stopReadersAsync();
3490
+ await this.cortexM.init();
3491
+ await this.cortexM.reset(true);
3492
+ await this.checkStateAsync();
3493
+ const uicr = await this.readUICR();
3494
+ pxt.tickEvent("hid.flash.uicr", { uicr });
3495
+ // shortcut, do a full flash
3496
+ if (uicr != 0 || this.forceFullFlash) {
3497
+ pxt.tickEvent("hid.flash.uicrfail");
3498
+ await this.fullVendorCommandFlashAsync(resp, progressCallback);
3499
+ }
3500
+ else {
3501
3501
  // check flash checksums
3502
- return this.computeFlashChecksum(resp)
3503
- .then(chk => {
3504
- pxt.tickEvent("hid.flash.checksum", { quick: chk.quick ? 1 : 0, changed: chk.changed ? chk.changed.length : 0 });
3502
+ const chk = await this.computeFlashChecksum(resp);
3503
+ pxt.tickEvent("hid.flash.checksum", { quick: chk.quick ? 1 : 0, changed: chk.changed ? chk.changed.length : 0 });
3504
+ if (chk.quick) {
3505
3505
  // let's do a quick flash!
3506
- if (chk.quick)
3507
- return this.quickHidFlashAsync(chk.changed, progressCallback);
3508
- else
3509
- return this.fullVendorCommandFlashAsync(resp, progressCallback);
3510
- });
3511
- })
3512
- .then(() => this.checkStateAsync(true))
3513
- .then(() => pxt.tickEvent("hid.flash.success"));
3506
+ await this.quickHidFlashAsync(chk.changed, progressCallback);
3507
+ }
3508
+ else {
3509
+ await this.fullVendorCommandFlashAsync(resp, progressCallback);
3510
+ }
3511
+ }
3512
+ await this.checkStateAsync(true);
3513
+ pxt.tickEvent("hid.flash.success");
3514
3514
  // don't disconnect here
3515
3515
  // the micro:bit will automatically disconnect and reconnect
3516
3516
  // via the webusb events
@@ -3521,117 +3521,108 @@ class DAPWrapper {
3521
3521
  else
3522
3522
  return this.pbuf.shiftAsync();
3523
3523
  }
3524
- dapCmd(buf) {
3525
- return this.io.sendPacketAsync(buf)
3526
- .then(() => this.recvPacketAsync())
3527
- .then(resp => {
3528
- if (resp[0] != buf[0]) {
3529
- pxt.tickEvent('hid.flash.cmderror', { req: buf[0], resp: resp[0] });
3530
- const msg = `bad dapCmd response: ${buf[0]} -> ${resp[0]}`;
3531
- // in case we got an invalid response, try to get another response, in case the current
3532
- // response is a left-over from previous communications
3533
- log(msg + "; retrying");
3534
- return this.recvPacketAsync()
3535
- .then(resp => {
3536
- if (resp[0] == buf[0]) {
3537
- log(msg + "; retry success");
3538
- return resp;
3539
- }
3540
- throw new Error(msg);
3541
- }, err => {
3542
- throw new Error(msg);
3543
- });
3524
+ async dapCmd(buf) {
3525
+ await this.io.sendPacketAsync(buf);
3526
+ const resp = await this.recvPacketAsync();
3527
+ if (resp[0] != buf[0]) {
3528
+ pxt.tickEvent('hid.flash.cmderror', { req: buf[0], resp: resp[0] });
3529
+ const msg = `bad dapCmd response: ${buf[0]} -> ${resp[0]}`;
3530
+ // in case we got an invalid response, try to get another response, in case the current
3531
+ // response is a left-over from previous communications
3532
+ log(msg + "; retrying");
3533
+ try {
3534
+ const secondTryResp = await this.recvPacketAsync();
3535
+ if (secondTryResp[0] === buf[0]) {
3536
+ log(msg + "; retry success");
3537
+ return secondTryResp;
3538
+ }
3544
3539
  }
3545
- return resp;
3546
- });
3540
+ catch (e) {
3541
+ log(e);
3542
+ }
3543
+ throw new Error(`retry failed ${msg}`);
3544
+ }
3545
+ return resp;
3547
3546
  }
3548
3547
  dapCmdNums(...nums) {
3549
3548
  return this.dapCmd(new Uint8Array(nums));
3550
3549
  }
3551
- fullVendorCommandFlashAsync(resp, progressCallback) {
3550
+ async fullVendorCommandFlashAsync(resp, progressCallback) {
3552
3551
  log("full flash");
3553
3552
  pxt.tickEvent("hid.flash.full.start");
3554
3553
  const start = Date.now();
3555
3554
  const chunkSize = 62;
3556
3555
  let sentPages = 0;
3557
- return pxt.Util.promiseTimeout(FULL_FLASH_TIMEOUT, Promise.resolve()
3558
- .then(() => this.dapCmdNums(0x8A /* DAPLinkFlash.OPEN */, 1))
3559
- .then((res) => {
3560
- log(`daplinkflash open: ${pxt.U.toHex(res)}`);
3561
- if (res[1] !== 0) {
3562
- pxt.tickEvent('hid.flash.full.error.open', { res: res[1] });
3563
- throw new Error(lf("Download failed, please try again"));
3564
- }
3565
- const binFile = this.getBinFile(resp);
3566
- log(`bin file ${this.binName} in ${Object.keys(resp.outfiles).join(', ')}, ${(binFile === null || binFile === void 0 ? void 0 : binFile.length) || -1}b`);
3567
- const hexUint8 = pxt.U.stringToUint8Array(binFile);
3568
- log(`hex ${(hexUint8 === null || hexUint8 === void 0 ? void 0 : hexUint8.byteLength) || -1}b, ~${(hexUint8.byteLength / chunkSize) | 0} chunks of ${chunkSize}b`);
3569
- const sendPages = (offset = 0) => {
3570
- const end = Math.min(hexUint8.length, offset + chunkSize);
3571
- const nextPageData = hexUint8.slice(offset, end);
3572
- const cmdData = new Uint8Array(2 + nextPageData.length);
3573
- cmdData[0] = 0x8C; /* DAPLinkFlash.WRITE */
3574
- cmdData[1] = nextPageData.length;
3575
- cmdData.set(nextPageData, 2);
3576
- if (sentPages % 128 == 0) { // reduce logging
3577
- progressCallback(offset / hexUint8.length);
3578
- log(`next page ${sentPages}: [${offset.toString(16)}, ${end.toString(16)}] (${Math.ceil((hexUint8.length - end) / 1000)}kb left)`);
3556
+ try {
3557
+ await pxt.Util.promiseTimeout(FULL_FLASH_TIMEOUT, (async () => {
3558
+ const dapOpenRes = await this.dapCmdNums(0x8A /* DAPLinkFlash.OPEN */, 1);
3559
+ log(`daplinkflash open: ${pxt.U.toHex(dapOpenRes)}`);
3560
+ if (dapOpenRes[1] !== 0) {
3561
+ pxt.tickEvent('hid.flash.full.error.open', { res: dapOpenRes[1] });
3562
+ throw new Error(lf("Download failed, please try again"));
3579
3563
  }
3580
- return this.dapCmd(cmdData)
3581
- .then(() => {
3582
- this.checkAborted();
3583
- if (end < hexUint8.length) {
3584
- sentPages++;
3585
- return sendPages(end);
3564
+ const binFile = this.getBinFile(resp);
3565
+ log(`bin file ${this.binName} in ${Object.keys(resp.outfiles).join(', ')}, ${(binFile === null || binFile === void 0 ? void 0 : binFile.length) || -1}b`);
3566
+ const hexUint8 = pxt.U.stringToUint8Array(binFile);
3567
+ log(`hex ${(hexUint8 === null || hexUint8 === void 0 ? void 0 : hexUint8.byteLength) || -1}b, ~${(hexUint8.byteLength / chunkSize) | 0} chunks of ${chunkSize}b`);
3568
+ let offset = 0;
3569
+ while (offset < hexUint8.length) {
3570
+ const end = Math.min(hexUint8.length, offset + chunkSize);
3571
+ const nextPageData = hexUint8.slice(offset, end);
3572
+ const cmdData = new Uint8Array(2 + nextPageData.length);
3573
+ cmdData[0] = 0x8C; /* DAPLinkFlash.WRITE */
3574
+ cmdData[1] = nextPageData.length;
3575
+ cmdData.set(nextPageData, 2);
3576
+ if (sentPages % 128 == 0) { // reduce logging
3577
+ progressCallback(offset / hexUint8.length);
3578
+ log(`next page ${sentPages}: [${offset.toString(16)}, ${end.toString(16)}] (${Math.ceil((hexUint8.length - end) / 1000)}kb left)`);
3586
3579
  }
3587
- return Promise.resolve();
3588
- });
3589
- };
3590
- return sendPages();
3591
- })
3592
- .then(() => {
3593
- log(`close`);
3594
- return this.dapCmdNums(0x8B /* DAPLinkFlash.CLOSE */);
3595
- })
3596
- .then(res => {
3597
- log(`daplinkclose: ${pxt.U.toHex(res)}`);
3598
- return this.dapCmdNums(0x89 /* DAPLinkFlash.RESET */);
3599
- })
3600
- .then((res) => {
3601
- log(`daplinkreset: ${pxt.U.toHex(res)}`);
3602
- log(`full flash done after ${Date.now() - start}ms`);
3603
- pxt.tickEvent("hid.flash.full.success");
3604
- }), timeoutMessage).catch((e) => {
3580
+ await this.dapCmd(cmdData);
3581
+ this.checkAborted();
3582
+ sentPages++;
3583
+ offset = end;
3584
+ }
3585
+ log("close");
3586
+ const closeRes = await this.dapCmdNums(0x8B /* DAPLinkFlash.CLOSE */);
3587
+ log(`daplinkclose: ${pxt.U.toHex(closeRes)}`);
3588
+ const resetRes = await this.dapCmdNums(0x89 /* DAPLinkFlash.RESET */);
3589
+ log(`daplinkreset: ${pxt.U.toHex(resetRes)}`);
3590
+ log(`full flash done after ${Date.now() - start}ms`);
3591
+ pxt.tickEvent("hid.flash.full.success");
3592
+ })(), timeoutMessage);
3593
+ }
3594
+ catch (e) {
3605
3595
  log(`error: abort`);
3606
3596
  pxt.tickEvent("hid.flash.full.error");
3607
3597
  this.flashAborted = true;
3608
3598
  return this.resetAndThrowAsync(e);
3609
- });
3599
+ }
3600
+ ;
3610
3601
  }
3611
- resetAndThrowAsync(e) {
3602
+ async resetAndThrowAsync(e) {
3612
3603
  log(`reset on error`);
3613
3604
  pxt.tickEvent("hid.flash.reset");
3614
3605
  console.debug(e);
3615
3606
  // reset any pending daplink
3616
- return this.dapCmdNums(0x89 /* DAPLinkFlash.RESET */)
3617
- .catch((e2) => {
3607
+ try {
3608
+ await this.dapCmdNums(0x89 /* DAPLinkFlash.RESET */);
3609
+ }
3610
+ catch (e) {
3618
3611
  // Best effort reset, no-op if there's an error
3619
- })
3620
- .then(() => this.cortexM.reset(false))
3621
- .catch((e2) => {
3612
+ }
3613
+ try {
3614
+ await this.cortexM.reset(false);
3615
+ }
3616
+ catch (e) {
3622
3617
  // Best effort reset, no-op if there's an error
3623
- })
3624
- .then(() => {
3625
- throw e;
3626
- });
3618
+ }
3619
+ throw e;
3627
3620
  }
3628
- readUICR() {
3629
- return this.readWords(0x10001014, 1)
3630
- .then(v => {
3631
- const uicr = v[0] & 0xff;
3632
- log(`uicr: ${uicr.toString(16)} (${v[0].toString(16)})`);
3633
- return uicr;
3634
- });
3621
+ async readUICR() {
3622
+ const v = await this.readWords(0x10001014, 1);
3623
+ const uicr = v[0] & 0xff;
3624
+ log(`uicr: ${uicr.toString(16)} (${v[0].toString(16)})`);
3625
+ return uicr;
3635
3626
  }
3636
3627
  getBinFile(resp) {
3637
3628
  var _a;
@@ -3643,31 +3634,29 @@ class DAPWrapper {
3643
3634
  return resp.outfiles[pxtc.BINARY_HEX];
3644
3635
  throw new Error(`unable to find ${this.binName} in outfiles ${Object.keys(resp.outfiles).join(', ')}`);
3645
3636
  }
3646
- computeFlashChecksum(resp) {
3637
+ async computeFlashChecksum(resp) {
3647
3638
  const binFile = this.getBinFile(resp);
3648
- return this.getFlashChecksumsAsync()
3649
- .then(checksums => {
3650
- log(`checksums ${pxt.Util.toHex(checksums)}`);
3651
- // TODO this is seriously inefficient (130ms on a fast machine)
3652
- const uf2 = ts.pxtc.UF2.newBlockFile();
3653
- ts.pxtc.UF2.writeHex(uf2, binFile.split(/\r?\n/));
3654
- const bytes = pxt.U.stringToUint8Array(ts.pxtc.UF2.serializeFile(uf2));
3655
- const parsed = ts.pxtc.UF2.parseFile(bytes);
3656
- const aligned = DAPWrapper.pageAlignBlocks(parsed, this.pageSize);
3657
- const changed = DAPWrapper.onlyChanged(aligned, checksums, this.pageSize);
3658
- const quick = changed.length < aligned.length / 2;
3659
- log(`pages: ${aligned.length}, changed ${changed.length}, ${quick ? "quick" : "full"}`);
3660
- return {
3661
- quick,
3662
- changed
3663
- };
3664
- });
3639
+ const checksums = await this.getFlashChecksumsAsync();
3640
+ log(`checksums ${pxt.Util.toHex(checksums)}`);
3641
+ // TODO this is seriously inefficient (130ms on a fast machine)
3642
+ const uf2 = ts.pxtc.UF2.newBlockFile();
3643
+ ts.pxtc.UF2.writeHex(uf2, binFile.split(/\r?\n/));
3644
+ const bytes = pxt.U.stringToUint8Array(ts.pxtc.UF2.serializeFile(uf2));
3645
+ const parsed = ts.pxtc.UF2.parseFile(bytes);
3646
+ const aligned = DAPWrapper.pageAlignBlocks(parsed, this.pageSize);
3647
+ const changed = DAPWrapper.onlyChanged(aligned, checksums, this.pageSize);
3648
+ const quick = changed.length < aligned.length / 2;
3649
+ log(`pages: ${aligned.length}, changed ${changed.length}, ${quick ? "quick" : "full"}`);
3650
+ return {
3651
+ quick,
3652
+ changed
3653
+ };
3665
3654
  }
3666
- quickHidFlashAsync(changed, progressCallback) {
3655
+ async quickHidFlashAsync(changed, progressCallback) {
3667
3656
  log("quick flash");
3668
3657
  pxt.tickEvent("hid.flash.quick.start");
3669
3658
  const start = Date.now();
3670
- const runFlash = (b, dataAddr) => {
3659
+ const runFlash = async (b, dataAddr) => {
3671
3660
  const cmd = this.cortexM.prepareCommand();
3672
3661
  cmd.halt();
3673
3662
  cmd.writeCoreRegister(15 /* PC */, loadAddr + 4 + 1);
@@ -3676,85 +3665,73 @@ class DAPWrapper {
3676
3665
  cmd.writeCoreRegister(0, b.targetAddr);
3677
3666
  cmd.writeCoreRegister(1, dataAddr);
3678
3667
  cmd.writeCoreRegister(2, this.pageSize >> 2);
3679
- return Promise.resolve()
3680
- .then(() => {
3681
- logV("setregs");
3682
- return cmd.go();
3683
- })
3684
- .then(() => {
3685
- // starts the program
3686
- logV(`cortex.debug.enable`);
3687
- return this.cortexM.debug.enable();
3688
- });
3668
+ logV("setregs");
3669
+ await cmd.go();
3670
+ // starts the program
3671
+ logV(`cortex.debug.enable`);
3672
+ return this.cortexM.debug.enable();
3689
3673
  };
3690
- return pxt.Util.promiseTimeout(PARTIAL_FLASH_TIMEOUT, Promise.resolve()
3691
- .then(() => this.cortexM.memory.writeBlock(loadAddr, flashPageBIN))
3692
- .then(() => pxt.Util.promiseMapAllSeries(pxt.U.range(changed.length), i => {
3693
- this.checkAborted();
3694
- let b = changed[i];
3695
- if (b.targetAddr >= 0x10000000) {
3696
- log(`target address 0x${b.targetAddr.toString(16)} > 0x10000000`);
3697
- return Promise.resolve();
3698
- }
3699
- log(`about to write at 0x${b.targetAddr.toString(16)}`);
3700
- progressCallback(i / changed.length);
3701
- let writeBl = Promise.resolve();
3702
- let thisAddr = (i & 1) ? dataAddr : dataAddr + this.pageSize;
3703
- let nextAddr = (i & 1) ? dataAddr + this.pageSize : dataAddr;
3704
- if (i == 0) {
3705
- let u32data = new Uint32Array(b.data.length / 4);
3706
- for (let i = 0; i < b.data.length; i += 4)
3707
- u32data[i >> 2] = pxt.HF2.read32(b.data, i);
3708
- writeBl = this.cortexM.memory.writeBlock(thisAddr, u32data);
3709
- }
3710
- return writeBl
3711
- .then(() => runFlash(b, thisAddr))
3712
- .then(() => {
3713
- let next = changed[i + 1];
3714
- if (!next)
3715
- return Promise.resolve();
3716
- logV("write next");
3717
- let buf = new Uint32Array(next.data.buffer);
3718
- return this.cortexM.memory.writeBlock(nextAddr, buf);
3719
- })
3720
- .then(() => {
3674
+ const quickHidFlashCoreAsync = async () => {
3675
+ await this.cortexM.memory.writeBlock(loadAddr, flashPageBIN);
3676
+ for (let i = 0; i < changed.length; i++) {
3677
+ this.checkAborted();
3678
+ let b = changed[i];
3679
+ if (b.targetAddr >= 0x10000000) {
3680
+ log(`target address 0x${b.targetAddr.toString(16)} > 0x10000000`);
3681
+ continue;
3682
+ }
3683
+ log(`about to write at 0x${b.targetAddr.toString(16)}`);
3684
+ progressCallback(i / changed.length);
3685
+ const thisAddr = (i & 1) ? dataAddr : dataAddr + this.pageSize;
3686
+ const nextAddr = (i & 1) ? dataAddr + this.pageSize : dataAddr;
3687
+ if (i == 0) {
3688
+ const u32data = new Uint32Array(b.data.length / 4);
3689
+ for (let i = 0; i < b.data.length; i += 4)
3690
+ u32data[i >> 2] = pxt.HF2.read32(b.data, i);
3691
+ await this.cortexM.memory.writeBlock(thisAddr, u32data);
3692
+ }
3693
+ await runFlash(b, thisAddr);
3694
+ const next = changed[i + 1];
3695
+ if (next) {
3696
+ logV("write next");
3697
+ const buf = new Uint32Array(next.data.buffer);
3698
+ await this.cortexM.memory.writeBlock(nextAddr, buf);
3699
+ }
3721
3700
  logV("wait");
3722
- return this.cortexM.waitForHalt(500);
3723
- })
3724
- .then(() => {
3701
+ await this.cortexM.waitForHalt(500);
3725
3702
  logV("done block");
3726
- });
3727
- }))
3728
- .then(() => {
3703
+ }
3729
3704
  log(`quick flash done after ${Date.now() - start}ms`);
3730
- return this.cortexM.reset(false);
3731
- })
3732
- .then(() => {
3705
+ await this.cortexM.reset(false);
3733
3706
  pxt.tickEvent("hid.flash.quick.success");
3734
- return this.checkStateAsync(true);
3735
- }), timeoutMessage).catch((e) => {
3707
+ await this.checkStateAsync(true);
3708
+ };
3709
+ try {
3710
+ await pxt.Util.promiseTimeout(PARTIAL_FLASH_TIMEOUT, quickHidFlashCoreAsync(), timeoutMessage);
3711
+ }
3712
+ catch (e) {
3736
3713
  pxt.tickEvent("hid.flash.quick.error");
3737
3714
  this.flashAborted = true;
3738
3715
  return this.resetAndThrowAsync(e);
3739
- });
3716
+ }
3740
3717
  }
3741
- getFlashChecksumsAsync() {
3718
+ async getFlashChecksumsAsync() {
3742
3719
  log("flash checksums");
3743
3720
  let pages = this.numPages;
3744
- return this.cortexM.runCode(computeChecksums2, loadAddr, loadAddr + 1, 0xffffffff, stackAddr, true, dataAddr, 0, this.pageSize, pages)
3745
- .then(() => this.cortexM.memory.readBlock(dataAddr, pages * 2, this.pageSize));
3721
+ await this.cortexM.runCode(computeChecksums2, loadAddr, loadAddr + 1, 0xffffffff, stackAddr, true, dataAddr, 0, this.pageSize, pages);
3722
+ return this.cortexM.memory.readBlock(dataAddr, pages * 2, this.pageSize);
3746
3723
  }
3747
- readWords(addr, numWords) {
3748
- return this.cortexM.memory.readBlock(addr, numWords, this.pageSize)
3749
- // assume browser is little-endian
3750
- .then(u8 => new Uint32Array(u8.buffer));
3724
+ async readWords(addr, numWords) {
3725
+ const u8 = await this.cortexM.memory.readBlock(addr, numWords, this.pageSize);
3726
+ // assume browser is little-endian
3727
+ return new Uint32Array(u8.buffer);
3751
3728
  }
3752
3729
  writeWords(addr, buf) {
3753
3730
  return this.cortexM.memory.writeBlock(addr, buf);
3754
3731
  }
3755
- readBytes(addr, numBytes) {
3756
- return this.cortexM.memory.readBlock(addr, (numBytes + 3) >> 2, this.pageSize)
3757
- .then(u8 => u8.length == numBytes ? u8 : u8.slice(0, numBytes));
3732
+ async readBytes(addr, numBytes) {
3733
+ const u8 = await this.cortexM.memory.readBlock(addr, (numBytes + 3) >> 2, this.pageSize);
3734
+ return u8.length == numBytes ? u8 : u8.slice(0, numBytes);
3758
3735
  }
3759
3736
  static onlyChanged(blocks, checksums, pageSize) {
3760
3737
  return blocks.filter(b => {