(data, offset, compress = false, progress)
| 739 | this.#baud = baud; |
| 740 | } |
| 741 | async downloadToFlash(data, offset, compress = false, progress) { |
| 742 | const uncompressedByteLength = data.byteLength; |
| 743 | const FLASH_WRITE_SIZE = 16 * 1024; |
| 744 | |
| 745 | if (compress && globalThis.pako) { |
| 746 | data = pako.deflate(data, {level: 9}); |
| 747 | console.log(`Compressed image from ${uncompressedByteLength} to ${data.byteLength} bytes.`); |
| 748 | } |
| 749 | |
| 750 | const cmdOffset = (compress && globalThis.pako) ? (Bootloader.FLASH_DEFL_BEGIN - Bootloader.FLASH_BEGIN) : 0; |
| 751 | |
| 752 | let blocks = Math.ceil(data.byteLength / FLASH_WRITE_SIZE); |
| 753 | const total = blocks; |
| 754 | |
| 755 | let payload = new DataView(new ArrayBuffer(4 * 4)); |
| 756 | payload.setUint32(0, uncompressedByteLength, true); // little-endian |
| 757 | payload.setUint32(4, blocks, true); // little-endian |
| 758 | payload.setUint32(8, FLASH_WRITE_SIZE, true); // little-endian |
| 759 | payload.setUint32(12, offset, true); // little-endian |
| 760 | await this.command(Bootloader.FLASH_BEGIN + cmdOffset, payload.buffer); |
| 761 | let reply = this.parseReply(await this.getReply(), Bootloader.FLASH_BEGIN + cmdOffset); |
| 762 | |
| 763 | let block = 0; |
| 764 | while (blocks--) { |
| 765 | const fragment = data.slice(block * FLASH_WRITE_SIZE, (block + 1) * FLASH_WRITE_SIZE); |
| 766 | payload = new DataView(new ArrayBuffer((4 * 4) + FLASH_WRITE_SIZE)); |
| 767 | payload.setUint32(0, FLASH_WRITE_SIZE, true); // little-endian |
| 768 | payload.setUint32(4, block, true); // little-endian |
| 769 | payload.setUint32(8, 0, true); // little-endian |
| 770 | payload.setUint32(12, 0, true); // little-endian |
| 771 | |
| 772 | if (0 === blocks) { // last block |
| 773 | if (0 === cmdOffset) { |
| 774 | payload = new Uint8Array(payload.buffer); |
| 775 | payload.fill(0xFF, 16, 16 + FLASH_WRITE_SIZE); // pad uncompressed |
| 776 | } |
| 777 | else { |
| 778 | const byteLength = data.byteLength - (block * FLASH_WRITE_SIZE); |
| 779 | payload.setUint32(0, byteLength, true); |
| 780 | payload = new Uint8Array(payload.buffer.slice(0, 16 + byteLength)); // shrink compressed |
| 781 | } |
| 782 | } |
| 783 | else |
| 784 | payload = new Uint8Array(payload.buffer); |
| 785 | payload.set(fragment, 16); |
| 786 | const checksum = this.espChecksum(payload, 16, payload.byteLength); |
| 787 | await this.command(Bootloader.FLASH_DATA + cmdOffset, payload, checksum); |
| 788 | reply = this.parseReply(await this.getReply(Math.floor(1000 + (payload.length / (this.#baud / 10) * 1000))), Bootloader.FLASH_DATA + cmdOffset); |
| 789 | block += 1; |
| 790 | progress(block / total); |
| 791 | } |
| 792 | |
| 793 | payload = new DataView(new ArrayBuffer(1 * 4)); |
| 794 | payload.setUint32(0, 1, true); // little-endian (STAY IN LOADER - DO NOT REBOOT) |
| 795 | |
| 796 | await this.command(Bootloader.FLASH_END + cmdOffset, new Uint8Array(payload.buffer)); |
| 797 | reply = await this.getReply(2000); |
| 798 | reply = this.parseReply(reply, Bootloader.FLASH_END + cmdOffset); |
no test coverage detected