diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index 618fd58..096b634 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -244,10 +244,20 @@
"driverIndex": "Type",
"capacity": "Capacity",
"capacityHint": "Supports numbers, hexadecimal (0x...) or with units (16M)",
+ "capacityRequired": "Please enter capacity",
+ "requiredField": "Required",
"manufacturerId": "Manufacturer ID",
- "deviceType": "Device Type",
- "densityId": "Density ID",
- "flags": "Flags",
+ "deviceType": "Device ID1",
+ "densityId": "Device ID2",
+ "flags": "Flag",
+ "flagsNorDtr": "DTR supported",
+ "flagsNandDualPlane": "double plane",
+ "flagsNandPageSize": "Page size",
+ "flagsNandBlockSize": "Block size",
+ "flagsNandEccMode": "ECC mode",
+ "flagsOptionEnabled": "Enabled",
+ "flagsOptionDisabled": "Disabled",
+ "chipIdTooltip": "The first three bytes read by the 9Fh instruction.",
"deviceInvalid": "Invalid",
"sectionInvalid": "Invalid",
"noDevices": "No FLASH devices added",
@@ -366,7 +376,7 @@
}
},
"stubConfig": {
- "title": "",
+ "title": " ",
"apply": "Apply Custom Stub Configuration",
"invalidConfig": "Configuration contains errors and cannot be enabled",
"configHasErrors": "Configuration contains errors, please check and correct on the Stub configuration page"
diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json
index a088698..9cff6ee 100644
--- a/src/i18n/locales/zh.json
+++ b/src/i18n/locales/zh.json
@@ -244,10 +244,20 @@
"driverIndex": "Type",
"capacity": "容量",
"capacityHint": "支持数字、十六进制 (0x...) 或带单位 (16M)",
- "manufacturerId": "制造商 ID",
- "deviceType": "设备类型",
- "densityId": "颗粒 ID",
+ "capacityRequired": "请输入容量",
+ "requiredField": "必填项",
+ "manufacturerId": "Manufacturer ID",
+ "deviceType": "Device ID1",
+ "densityId": "Device ID2",
"flags": "标志",
+ "flagsNorDtr": "DTR 支持",
+ "flagsNandDualPlane": "双 plane",
+ "flagsNandPageSize": "Page 大小",
+ "flagsNandBlockSize": "Block 大小",
+ "flagsNandEccMode": "ECC 模式",
+ "flagsOptionEnabled": "开启",
+ "flagsOptionDisabled": "关闭",
+ "chipIdTooltip": "9Fh指令读取到的前三个byte",
"deviceInvalid": "配置有误",
"sectionInvalid": "配置有误",
"noDevices": "尚未添加 FLASH 设备",
diff --git a/src/views/StubConfigView.vue b/src/views/StubConfigView.vue
index fdc0b49..b06cef4 100644
--- a/src/views/StubConfigView.vue
+++ b/src/views/StubConfigView.vue
@@ -44,7 +44,7 @@
{{ $t('stubConfig.flash.media') }}
-
-
-
-
-
-
-
-
-
-
-
-
@@ -551,6 +641,11 @@ type FlashDevice = {
device_type: string;
density_id: string;
flags: string;
+ nor_dtr?: boolean;
+ nand_dual_plane?: boolean;
+ nand_page_size?: number;
+ nand_block_size?: number;
+ nand_ecc_mode?: number;
capacity_bytes: string | number;
expanded: boolean;
capacityError?: string;
@@ -615,6 +710,8 @@ const flashConfig = computed({
},
});
+const flashDevices = computed(() => flashConfig.value.devices as FlashDevice[]);
+
// PMIC 可用通道
const availablePmicChannels = [
'1v8_lvsw100_1',
@@ -718,7 +815,7 @@ const validateCapacity = (device: any) => {
const value = device.capacity_bytes;
if (!value) {
- device.capacityError = '';
+ device.capacityError = t('stubConfig.flash.capacityRequired');
return;
}
@@ -787,7 +884,7 @@ const validateHexField = (device: any, fieldName: string) => {
: 'flagsError';
if (!value) {
- device[errorFieldName] = '';
+ device[errorFieldName] = t('stubConfig.flash.requiredField');
return;
}
@@ -806,6 +903,67 @@ const validateHexField = (device: any, fieldName: string) => {
device[errorFieldName] = t('stubConfig.flash.invalidHexValue');
};
+const parseFlagsByte = (flags: string) => {
+ const valueStr = String(flags || '').trim();
+ const hexPattern = /^0x[0-9a-fA-F]{1,2}$/;
+ if (!hexPattern.test(valueStr)) {
+ return null;
+ }
+ return parseInt(valueStr, 16);
+};
+
+const parseFlagsToUi = (device: FlashDevice) => {
+ const parsed = parseFlagsByte(device.flags);
+ const byte = parsed === null ? 0 : parsed;
+ device.flagsError = parsed === null ? t('stubConfig.flash.invalidHexValue') : '';
+
+ if (device.media === 'nor') {
+ device.nor_dtr = (byte & 0x01) !== 0;
+ device.nand_dual_plane = false;
+ device.nand_page_size = 2048;
+ device.nand_block_size = 64;
+ device.nand_ecc_mode = 0;
+ return;
+ }
+
+ device.nor_dtr = false;
+ device.nand_dual_plane = (byte & 0x02) !== 0;
+ device.nand_page_size = (byte & 0x04) !== 0 ? 4096 : 2048;
+ device.nand_block_size = (byte & 0x08) !== 0 ? 128 : 64;
+ const ecc = (byte >> 4) & 0x0f;
+ device.nand_ecc_mode = ecc <= 6 ? ecc : 0;
+};
+
+const updateFlagsFromUi = (device: FlashDevice) => {
+ let byte = 0;
+ const norDtr = device.nor_dtr ?? false;
+ const nandDualPlane = device.nand_dual_plane ?? false;
+ const nandPageSize = device.nand_page_size ?? 2048;
+ const nandBlockSize = device.nand_block_size ?? 64;
+ const nandEccMode = device.nand_ecc_mode ?? 0;
+
+ if (device.media === 'nor') {
+ byte |= norDtr ? 0x01 : 0x00;
+ } else {
+ byte |= nandDualPlane ? 0x02 : 0x00;
+ byte |= nandPageSize === 4096 ? 0x04 : 0x00;
+ byte |= nandBlockSize === 128 ? 0x08 : 0x00;
+ const ecc = Math.min(6, Math.max(0, Number(nandEccMode) || 0));
+ byte |= ecc << 4;
+ }
+
+ device.flags = `0x${byte.toString(16).padStart(2, '0')}`;
+ device.flagsError = '';
+};
+
+const validateFlashDeviceRequired = (device: FlashDevice) => {
+ validateCapacity(device);
+ validateHexField(device, 'manufacturer_id');
+ validateHexField(device, 'device_type');
+ validateHexField(device, 'density_id');
+ validateHexField(device, 'flags');
+};
+
const createFlashDevice = (overrides: Partial = {}): FlashDevice => {
return {
id: `${Date.now()}-${Math.random().toString(16).slice(2)}`,
@@ -814,7 +972,12 @@ const createFlashDevice = (overrides: Partial = {}): FlashDevice =>
manufacturer_id: '',
device_type: '',
density_id: '',
- flags: '',
+ flags: '0x00',
+ nor_dtr: false,
+ nand_dual_plane: false,
+ nand_page_size: 2048,
+ nand_block_size: 64,
+ nand_ecc_mode: 0,
capacity_bytes: '', // 16MB
expanded: false,
capacityError: '',
@@ -851,7 +1014,10 @@ const addFlashDevice = () => {
logStore.addMessage(t('stubConfig.flash.maxReached'), true);
return;
}
- flashConfig.value.devices.push(createFlashDevice());
+ const device = createFlashDevice();
+ updateFlagsFromUi(device);
+ validateFlashDeviceRequired(device);
+ flashConfig.value.devices.push(device);
};
// 移除 FLASH 设备
@@ -859,6 +1025,18 @@ const removeFlashDevice = (index: number) => {
flashConfig.value.devices.splice(index, 1);
};
+const onFlashMediaChange = (device: FlashDevice) => {
+ if (device.media === 'nor') {
+ device.nor_dtr = device.nor_dtr ?? false;
+ } else {
+ device.nand_dual_plane = device.nand_dual_plane ?? false;
+ device.nand_page_size = device.nand_page_size ?? 2048;
+ device.nand_block_size = device.nand_block_size ?? 64;
+ device.nand_ecc_mode = device.nand_ecc_mode ?? 0;
+ }
+ updateFlagsFromUi(device);
+};
+
const collapseAllFlashDevices = () => {
flashConfig.value.devices.forEach(device => {
device.expanded = false;
@@ -1018,8 +1196,8 @@ const applyImportedConfig = (config: any) => {
// flash
if (Array.isArray(config.flash)) {
- flashConfig.value.devices = config.flash.slice(0, 12).map((f: any) =>
- createFlashDevice({
+ flashConfig.value.devices = config.flash.slice(0, 12).map((f: any) => {
+ const device = createFlashDevice({
media: f.media === 'nand' ? 'nand' : 'nor',
driver_index: Number(f.driver_index) || 0,
manufacturer_id: f.manufacturer_id ?? '0x00',
@@ -1027,8 +1205,11 @@ const applyImportedConfig = (config: any) => {
density_id: f.density_id ?? '0x00',
flags: f.flags ?? '0x00',
capacity_bytes: f.capacity_bytes ?? '0x1000000',
- })
- );
+ });
+ parseFlagsToUi(device);
+ validateFlashDeviceRequired(device);
+ return device;
+ });
}
};
@@ -1090,6 +1271,7 @@ onMounted(async () => {
await loadConfigFromLocal();
collapseAllFlashDevices();
ensurePinIds();
+ flashConfig.value.devices.forEach(device => parseFlagsToUi(device));
});
// 监听配置变化,自动保存到Pinia store和本地