|
| 1 | +import { readFileSync } from 'fs'; |
| 2 | +import { basename, resolve, dirname } from 'path'; |
| 3 | +import { type APIClient } from './APIClient.js'; |
| 4 | +import { type IESP32FlasherJSON } from './esp32.js'; |
| 5 | + |
| 6 | +interface IFirmwarePiece { |
| 7 | + offset: number; |
| 8 | + data: ArrayBuffer; |
| 9 | +} |
| 10 | + |
| 11 | +const MAX_FIRMWARE_SIZE = 4 * 1024 * 1024; |
| 12 | + |
| 13 | +export async function uploadESP32Firmware(client: APIClient, firmwarePath: string) { |
| 14 | + const flasherArgs = JSON.parse(readFileSync(firmwarePath, 'utf-8')) as IESP32FlasherJSON; |
| 15 | + if (!('flash_files' in flasherArgs)) { |
| 16 | + throw new Error('flash_files is not defined in flasher_args.json'); |
| 17 | + } |
| 18 | + |
| 19 | + const firmwareParts: IFirmwarePiece[] = []; |
| 20 | + let firmwareSize = 0; |
| 21 | + for (const [offset, file] of Object.entries(flasherArgs.flash_files)) { |
| 22 | + const offsetNum = parseInt(offset, 16); |
| 23 | + if (isNaN(offsetNum)) { |
| 24 | + throw new Error(`Invalid offset in flasher_args.json flash_files: ${offset}`); |
| 25 | + } |
| 26 | + |
| 27 | + const data = readFileSync(resolve(dirname(firmwarePath), file)); |
| 28 | + firmwareParts.push({ offset: offsetNum, data }); |
| 29 | + firmwareSize = Math.max(firmwareSize, offsetNum + data.byteLength); |
| 30 | + } |
| 31 | + |
| 32 | + if (firmwareSize > MAX_FIRMWARE_SIZE) { |
| 33 | + throw new Error( |
| 34 | + `Firmware size (${firmwareSize} bytes) exceeds the maximum supported size (${MAX_FIRMWARE_SIZE} bytes)`, |
| 35 | + ); |
| 36 | + } |
| 37 | + |
| 38 | + const firmwareData = new Uint8Array(firmwareSize); |
| 39 | + for (const { offset, data } of firmwareParts) { |
| 40 | + firmwareData.set(new Uint8Array(data), offset); |
| 41 | + } |
| 42 | + await client.fileUpload('firmware.bin', firmwareData); |
| 43 | + |
| 44 | + return 'firmware.bin'; |
| 45 | +} |
| 46 | + |
| 47 | +export async function uploadFirmware(client: APIClient, firmwarePath: string) { |
| 48 | + if (basename(firmwarePath) === 'flasher_args.json') { |
| 49 | + return await uploadESP32Firmware(client, firmwarePath); |
| 50 | + } |
| 51 | + |
| 52 | + const extension = firmwarePath.split('.').pop(); |
| 53 | + const firmwareName = `firmware.${extension}`; |
| 54 | + await client.fileUpload(firmwareName, readFileSync(firmwarePath)); |
| 55 | + return firmwareName; |
| 56 | +} |
0 commit comments