@nordicsemiconductor/pc-nrfconnect-shared 120.0.0 → 122.0.0
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/Changelog.md +48 -0
- package/coverage/cobertura-coverage.xml +1358 -1215
- package/nrfutil/device/__mocks__/device.ts +2 -0
- package/nrfutil/device/batch.ts +18 -2
- package/nrfutil/device/common.ts +17 -38
- package/nrfutil/device/device.ts +2 -0
- package/nrfutil/device/deviceInfo.ts +70 -0
- package/nrfutil/device/erase.ts +2 -2
- package/nrfutil/device/firmwareRead.ts +2 -2
- package/nrfutil/device/getCoreInfo.ts +2 -2
- package/nrfutil/device/getFwInfo.ts +2 -2
- package/nrfutil/device/getProtectionStatus.ts +2 -2
- package/nrfutil/device/list.ts +4 -30
- package/nrfutil/device/program.ts +4 -4
- package/nrfutil/device/recover.ts +2 -2
- package/nrfutil/device/reset.ts +2 -2
- package/nrfutil/device/setMcuState.ts +2 -5
- package/nrfutil/device/setProtectionStatus.ts +2 -2
- package/nrfutil/index.ts +1 -1
- package/nrfutil/moduleVersion.ts +20 -0
- package/nrfutil/sandboxTypes.ts +14 -0
- package/package.json +1 -1
- package/src/About/DeviceCard.tsx +6 -5
- package/src/About/SupportCard.tsx +2 -2
- package/src/App/shared.scss +0 -1
- package/src/Device/DeviceSelector/BasicDeviceInfo.tsx +12 -6
- package/src/Device/DeviceSelector/DeviceList/AnimatedList.tsx +1 -1
- package/src/Device/DeviceSelector/DeviceList/Device.tsx +7 -5
- package/src/Device/DeviceSelector/DeviceList/DeviceList.tsx +23 -5
- package/src/Device/DeviceSelector/DeviceList/EditDeviceButtons.tsx +7 -6
- package/src/Device/DeviceSelector/DeviceList/MoreDeviceInfo.tsx +26 -30
- package/src/Device/DeviceSelector/DeviceList/edit-device-buttons.scss +1 -2
- package/src/Device/DeviceSelector/DeviceSelector.test.tsx +26 -46
- package/src/Device/DeviceSelector/DeviceSelector.tsx +40 -15
- package/src/Device/DeviceSelector/Favorite.tsx +10 -10
- package/src/Device/DeviceSelector/basic-device-info.scss +0 -12
- package/src/Device/deviceInfo/deviceInfo.ts +2 -2
- package/src/Device/deviceLister.ts +59 -50
- package/src/Device/deviceSetup.ts +28 -10
- package/src/Device/deviceSlice.ts +148 -84
- package/src/Device/jprogOperations.ts +56 -27
- package/src/Device/sdfuOperations.ts +25 -31
- package/src/Dropdown/Dropdown.tsx +2 -2
- package/src/InlineInput/InlineInput.tsx +25 -3
- package/src/InlineInput/NumberInlineInput.tsx +24 -8
- package/src/InlineInput/NumberInputWithDropdown.tsx +131 -0
- package/src/index.ts +3 -0
- package/src/logging/sendInitialLogMessages.ts +13 -9
- package/src/utils/logLibVersions.ts +1 -1
- package/src/utils/systemReport.ts +3 -3
- package/typings/generated/nrfutil/device/__mocks__/device.d.ts +1 -0
- package/typings/generated/nrfutil/device/__mocks__/device.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/batch.d.ts +3 -2
- package/typings/generated/nrfutil/device/batch.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/common.d.ts +6 -33
- package/typings/generated/nrfutil/device/common.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/device.d.ts +13 -12
- package/typings/generated/nrfutil/device/device.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/deviceInfo.d.ts +40 -0
- package/typings/generated/nrfutil/device/deviceInfo.d.ts.map +1 -0
- package/typings/generated/nrfutil/device/erase.d.ts +2 -2
- package/typings/generated/nrfutil/device/erase.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/firmwareRead.d.ts +2 -2
- package/typings/generated/nrfutil/device/firmwareRead.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/getCoreInfo.d.ts +2 -2
- package/typings/generated/nrfutil/device/getCoreInfo.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/getFwInfo.d.ts +2 -2
- package/typings/generated/nrfutil/device/getFwInfo.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/getProtectionStatus.d.ts +2 -2
- package/typings/generated/nrfutil/device/getProtectionStatus.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/list.d.ts +3 -3
- package/typings/generated/nrfutil/device/list.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/program.d.ts +2 -2
- package/typings/generated/nrfutil/device/program.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/recover.d.ts +2 -2
- package/typings/generated/nrfutil/device/recover.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/reset.d.ts +2 -2
- package/typings/generated/nrfutil/device/reset.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/setMcuState.d.ts +2 -2
- package/typings/generated/nrfutil/device/setMcuState.d.ts.map +1 -1
- package/typings/generated/nrfutil/device/setProtectionStatus.d.ts +2 -2
- package/typings/generated/nrfutil/device/setProtectionStatus.d.ts.map +1 -1
- package/typings/generated/nrfutil/index.d.ts +2 -1
- package/typings/generated/nrfutil/index.d.ts.map +1 -1
- package/typings/generated/nrfutil/moduleVersion.d.ts +4 -0
- package/typings/generated/nrfutil/moduleVersion.d.ts.map +1 -1
- package/typings/generated/nrfutil/sandboxTypes.d.ts +9 -0
- package/typings/generated/nrfutil/sandboxTypes.d.ts.map +1 -1
- package/typings/generated/src/About/DeviceCard.d.ts.map +1 -1
- package/typings/generated/src/Device/DeviceSelector/BasicDeviceInfo.d.ts.map +1 -1
- package/typings/generated/src/Device/DeviceSelector/DeviceList/Device.d.ts +0 -1
- package/typings/generated/src/Device/DeviceSelector/DeviceList/Device.d.ts.map +1 -1
- package/typings/generated/src/Device/DeviceSelector/DeviceList/DeviceList.d.ts.map +1 -1
- package/typings/generated/src/Device/DeviceSelector/DeviceList/EditDeviceButtons.d.ts.map +1 -1
- package/typings/generated/src/Device/DeviceSelector/DeviceList/MoreDeviceInfo.d.ts +0 -1
- package/typings/generated/src/Device/DeviceSelector/DeviceList/MoreDeviceInfo.d.ts.map +1 -1
- package/typings/generated/src/Device/DeviceSelector/DeviceSelector.d.ts.map +1 -1
- package/typings/generated/src/Device/DeviceSelector/Favorite.d.ts +0 -1
- package/typings/generated/src/Device/DeviceSelector/Favorite.d.ts.map +1 -1
- package/typings/generated/src/Device/deviceLister.d.ts +1 -15
- package/typings/generated/src/Device/deviceLister.d.ts.map +1 -1
- package/typings/generated/src/Device/deviceSetup.d.ts +6 -5
- package/typings/generated/src/Device/deviceSetup.d.ts.map +1 -1
- package/typings/generated/src/Device/deviceSlice.d.ts +12 -15
- package/typings/generated/src/Device/deviceSlice.d.ts.map +1 -1
- package/typings/generated/src/Device/jprogOperations.d.ts.map +1 -1
- package/typings/generated/src/Device/sdfuOperations.d.ts.map +1 -1
- package/typings/generated/src/Dropdown/Dropdown.d.ts +2 -2
- package/typings/generated/src/Dropdown/Dropdown.d.ts.map +1 -1
- package/typings/generated/src/InlineInput/InlineInput.d.ts +3 -0
- package/typings/generated/src/InlineInput/InlineInput.d.ts.map +1 -1
- package/typings/generated/src/InlineInput/NumberInlineInput.d.ts +8 -4
- package/typings/generated/src/InlineInput/NumberInlineInput.d.ts.map +1 -1
- package/typings/generated/src/InlineInput/NumberInputWithDropdown.d.ts +19 -0
- package/typings/generated/src/InlineInput/NumberInputWithDropdown.d.ts.map +1 -0
- package/typings/generated/src/index.d.ts +3 -1
- package/typings/generated/src/index.d.ts.map +1 -1
- package/typings/generated/src/logging/sendInitialLogMessages.d.ts.map +1 -1
- package/typings/generated/src/utils/systemReport.d.ts +1 -1
- package/typings/generated/src/utils/systemReport.d.ts.map +1 -1
- package/src/Device/DeviceSelector/DeviceList/device.scss +0 -28
- package/src/Device/DeviceSelector/DeviceList/more-device-info.scss +0 -33
- package/src/Device/DeviceSelector/favorite.scss +0 -17
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import NrfutilDeviceLib from '../../nrfutil/device/device';
|
|
8
|
+
import { DeviceInfo } from '../../nrfutil/device/deviceInfo';
|
|
8
9
|
import { FWInfo } from '../../nrfutil/device/getFwInfo';
|
|
9
10
|
import logger from '../logging';
|
|
10
11
|
import type { AppThunk, RootState } from '../store';
|
|
@@ -18,14 +19,15 @@ const getDeviceReadProtection = async (
|
|
|
18
19
|
readbackProtection: 'unknown' | 'protected' | 'unprotected';
|
|
19
20
|
}> => {
|
|
20
21
|
try {
|
|
22
|
+
logger.info('Checking readback protection on device');
|
|
21
23
|
const info = await NrfutilDeviceLib.getFwInfo(device);
|
|
22
24
|
return {
|
|
23
25
|
fwInfo: info,
|
|
24
26
|
readbackProtection: 'unprotected',
|
|
25
27
|
};
|
|
26
|
-
} catch (
|
|
27
|
-
|
|
28
|
-
if (error.
|
|
28
|
+
} catch (e) {
|
|
29
|
+
const error = e as Error;
|
|
30
|
+
if (error.message.includes('NotAvailableBecauseProtection')) {
|
|
29
31
|
logger.warn(
|
|
30
32
|
'Readback protection on device enabled. Unable to verify that the firmware version is correct.'
|
|
31
33
|
);
|
|
@@ -49,29 +51,50 @@ const programDeviceWithFw =
|
|
|
49
51
|
): AppThunk<RootState, Promise<Device>> =>
|
|
50
52
|
async (dispatch, getState) => {
|
|
51
53
|
try {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
const batch = NrfutilDeviceLib.batch();
|
|
55
|
+
if (getState().device.readbackProtection !== 'unprotected') {
|
|
56
|
+
batch.recover('Application', {
|
|
57
|
+
onTaskBegin: () =>
|
|
58
|
+
logger.info(`Device protected, recovering device`),
|
|
59
|
+
onTaskEnd: () => logger.info(`Finished recovering device.`),
|
|
60
|
+
onException: () =>
|
|
61
|
+
logger.error(`Failed to recover device.`),
|
|
62
|
+
onProgress: progress => {
|
|
63
|
+
onProgress(
|
|
64
|
+
progress.totalProgressPercentage,
|
|
65
|
+
'Recovering device'
|
|
66
|
+
);
|
|
67
|
+
},
|
|
68
|
+
});
|
|
56
69
|
}
|
|
57
70
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
selectedFw.fw,
|
|
64
|
-
progress => {
|
|
71
|
+
batch.program(selectedFw.fw, 'Application', undefined, undefined, {
|
|
72
|
+
onTaskBegin: () => logger.info(`Programming device`),
|
|
73
|
+
onTaskEnd: () => logger.info(`Finished programming device.`),
|
|
74
|
+
onException: () => logger.error(`Failed to program device.`),
|
|
75
|
+
onProgress: progress => {
|
|
65
76
|
onProgress(
|
|
66
77
|
progress.totalProgressPercentage,
|
|
67
78
|
progress.message ?? 'programming'
|
|
68
79
|
);
|
|
69
80
|
},
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
batch.reset('Application', undefined, {
|
|
84
|
+
onTaskBegin: () => logger.info(`Resting device`),
|
|
85
|
+
onTaskEnd: () => logger.info(`Finished resting device.`),
|
|
86
|
+
onException: () => logger.error(`Failed to reset device.`),
|
|
87
|
+
onProgress: progress => {
|
|
88
|
+
onProgress(
|
|
89
|
+
progress.totalProgressPercentage,
|
|
90
|
+
'Resetting device'
|
|
91
|
+
);
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
await batch.run(device);
|
|
74
96
|
await NrfutilDeviceLib.reset(device);
|
|
97
|
+
onProgress(0, 'Updating readback protection');
|
|
75
98
|
const { readbackProtection } = await getDeviceReadProtection(
|
|
76
99
|
device
|
|
77
100
|
);
|
|
@@ -88,12 +111,18 @@ const programDeviceWithFw =
|
|
|
88
111
|
return device;
|
|
89
112
|
};
|
|
90
113
|
|
|
91
|
-
const firmwareOptions = (
|
|
114
|
+
const firmwareOptions = (
|
|
115
|
+
device: Device,
|
|
116
|
+
firmware: JprogEntry[],
|
|
117
|
+
deviceInfo?: DeviceInfo
|
|
118
|
+
) =>
|
|
92
119
|
firmware.filter(fw => {
|
|
93
|
-
const family = (device.
|
|
94
|
-
const deviceType = (
|
|
120
|
+
const family = (device.devkit?.deviceFamily || '').toLowerCase();
|
|
121
|
+
const deviceType = (
|
|
122
|
+
deviceInfo?.jlink?.deviceVersion || ''
|
|
123
|
+
).toLowerCase();
|
|
95
124
|
const shortDeviceType = deviceType.split('_').shift();
|
|
96
|
-
const boardVersion = (device.
|
|
125
|
+
const boardVersion = (device.devkit?.boardVersion || '').toLowerCase();
|
|
97
126
|
|
|
98
127
|
const key = fw.key.toLowerCase();
|
|
99
128
|
return (
|
|
@@ -108,11 +137,11 @@ export const jprogDeviceSetup = (
|
|
|
108
137
|
firmware: JprogEntry[],
|
|
109
138
|
needSerialport = false
|
|
110
139
|
): DeviceSetup => ({
|
|
111
|
-
supportsProgrammingMode:
|
|
140
|
+
supportsProgrammingMode: device =>
|
|
112
141
|
(needSerialport === !!device.traits.serialPorts || !needSerialport) &&
|
|
113
142
|
!!device.traits.jlink,
|
|
114
|
-
getFirmwareOptions: device =>
|
|
115
|
-
firmwareOptions(device, firmware).map(firmwareOption => ({
|
|
143
|
+
getFirmwareOptions: (device, deviceInfo) =>
|
|
144
|
+
firmwareOptions(device, firmware, deviceInfo).map(firmwareOption => ({
|
|
116
145
|
key: firmwareOption.key,
|
|
117
146
|
description: firmwareOption.description,
|
|
118
147
|
programDevice: onProgress => dispatch =>
|
|
@@ -120,8 +149,8 @@ export const jprogDeviceSetup = (
|
|
|
120
149
|
programDeviceWithFw(device, firmwareOption, onProgress)
|
|
121
150
|
),
|
|
122
151
|
})),
|
|
123
|
-
isExpectedFirmware: (device
|
|
124
|
-
const fwVersions = firmwareOptions(device, firmware);
|
|
152
|
+
isExpectedFirmware: (device, deviceInfo) => dispatch => {
|
|
153
|
+
const fwVersions = firmwareOptions(device, firmware, deviceInfo);
|
|
125
154
|
if (fwVersions.length === 0) {
|
|
126
155
|
return Promise.resolve({
|
|
127
156
|
device,
|
|
@@ -46,8 +46,9 @@ export const isDeviceInDFUBootloader = (device: Device) => {
|
|
|
46
46
|
d.idProduct === NORDIC_DFU_PRODUCT_ID
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
|
|
50
|
+
if (device.serialPorts && device.serialPorts[0]) {
|
|
51
|
+
const { vendorId, productId } = device.serialPorts[0];
|
|
51
52
|
return vendorId === '1915' && productId?.toUpperCase() === '521F';
|
|
52
53
|
}
|
|
53
54
|
return false;
|
|
@@ -410,9 +411,7 @@ const programInDFUBootloader =
|
|
|
410
411
|
onFail: (reason?: unknown) => void
|
|
411
412
|
): AppThunk<RootState, Promise<void>> =>
|
|
412
413
|
async dispatch => {
|
|
413
|
-
logger.debug(
|
|
414
|
-
`${device.serialNumber} on ${device.serialport?.comName} is now in DFU-Bootloader...`
|
|
415
|
-
);
|
|
414
|
+
logger.debug(`${device.serialNumber} on is now in DFU-Bootloader...`);
|
|
416
415
|
const { application, softdevice } = dfu;
|
|
417
416
|
const params: Partial<InitPacket> = dfu.params || {};
|
|
418
417
|
|
|
@@ -545,9 +544,9 @@ export const sdfuDeviceSetup = (
|
|
|
545
544
|
dfuFirmware: DfuEntry[],
|
|
546
545
|
needSerialport = false
|
|
547
546
|
): DeviceSetup => ({
|
|
548
|
-
supportsProgrammingMode: (device
|
|
549
|
-
((!!
|
|
550
|
-
|
|
547
|
+
supportsProgrammingMode: (device, deviceInfo) =>
|
|
548
|
+
((!!deviceInfo?.dfuTriggerVersion &&
|
|
549
|
+
deviceInfo.dfuTriggerVersion.semVer.length > 0) ||
|
|
551
550
|
isDeviceInDFUBootloader(device)) &&
|
|
552
551
|
(needSerialport === device.traits.serialPorts || !needSerialport),
|
|
553
552
|
getFirmwareOptions: device =>
|
|
@@ -559,31 +558,26 @@ export const sdfuDeviceSetup = (
|
|
|
559
558
|
programDeviceWithFw(device, firmwareOption, onProgress)
|
|
560
559
|
),
|
|
561
560
|
})),
|
|
562
|
-
isExpectedFirmware: (device
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (device.dfuTriggerVersion) {
|
|
568
|
-
logger.debug(
|
|
569
|
-
'Device has DFU trigger interface, the device is in Application mode'
|
|
570
|
-
);
|
|
561
|
+
isExpectedFirmware: (device, deviceInfo) => () => {
|
|
562
|
+
if (deviceInfo?.dfuTriggerVersion) {
|
|
563
|
+
logger.debug(
|
|
564
|
+
'Device has DFU trigger interface, the device is in Application mode'
|
|
565
|
+
);
|
|
571
566
|
|
|
572
|
-
|
|
567
|
+
const { semVer } = deviceInfo.dfuTriggerVersion;
|
|
573
568
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
}),
|
|
569
|
+
return Promise.resolve({
|
|
570
|
+
device,
|
|
571
|
+
validFirmware:
|
|
572
|
+
dfuFirmware.filter(fw => fw.semver === semVer).length > 0,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return Promise.resolve({
|
|
577
|
+
device,
|
|
578
|
+
validFirmware: false,
|
|
579
|
+
});
|
|
580
|
+
},
|
|
587
581
|
tryToSwitchToApplicationMode: device => dispatch =>
|
|
588
582
|
new Promise<Device>((resolve, reject) => {
|
|
589
583
|
dispatch(switchToApplicationMode(device, resolve, reject));
|
|
@@ -11,9 +11,9 @@ import classNames from '../utils/classNames';
|
|
|
11
11
|
|
|
12
12
|
import styles from './Dropdown.module.scss';
|
|
13
13
|
|
|
14
|
-
export interface DropdownItem {
|
|
14
|
+
export interface DropdownItem<T = string> {
|
|
15
15
|
label: React.ReactNode;
|
|
16
|
-
value:
|
|
16
|
+
value: T;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export interface DropdownProps {
|
|
@@ -57,6 +57,9 @@ interface Props {
|
|
|
57
57
|
onKeyboardIncrementAction?: () => string;
|
|
58
58
|
onKeyboardDecrementAction?: () => string;
|
|
59
59
|
className?: string;
|
|
60
|
+
textAlignLeft?: boolean;
|
|
61
|
+
onValidityChanged?: (validity: boolean) => void;
|
|
62
|
+
preventDefaultInvalidStyle?: boolean;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
const InlineInput = React.forwardRef<HTMLInputElement, Props>(
|
|
@@ -70,19 +73,28 @@ const InlineInput = React.forwardRef<HTMLInputElement, Props>(
|
|
|
70
73
|
onKeyboardIncrementAction = () => externalValue,
|
|
71
74
|
onKeyboardDecrementAction = () => externalValue,
|
|
72
75
|
className = '',
|
|
76
|
+
textAlignLeft = false,
|
|
77
|
+
onValidityChanged,
|
|
78
|
+
preventDefaultInvalidStyle,
|
|
73
79
|
},
|
|
74
80
|
ref
|
|
75
81
|
) => {
|
|
76
82
|
const [internalValue, setInternalValue] = useState(externalValue);
|
|
77
83
|
const [initialValue, setInitialValue] = useState(externalValue);
|
|
78
84
|
useSynchronisationIfChangedFromOutside(externalValue, setInternalValue);
|
|
85
|
+
|
|
79
86
|
const onChangeIfValid = (newValue: string) => {
|
|
80
87
|
if (disabled) {
|
|
81
88
|
return;
|
|
82
89
|
}
|
|
83
90
|
|
|
91
|
+
const validity = isValid(newValue);
|
|
92
|
+
if (onValidityChanged != null) {
|
|
93
|
+
onValidityChanged(validity);
|
|
94
|
+
}
|
|
95
|
+
|
|
84
96
|
setInternalValue(newValue);
|
|
85
|
-
if (
|
|
97
|
+
if (validity) {
|
|
86
98
|
if (externalValue !== newValue) {
|
|
87
99
|
onChange(newValue);
|
|
88
100
|
}
|
|
@@ -94,7 +106,9 @@ const InlineInput = React.forwardRef<HTMLInputElement, Props>(
|
|
|
94
106
|
return;
|
|
95
107
|
}
|
|
96
108
|
|
|
97
|
-
|
|
109
|
+
const validity = isValid(internalValue);
|
|
110
|
+
|
|
111
|
+
if (validity) {
|
|
98
112
|
if (initialValue !== internalValue) {
|
|
99
113
|
setInitialValue(internalValue);
|
|
100
114
|
onChangeComplete(internalValue);
|
|
@@ -102,6 +116,11 @@ const InlineInput = React.forwardRef<HTMLInputElement, Props>(
|
|
|
102
116
|
} else {
|
|
103
117
|
setInternalValue(externalValue);
|
|
104
118
|
}
|
|
119
|
+
|
|
120
|
+
// Should always end up valid in this case
|
|
121
|
+
if (onValidityChanged != null) {
|
|
122
|
+
onValidityChanged(true);
|
|
123
|
+
}
|
|
105
124
|
};
|
|
106
125
|
|
|
107
126
|
const onChangeCompleteIfValid = (event: React.KeyboardEvent) => {
|
|
@@ -144,8 +163,11 @@ const InlineInput = React.forwardRef<HTMLInputElement, Props>(
|
|
|
144
163
|
type="text"
|
|
145
164
|
className={classNames(
|
|
146
165
|
'inline-input',
|
|
147
|
-
|
|
166
|
+
preventDefaultInvalidStyle
|
|
167
|
+
? null
|
|
168
|
+
: isValid(internalValue) || 'invalid',
|
|
148
169
|
disabled && 'disabled',
|
|
170
|
+
textAlignLeft && 'tw-pl-2 tw-text-left',
|
|
149
171
|
className
|
|
150
172
|
)}
|
|
151
173
|
size={
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React
|
|
7
|
+
import React from 'react';
|
|
8
8
|
|
|
9
9
|
import { isFactor } from '../Slider/factor';
|
|
10
10
|
import {
|
|
@@ -19,12 +19,16 @@ import InlineInput from './InlineInput';
|
|
|
19
19
|
|
|
20
20
|
import './number-inline-input.scss';
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
interface NumberInlineInput {
|
|
23
23
|
disabled?: boolean;
|
|
24
24
|
value: number;
|
|
25
25
|
range: RangeOrValues;
|
|
26
|
+
className?: string;
|
|
26
27
|
onChange: (value: number) => void;
|
|
27
28
|
onChangeComplete?: (value: number) => void;
|
|
29
|
+
textAlignLeft?: boolean;
|
|
30
|
+
onValidityChanged?: (validity: boolean) => void;
|
|
31
|
+
preventDefaultInvalidStyle?: boolean;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
const isInValues = (value: number, values: Values) => values.includes(value);
|
|
@@ -77,21 +81,24 @@ const changeValueStepwise = (
|
|
|
77
81
|
return nextValue != null ? nextValue : current;
|
|
78
82
|
};
|
|
79
83
|
|
|
80
|
-
|
|
84
|
+
export default ({
|
|
81
85
|
disabled,
|
|
82
86
|
value,
|
|
83
87
|
range,
|
|
88
|
+
className,
|
|
84
89
|
onChange,
|
|
85
90
|
onChangeComplete = () => {},
|
|
86
|
-
|
|
91
|
+
textAlignLeft,
|
|
92
|
+
onValidityChanged,
|
|
93
|
+
preventDefaultInvalidStyle,
|
|
94
|
+
}: NumberInlineInput) => {
|
|
87
95
|
useValidatedRangeOrValues(range);
|
|
88
96
|
|
|
89
97
|
return (
|
|
90
98
|
<InlineInput
|
|
91
|
-
className=
|
|
99
|
+
className={`${className} number-inline-input`}
|
|
92
100
|
disabled={disabled}
|
|
93
101
|
value={String(value)}
|
|
94
|
-
isValid={newValue => isValid(Number(newValue), range)}
|
|
95
102
|
onChange={newValue => onChange(Number(newValue))}
|
|
96
103
|
onChangeComplete={newValue => onChangeComplete(Number(newValue))}
|
|
97
104
|
onKeyboardIncrementAction={() =>
|
|
@@ -100,8 +107,17 @@ const NumberInlineInput: FC<Props> = ({
|
|
|
100
107
|
onKeyboardDecrementAction={() =>
|
|
101
108
|
changeValueStepwise(value, range, -1).toString()
|
|
102
109
|
}
|
|
110
|
+
textAlignLeft={textAlignLeft}
|
|
111
|
+
isValid={newValue => {
|
|
112
|
+
const validity = isValid(Number(newValue), range);
|
|
113
|
+
if (onValidityChanged != null) {
|
|
114
|
+
// Then propagate the validity back to parent
|
|
115
|
+
onValidityChanged(validity);
|
|
116
|
+
}
|
|
117
|
+
return validity;
|
|
118
|
+
}}
|
|
119
|
+
onValidityChanged={onValidityChanged}
|
|
120
|
+
preventDefaultInvalidStyle={preventDefaultInvalidStyle}
|
|
103
121
|
/>
|
|
104
122
|
);
|
|
105
123
|
};
|
|
106
|
-
|
|
107
|
-
export default NumberInlineInput;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023 Nordic Semiconductor ASA
|
|
3
|
+
*
|
|
4
|
+
* SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useState } from 'react';
|
|
8
|
+
|
|
9
|
+
import { DropdownItem } from '../Dropdown/Dropdown';
|
|
10
|
+
import { RangeOrValues } from '../Slider/range';
|
|
11
|
+
import classNames from '../utils/classNames';
|
|
12
|
+
import NumberInlineInput from './NumberInlineInput';
|
|
13
|
+
|
|
14
|
+
import styles from '../Dropdown/Dropdown.module.scss';
|
|
15
|
+
|
|
16
|
+
export type NumberDropdownItem = DropdownItem<number>;
|
|
17
|
+
|
|
18
|
+
interface DropdownProps {
|
|
19
|
+
id?: string;
|
|
20
|
+
label?: React.ReactNode;
|
|
21
|
+
items: NumberDropdownItem[];
|
|
22
|
+
value: number;
|
|
23
|
+
onChange: (value: number) => void;
|
|
24
|
+
range: RangeOrValues;
|
|
25
|
+
numItemsBeforeScroll?: number;
|
|
26
|
+
className?: string;
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
title?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default ({
|
|
32
|
+
id,
|
|
33
|
+
label,
|
|
34
|
+
items,
|
|
35
|
+
value,
|
|
36
|
+
onChange,
|
|
37
|
+
range,
|
|
38
|
+
numItemsBeforeScroll = 0,
|
|
39
|
+
className = '',
|
|
40
|
+
disabled = false,
|
|
41
|
+
title,
|
|
42
|
+
}: DropdownProps) => {
|
|
43
|
+
const [isActive, setIsActive] = useState(false);
|
|
44
|
+
const [inlineValue, setInlineValue] = useState(value);
|
|
45
|
+
const [isValid, setIsValid] = useState(true);
|
|
46
|
+
|
|
47
|
+
const setNewValue = (newValue: number) => {
|
|
48
|
+
setInlineValue(newValue);
|
|
49
|
+
onChange(newValue);
|
|
50
|
+
setIsActive(false);
|
|
51
|
+
};
|
|
52
|
+
const onClickItem = (item: NumberDropdownItem) => {
|
|
53
|
+
if (item.value != null && typeof item.value === 'number') {
|
|
54
|
+
setNewValue(item.value);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div
|
|
60
|
+
className={`tw-preflight tw-relative tw-w-full ${className}`}
|
|
61
|
+
onBlur={event => {
|
|
62
|
+
if (!event.currentTarget.contains(event.relatedTarget)) {
|
|
63
|
+
setIsActive(false);
|
|
64
|
+
}
|
|
65
|
+
}}
|
|
66
|
+
title={title}
|
|
67
|
+
>
|
|
68
|
+
<div className="tw-mb-1 tw-text-xs">{label}</div>
|
|
69
|
+
<div className="tw-flex tw-h-8 tw-w-full">
|
|
70
|
+
<NumberInlineInput
|
|
71
|
+
value={inlineValue}
|
|
72
|
+
range={range}
|
|
73
|
+
onChange={val => setInlineValue(val)}
|
|
74
|
+
onChangeComplete={val => setNewValue(val)}
|
|
75
|
+
className={`tw-x-2 tw-h-full tw-w-full tw-bg-gray-700 tw-text-white tw-underline tw-underline-offset-2 ${
|
|
76
|
+
isValid ? 'tw-decoration-white' : 'tw-decoration-red'
|
|
77
|
+
}`}
|
|
78
|
+
textAlignLeft
|
|
79
|
+
onValidityChanged={setIsValid}
|
|
80
|
+
preventDefaultInvalidStyle
|
|
81
|
+
/>
|
|
82
|
+
<button
|
|
83
|
+
id={id}
|
|
84
|
+
type="button"
|
|
85
|
+
className="tw-overflow-hidden tw-border-b tw-border-solid tw-border-b-gray-200 tw-bg-gray-700 tw-px-2 tw-text-white"
|
|
86
|
+
onClick={() => setIsActive(!isActive)}
|
|
87
|
+
disabled={disabled}
|
|
88
|
+
>
|
|
89
|
+
<span
|
|
90
|
+
className={`mdi mdi-chevron-down tw-text-lg ${classNames(
|
|
91
|
+
isActive && 'tw-rotate-180'
|
|
92
|
+
)}`}
|
|
93
|
+
/>
|
|
94
|
+
</button>
|
|
95
|
+
</div>
|
|
96
|
+
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions -- We need an interactive handler as described below */}
|
|
97
|
+
<div
|
|
98
|
+
onMouseDown={ev => {
|
|
99
|
+
// To prevent the dropdown from closing when users click on the scrollbar of the items
|
|
100
|
+
ev.preventDefault();
|
|
101
|
+
}}
|
|
102
|
+
style={
|
|
103
|
+
numItemsBeforeScroll > 0
|
|
104
|
+
? {
|
|
105
|
+
maxHeight: `${numItemsBeforeScroll * 24}px`,
|
|
106
|
+
}
|
|
107
|
+
: {}
|
|
108
|
+
}
|
|
109
|
+
data-height={
|
|
110
|
+
numItemsBeforeScroll > 0 &&
|
|
111
|
+
items.length > numItemsBeforeScroll
|
|
112
|
+
}
|
|
113
|
+
className={`tw-text-while tw-absolute tw-right-0 tw-z-10 tw-w-full tw-bg-gray-700 tw-p-0 ${classNames(
|
|
114
|
+
styles.content,
|
|
115
|
+
!isActive && 'tw-hidden'
|
|
116
|
+
)}`}
|
|
117
|
+
>
|
|
118
|
+
{items.map(item => (
|
|
119
|
+
<button
|
|
120
|
+
type="button"
|
|
121
|
+
className="tw-bg-transparent tw-clear-both tw-block tw-h-6 tw-w-full tw-whitespace-nowrap tw-border-0 tw-px-2 tw-py-1 tw-text-left tw-font-normal tw-text-white hover:tw-bg-gray-600 focus:tw-bg-gray-600"
|
|
122
|
+
key={item.value}
|
|
123
|
+
onClick={() => onClickItem(item)}
|
|
124
|
+
>
|
|
125
|
+
{item.label}
|
|
126
|
+
</button>
|
|
127
|
+
))}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -48,6 +48,8 @@ export { Group, CollapsibleGroup } from './SidePanel/Group';
|
|
|
48
48
|
export { default as InlineInput } from './InlineInput/InlineInput';
|
|
49
49
|
export { default as NumberInlineInput } from './InlineInput/NumberInlineInput';
|
|
50
50
|
export { default as NumberInputSliderWithUnit } from './NumberInputWithSlider/NumberInputSliderWithUnit';
|
|
51
|
+
export { default as NumberInputWithDropdown } from './InlineInput/NumberInputWithDropdown';
|
|
52
|
+
export type { NumberDropdownItem } from './InlineInput/NumberInputWithDropdown';
|
|
51
53
|
|
|
52
54
|
export { default as Spinner } from './Spinner/Spinner';
|
|
53
55
|
|
|
@@ -101,6 +103,7 @@ export { sdfuDeviceSetup } from './Device/sdfuOperations';
|
|
|
101
103
|
|
|
102
104
|
export {
|
|
103
105
|
selectedDevice,
|
|
106
|
+
selectedDeviceInfo,
|
|
104
107
|
getReadbackProtection,
|
|
105
108
|
persistSerialPortOptions,
|
|
106
109
|
type Device,
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { inMain as appDetails } from '../../ipc/appDetails';
|
|
8
8
|
import NrfutilDeviceLib from '../../nrfutil/device/device';
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
getExpectedVersion,
|
|
11
11
|
resolveModuleVersion,
|
|
12
12
|
} from '../../nrfutil/moduleVersion';
|
|
13
13
|
import { getAppDataDir } from '../utils/appDirs';
|
|
@@ -34,7 +34,6 @@ export default async () => {
|
|
|
34
34
|
installed,
|
|
35
35
|
homeDir,
|
|
36
36
|
tmpDir,
|
|
37
|
-
bundledJlink,
|
|
38
37
|
source,
|
|
39
38
|
} = details;
|
|
40
39
|
|
|
@@ -47,16 +46,21 @@ export default async () => {
|
|
|
47
46
|
logger.debug(`HomeDir: ${homeDir}`);
|
|
48
47
|
logger.debug(`TmpDir: ${tmpDir}`);
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const jlinkVersion = resolveModuleVersion('JlinkARM', dependencies);
|
|
49
|
+
const dependencies = (await NrfutilDeviceLib.getModuleVersion())
|
|
50
|
+
.dependencies;
|
|
51
|
+
const jlinkVersion = resolveModuleVersion('JlinkARM', dependencies);
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
if (jlinkVersion) {
|
|
54
|
+
const result = getExpectedVersion(jlinkVersion);
|
|
55
|
+
if (!result.isExpectedVersion) {
|
|
56
|
+
logger.warn(
|
|
57
|
+
`Installed JLink version does not match the expected version (${result.expectedVersion})`
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
|
+
} else {
|
|
61
|
+
logger.warn(
|
|
62
|
+
`JLink is not installed. Please install JLink from: https://www.segger.com/downloads/jlink`
|
|
63
|
+
);
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
if (!udevInstalled()) {
|
|
@@ -91,7 +91,7 @@ export default async () => {
|
|
|
91
91
|
`It looks like you have installed JLink using ${JLinkInstallerVersion}, but currently we only support their Universal Installer for your system.`
|
|
92
92
|
);
|
|
93
93
|
logger.warn(
|
|
94
|
-
`Please install JLink: https://www.segger.com/downloads/jlink/
|
|
94
|
+
`Please install JLink: https://www.segger.com/downloads/jlink/JLink_MacOSX_V788j_universal.pkg`
|
|
95
95
|
);
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -89,7 +89,7 @@ const allDevicesReport = (allDevices: Device[] = []) => [
|
|
|
89
89
|
...allDevices.map(
|
|
90
90
|
d =>
|
|
91
91
|
` - ${d.serialNumber} ${
|
|
92
|
-
d.
|
|
92
|
+
d.devkit?.boardVersion || ''
|
|
93
93
|
}: ${d.serialPorts?.map(s => s.comName).join(', ')}`
|
|
94
94
|
),
|
|
95
95
|
'',
|
|
@@ -129,14 +129,14 @@ export const generateSystemReport = async (
|
|
|
129
129
|
export default async (
|
|
130
130
|
allDevices: Device[],
|
|
131
131
|
currentSerialNumber: string,
|
|
132
|
-
currentDevice
|
|
132
|
+
currentDevice?: Device
|
|
133
133
|
) => {
|
|
134
134
|
logger.info('Generating system report...');
|
|
135
135
|
const timestamp = new Date().toISOString().replace(/:/g, '-');
|
|
136
136
|
const report = await generateSystemReport(
|
|
137
137
|
timestamp,
|
|
138
138
|
allDevices,
|
|
139
|
-
currentDevice
|
|
139
|
+
currentDevice,
|
|
140
140
|
currentSerialNumber
|
|
141
141
|
);
|
|
142
142
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../../../../nrfutil/device/__mocks__/device.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../../../../nrfutil/device/__mocks__/device.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA0BA,wBAkBE"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { TaskEnd } from '../sandboxTypes';
|
|
3
3
|
import { Callbacks } from './batchTypes';
|
|
4
|
-
import { DeviceCore, DeviceTraits,
|
|
4
|
+
import { DeviceCore, DeviceTraits, NrfutilDevice, ResetKind } from './common';
|
|
5
5
|
import { DeviceCoreInfo } from './getCoreInfo';
|
|
6
6
|
import { FWInfo } from './getFwInfo';
|
|
7
7
|
import { GetProtectionStatusResult } from './getProtectionStatus';
|
|
@@ -10,6 +10,7 @@ export declare class Batch {
|
|
|
10
10
|
private operationBatchGeneration;
|
|
11
11
|
private collectOperations;
|
|
12
12
|
private enqueueBatchOperationObject;
|
|
13
|
+
getDeviceInfo(core: DeviceCore, callbacks?: Callbacks<FWInfo>): this;
|
|
13
14
|
erase(core: DeviceCore, callbacks?: Callbacks): this;
|
|
14
15
|
firmwareRead(core: DeviceCore, callbacks?: Callbacks<Buffer>): this;
|
|
15
16
|
getCoreInfo(core: DeviceCore, callbacks?: Callbacks<DeviceCoreInfo>): this;
|
|
@@ -19,6 +20,6 @@ export declare class Batch {
|
|
|
19
20
|
recover(core: DeviceCore, callbacks?: Callbacks): this;
|
|
20
21
|
reset(core: DeviceCore, reset?: ResetKind, callbacks?: Callbacks): this;
|
|
21
22
|
collect(count: number, callback: (completedTasks: TaskEnd<unknown>[]) => void): this;
|
|
22
|
-
run(device:
|
|
23
|
+
run(device: NrfutilDevice, controller?: AbortController | undefined): Promise<unknown[]>;
|
|
23
24
|
}
|
|
24
25
|
//# sourceMappingURL=batch.d.ts.map
|