import { CRC16_CCITT, ZWaveError, ZWaveErrorCodes } from "@zwave-js/core";
import { XModemMessageHeaders } from "@zwave-js/serial";
import { Bytes } from "@zwave-js/shared";
export var BootloaderState;
(function (BootloaderState) {
    BootloaderState[BootloaderState["Menu"] = 0] = "Menu";
    BootloaderState[BootloaderState["UploadingFirmware"] = 1] = "UploadingFirmware";
})(BootloaderState || (BootloaderState = {}));
/** Encapsulates information about the currently active bootloader */
export class Bootloader {
    constructor(writeSerial, version, options) {
        this.writeSerial = writeSerial;
        this.version = version;
        this.options = new Map(options.map((o) => [o.num, o.option]));
        const uploadOption = options.find((o) => o.option === "upload gbl")?.num;
        if (!uploadOption) {
            throw new ZWaveError("The bootloader does not support uploading a GBL file!", ZWaveErrorCodes.Driver_NotSupported);
        }
        this.uploadOption = uploadOption;
        const runOption = options.find((o) => o.option === "run")?.num;
        if (!runOption) {
            throw new ZWaveError("Could not find run option in bootloader menu!", ZWaveErrorCodes.Driver_NotSupported);
        }
        this.runOption = runOption;
    }
    writeSerial;
    state = BootloaderState.Menu;
    version;
    options;
    uploadOption;
    runOption;
    async selectOption(option) {
        if (!this.options.has(option))
            return false;
        await this.writeSerial(Bytes.from(option.toString(), "ascii"));
        return true;
    }
    findOption(predicate) {
        return [...this.options.entries()].find(([, option]) => predicate(option))?.[0];
    }
    async beginUpload() {
        await this.selectOption(this.uploadOption);
    }
    async runApplication() {
        await this.selectOption(this.runOption);
    }
    async uploadFragment(fragmentNumber, data) {
        const command = Bytes.concat([
            Bytes.from([
                XModemMessageHeaders.SOF,
                fragmentNumber & 0xff,
                0xff - (fragmentNumber & 0xff),
            ]),
            data,
            new Bytes(2),
        ]);
        command.writeUInt16BE(CRC16_CCITT(data, 0x0000), command.length - 2);
        await this.writeSerial(command);
    }
    async finishUpload() {
        await this.writeSerial(Bytes.from([XModemMessageHeaders.EOT]));
    }
}
//# sourceMappingURL=Bootloader.js.map