feat(app-image): add custom app desc dump and SPI pin drive display
This commit is contained in:
parent
1076aa3848
commit
da91312ca9
|
|
@ -34,6 +34,10 @@ function formatHex(val: number): string {
|
|||
return '0x' + val.toString(16).toUpperCase();
|
||||
}
|
||||
|
||||
function formatHexDump(data: Uint8Array): string {
|
||||
return Array.from(data).map(b => b.toString(16).padStart(2, '0')).join(' ');
|
||||
}
|
||||
|
||||
function formatSha256(data: Uint8Array): string {
|
||||
// Check if all zeros (not computed)
|
||||
if (data.every(b => b === 0)) return '(未计算)';
|
||||
|
|
@ -110,6 +114,7 @@ async function handleOpenFile(file: File): Promise<false> {
|
|||
<el-descriptions-item label="Flash大小">{{ SPI_FLASH_SIZE_NAMES[imageInfo.header.spiSize] ?? formatHex(imageInfo.header.spiSize) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="段数">{{ imageInfo.header.segmentCount }}</el-descriptions-item>
|
||||
<el-descriptions-item label="WP引脚">{{ formatHex(imageInfo.extendedHeader.wpPin) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="SPI引脚驱动">{{ imageInfo.extendedHeader.spiPinDrv.map(formatHex).join(' / ') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="最小芯片版本">{{ imageInfo.extendedHeader.minChipRevFull / 100 }}</el-descriptions-item>
|
||||
<el-descriptions-item label="最大芯片版本">{{ imageInfo.extendedHeader.maxChipRevFull === 0xFFFF ? '不限' : imageInfo.extendedHeader.maxChipRevFull / 100 }}</el-descriptions-item>
|
||||
<el-descriptions-item label="附加哈希">{{ imageInfo.extendedHeader.hashAppended ? '是' : '否' }}</el-descriptions-item>
|
||||
|
|
@ -128,6 +133,14 @@ async function handleOpenFile(file: File): Promise<false> {
|
|||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- Custom App Description (raw bytes) -->
|
||||
<template v-if="imageInfo.customDescRawBytes && !imageInfo.customDescRawBytes.every(b => b === 0)">
|
||||
<el-text tag="b" class="block mb-2">自定义应用描述(偏移 288 B,原始字节)</el-text>
|
||||
<el-text size="small" class="font-mono break-all">
|
||||
{{ formatHexDump(imageInfo.customDescRawBytes) }}
|
||||
</el-text>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<el-empty v-else description="请打开一个ESP32固件文件 (.bin)" />
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ export const APP_DESC_MAGIC = 0xABCD5432;
|
|||
/** Size of esp_app_desc_t structure */
|
||||
export const APP_DESC_SIZE = 256;
|
||||
|
||||
/** Offset of custom app desc within first segment data (immediately after esp_app_desc_t) */
|
||||
export const CUSTOM_DESC_OFFSET_IN_SEGMENT = APP_DESC_SIZE; // 256
|
||||
|
||||
/** How many raw bytes to extract for the custom app desc dump */
|
||||
export const CUSTOM_DESC_DUMP_SIZE = 64;
|
||||
|
||||
/** Chip ID to human-readable name */
|
||||
export const CHIP_ID_NAMES: Record<number, string> = {
|
||||
0x0000: 'ESP32',
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import type {
|
|||
import {
|
||||
IMAGE_MAGIC, IMAGE_HEADER_SIZE, EXTENDED_HEADER_SIZE,
|
||||
SEGMENT_HEADER_SIZE, APP_DESC_MAGIC, APP_DESC_SIZE, CHIP_ID_NAMES,
|
||||
CUSTOM_DESC_OFFSET_IN_SEGMENT, CUSTOM_DESC_DUMP_SIZE,
|
||||
} from './constants';
|
||||
|
||||
/**
|
||||
|
|
@ -93,11 +94,21 @@ export function parseAppImage(data: Uint8Array): AppImageInfo {
|
|||
}
|
||||
}
|
||||
|
||||
// ── Custom App Description — fixed offset in first segment ──
|
||||
let customDescRawBytes: Uint8Array | null = null;
|
||||
if (segDataOffsets.length > 0) {
|
||||
const customOff = segDataOffsets[0] + CUSTOM_DESC_OFFSET_IN_SEGMENT;
|
||||
if (customOff + CUSTOM_DESC_DUMP_SIZE <= data.length) {
|
||||
customDescRawBytes = new Uint8Array(data.subarray(customOff, customOff + CUSTOM_DESC_DUMP_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
header,
|
||||
extendedHeader,
|
||||
segments,
|
||||
appDescription,
|
||||
customDescRawBytes,
|
||||
valid: segments.length === segmentCount, // false if image was truncated mid-segment
|
||||
chipName: CHIP_ID_NAMES[chipId] ?? `Unknown (0x${chipId.toString(16)})`,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ export interface AppImageInfo {
|
|||
extendedHeader: ExtendedHeader;
|
||||
segments: SegmentHeader[];
|
||||
appDescription: AppDescription | null;
|
||||
/** Raw bytes at the custom app desc location (null if first segment too short) */
|
||||
customDescRawBytes: Uint8Array | null;
|
||||
valid: boolean;
|
||||
chipName: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue