add firmware flash failure reasons

This commit is contained in:
David Lechner
2021-01-21 19:45:24 -06:00
parent 3b31412186
commit a7ae66021b
+249 -3
View File
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020-2021 The Pybricks Authors
import { FirmwareMetadata, FirmwareReaderError } from '@pybricks/firmware';
import { Action } from 'redux';
import { assert } from '../utils';
@@ -12,6 +13,8 @@ export enum FlashFirmwareActionType {
FlashFirmware = 'flashFirmware.action.flashFirmware',
/** Flashing started. */
DidStart = 'flashFirmware.action.didStart',
/** Flashing was not able to start. */
DidFailToStart = 'flashFirmware.action.didFailStart',
/** Firmware flash progress. */
DidProgress = 'flashFirmware.action.didProgress',
/** Flashing finished successfully. */
@@ -20,6 +23,116 @@ export enum FlashFirmwareActionType {
DidFailToFinish = 'flashFirmware.action.didFailToFinish',
}
export enum MetadataProblem {
Missing = 'metadata.missing',
NotSupported = 'metadata.notSupported',
}
export enum HubError {
UnknownCommand = 'hubError.unknownCommand',
EraseFailed = 'hubError.eraseFailed',
InitFailed = 'hubError.initFailed',
CountMismatch = 'hubError.countMismatch',
ChecksumMismatch = 'hubError.checksumMismatch',
}
function isHubError(arg: unknown): arg is HubError {
if (typeof arg !== 'string') {
return false;
}
return Object.keys(HubError).includes(arg);
}
type Reason<T> = {
reason: T;
};
export enum FailToStartReasonType {
/** Connecting to the hub failed. */
FailedToConnect = 'flashFirmware.failToStart.reason.failedToConnect',
/** The is no firmware available that matches the connected hub. */
NoFirmware = 'flashFirmware.failToStart.reason.noFirmware',
/** The provided firmware.zip does not match the connected hub. */
DeviceMismatch = 'flashFirmware.failToStart.reason.deviceMismatch',
/** There was a problem with the zip file. */
ZipError = 'flashFirmware.failToStart.reason.zipError',
/** Metadata property is missing or invalid. */
BadMetadata = 'flashFirmware.failToStart.reason.badMetadata',
/** The main.py file failed to compile. */
FailedToCompile = 'flashFirmware.failToStart.reason.failedToCompile',
/** The combined firmware-base.bin and main.mpy are too big. */
FirmwareSize = 'flashFirmware.failToStart.reason.firmwareSize',
/** An unexpected error occurred. */
Unknown = 'flashFirmware.failToStart.reason.unknown',
}
export type FailToStartReasonFailedToConnect = Reason<FailToStartReasonType.FailedToConnect>;
export type FailToStartReasonNoFirmware = Reason<FailToStartReasonType.NoFirmware>;
export type FailToStartReasonDeviceMismatch = Reason<FailToStartReasonType.DeviceMismatch>;
export type FailToStartReasonZipError = Reason<FailToStartReasonType.ZipError> & {
err: FirmwareReaderError;
};
export type FailToStartReasonBadMetadata = Reason<FailToStartReasonType.BadMetadata> & {
property: keyof FirmwareMetadata;
problem: MetadataProblem;
};
export type FailToStartReasonFirmwareSize = Reason<FailToStartReasonType.FirmwareSize>;
export type FailToStartReasonFailedToCompile = Reason<FailToStartReasonType.FailedToCompile>;
export type FailToStartReasonUnknown = Reason<FailToStartReasonType.Unknown> & {
err: Error;
};
export type FailToStartReason =
| FailToStartReasonFailedToConnect
| FailToStartReasonNoFirmware
| FailToStartReasonDeviceMismatch
| FailToStartReasonZipError
| FailToStartReasonBadMetadata
| FailToStartReasonFirmwareSize
| FailToStartReasonFailedToCompile
| FailToStartReasonUnknown;
export enum FailToFinishReasonType {
/** Waiting for a response from the hub took too long. */
TimedOut = 'flashFirmware.failToFinish.reason.timedOut',
/** Something went wrong with the BLE connection. */
BleError = 'flashFirmware.failToFinish.reason.bleError',
/** The BLE connection was lost before flashing completed. */
Disconnected = 'flashFirmware.failToFinish.reason.disconnected',
/** The hub sent a response indicating a problem. */
HubError = 'flashFirmware.failToFinish.reason.hubError',
/** An unexpected error occurred. */
Unknown = 'flashFirmware.failToFinish.reason.unknown',
}
export type FailToFinishReasonTimedOut = Reason<FailToFinishReasonType.TimedOut>;
export type FailToFinishReasonBleError = Reason<FailToFinishReasonType.BleError>;
export type FailToFinishReasonDisconnected = Reason<FailToFinishReasonType.Disconnected>;
export type FailToFinishReasonHubError = Reason<FailToFinishReasonType.HubError> & {
hubError: HubError;
};
export type FailToFinishReasonUnknown = Reason<FailToFinishReasonType.Unknown> & {
err: Error;
};
export type FailToFinishReason =
| FailToFinishReasonTimedOut
| FailToFinishReasonBleError
| FailToFinishReasonDisconnected
| FailToFinishReasonHubError
| FailToFinishReasonUnknown;
/**
* Action that flashes firmware to a hub.
*/
@@ -47,6 +160,94 @@ export function didStart(): FlashFirmwareDidStartAction {
return { type: FlashFirmwareActionType.DidStart };
}
/** Action that indicates flashing did not start because of an error. */
export type FlashFirmwareDidFailToStartAction = Action<FlashFirmwareActionType.DidFailToStart> & {
reason: FailToStartReason;
};
export function didFailToStart(
reason: FailToStartReasonType.ZipError,
err: FirmwareReaderError,
): FlashFirmwareDidFailToStartAction;
export function didFailToStart(
reason: FailToStartReasonType.BadMetadata,
property: keyof FirmwareMetadata,
problem: MetadataProblem,
): FlashFirmwareDidFailToStartAction;
export function didFailToStart(
reason: FailToStartReasonType.Unknown,
err: Error,
): FlashFirmwareDidFailToStartAction;
export function didFailToStart(
reason: Exclude<
FailToStartReasonType,
| FailToStartReasonType.ZipError
| FailToStartReasonType.BadMetadata
| FailToStartReasonType.Unknown
>,
): FlashFirmwareDidFailToStartAction;
/**
* Action that indicates flashing did not start because of an error.
* @param total The total number of bytes to be flashed.
*/
export function didFailToStart(
reason: FailToStartReasonType,
arg1?: string | Error,
arg2?: MetadataProblem,
): FlashFirmwareDidFailToStartAction {
if (reason === FailToStartReasonType.ZipError) {
// istanbul ignore if: programmer error give wrong arg
if (!(arg1 instanceof FirmwareReaderError)) {
throw new Error('missing or invalid err');
}
return {
type: FlashFirmwareActionType.DidFailToStart,
reason: { reason, err: arg1 },
};
}
if (reason === FailToStartReasonType.BadMetadata) {
// istanbul ignore if: programmer error give wrong arg
if (
arg1 !== 'metadata-version' &&
arg1 !== 'firmware-version' &&
arg1 !== 'device-id' &&
arg1 !== 'checksum-type' &&
arg1 !== 'mpy-abi-version' &&
arg1 !== 'mpy-cross-options' &&
arg1 !== 'user-mpy-offset' &&
arg1 !== 'max-firmware-size'
) {
throw new Error('missing or invalid property');
}
// istanbul ignore if: programmer error give wrong arg
if (arg2 === undefined) {
throw new Error('missing or invalid problem');
}
return {
type: FlashFirmwareActionType.DidFailToStart,
reason: { reason, property: arg1, problem: arg2 },
};
}
if (reason === FailToStartReasonType.Unknown) {
// istanbul ignore if: programmer error give wrong arg
if (!(arg1 instanceof Error)) {
throw new Error('missing or invalid err');
}
return {
type: FlashFirmwareActionType.DidFailToStart,
reason: { reason, err: arg1 },
};
}
return { type: FlashFirmwareActionType.DidFailToStart, reason: { reason } };
}
/** Action that indicates current firmware flashing progress. */
export type FlashFirmwareDidProgressAction = Action<FlashFirmwareActionType.DidProgress> & {
/** The current progress (0 to 1). */
@@ -71,11 +272,55 @@ export function didFinish(): FlashFirmwareDidFinishAction {
}
/** Action that indicates that flashing failed. */
export type FlashFirmwareDidFailToFinishAction = Action<FlashFirmwareActionType.DidFailToFinish>;
export type FlashFirmwareDidFailToFinishAction = Action<FlashFirmwareActionType.DidFailToFinish> & {
reason: FailToFinishReason;
};
export function didFailToFinish(
reason: FailToFinishReasonType.HubError,
hubError: HubError,
): FlashFirmwareDidFailToFinishAction;
export function didFailToFinish(
reason: FailToFinishReasonType.Unknown,
err: Error,
): FlashFirmwareDidFailToFinishAction;
export function didFailToFinish(
reason: Exclude<
FailToFinishReasonType,
FailToFinishReasonType.HubError | FailToFinishReasonType.Unknown
>,
): FlashFirmwareDidFailToFinishAction;
/** Action that indicates that flashing failed. */
export function didFailToFinish(): FlashFirmwareDidFailToFinishAction {
return { type: FlashFirmwareActionType.DidFailToFinish };
export function didFailToFinish(
reason: FailToFinishReasonType,
arg1?: HubError | Error,
): FlashFirmwareDidFailToFinishAction {
if (reason === FailToFinishReasonType.HubError) {
// istanbul ignore if: programmer error give wrong arg
if (!isHubError(arg1)) {
throw new Error('missing or invalid err');
}
return {
type: FlashFirmwareActionType.DidFailToFinish,
reason: { reason, hubError: arg1 },
};
}
if (reason === FailToFinishReasonType.Unknown) {
// istanbul ignore if: programmer error give wrong arg
if (!(arg1 instanceof Error)) {
throw new Error('missing or invalid err');
}
return {
type: FlashFirmwareActionType.DidFailToFinish,
reason: { reason, err: arg1 },
};
}
return { type: FlashFirmwareActionType.DidFailToFinish, reason: { reason } };
}
/**
@@ -84,6 +329,7 @@ export function didFailToFinish(): FlashFirmwareDidFailToFinishAction {
export type FlashFirmwareAction =
| FlashFirmwareFlashAction
| FlashFirmwareDidStartAction
| FlashFirmwareDidFailToStartAction
| FlashFirmwareDidProgressAction
| FlashFirmwareDidFinishAction
| FlashFirmwareDidFailToFinishAction;