Skip to content

Commit 226f250

Browse files
Fix Ethernet IP display (#838)
* Fix Ethernet IP display * fixed padding and tests * fallback to bytes if requested size > type size. Needed for IP address. * updated unit tests
1 parent 9be0996 commit 226f250

10 files changed

Lines changed: 581 additions & 218 deletions

File tree

src/views/component-viewer/data-host/memory-host.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ export class MemoryHost {
199199
// TOIMPL: add BE support if needed
200200
}
201201

202+
// Check if widthBytes exceeds the natural type size
203+
// This indicates a multi-byte value (e.g., uint8_t with size="4" for IP address)
204+
// that should remain as raw bytes rather than being converted to a number
205+
const typeSize = ref.valueType?.bits ? ref.valueType.bits / 8 : undefined;
206+
if (typeSize && widthBytes > typeSize && ref.valueType?.kind !== 'float') {
207+
componentViewerLogger.trace(`[MemoryHost.readValue] → raw bytes (width=${widthBytes} > typeSize=${typeSize})`);
208+
return raw.slice();
209+
}
210+
202211
// Interpret the bytes:
203212
// - float kinds decode as float32/float64
204213
// - ≤4 bytes: JS number (uint32)

src/views/component-viewer/model/scvd-format-specifier.ts

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,27 @@ export class ScvdFormatSpecifier {
139139
const n = Number(v);
140140
return Number.isFinite(n) ? n : NaN;
141141
}
142+
// Convert Uint8Array to number (little-endian)
143+
if (v instanceof Uint8Array) {
144+
if (v.length === 0) {
145+
return 0;
146+
}
147+
if (v.length <= 4) {
148+
let out = 0;
149+
for (const b of Array.from(v).reverse()) {
150+
out = (out << 8) | (b & 0xff);
151+
}
152+
return out >>> 0;
153+
}
154+
if (v.length === 8) {
155+
let out = 0n;
156+
for (let i = 0; i < 8; i++) {
157+
// eslint-disable-next-line security/detect-object-injection
158+
out |= BigInt(v[i]) << BigInt(8 * i);
159+
}
160+
return out;
161+
}
162+
}
142163
return NaN;
143164
};
144165

@@ -158,7 +179,9 @@ export class ScvdFormatSpecifier {
158179
if (typeof n === 'number') {
159180
n = Math.trunc(n);
160181
}
161-
return this.formatNumberByType(n, numOpts('int'));
182+
// Legacy compatibility: if type is unsigned (uint8/uint16/uint32), format as unsigned
183+
const isUnsigned = typeInfo?.kind === 'uint';
184+
return this.formatNumberByType(n, numOpts(isUnsigned ? 'uint' : 'int'));
162185
}
163186
case 'u': {
164187
let n = toNumber(value);
@@ -168,11 +191,15 @@ export class ScvdFormatSpecifier {
168191
return this.formatNumberByType(n, numOpts('uint'));
169192
}
170193
case 'x': {
194+
const isStringValue = typeof value === 'string';
171195
let n = toNumeric(value);
172196
if (typeof n === 'number' && (typeInfo?.kind ?? 'unknown') !== 'float') {
173197
n = Math.trunc(n);
174198
}
175-
return this.format_x(n, typeInfo, padHex);
199+
// Always pad hex values when type info is available OR when value is a string (8-bit→2, 16-bit→4, 32-bit→8 hex digits)
200+
const shouldPad = padHex || (typeInfo?.bits !== undefined) || isStringValue;
201+
const effectiveType = typeInfo ?? (isStringValue ? { kind: 'int' as const, bits: 32 } : undefined);
202+
return this.format_x(n, effectiveType, shouldPad);
176203
}
177204
case 't': {
178205
if (typeof value === 'string') {
@@ -258,17 +285,42 @@ export class ScvdFormatSpecifier {
258285
if (typeof value === 'bigint') {
259286
const widthRaw = bits ? Math.ceil(bits / 4) : 0;
260287
const width = padZeroes && widthRaw > 0 ? Math.min(widthRaw, 16) : 0;
261-
const hex = value.toString(16);
288+
// Mask to bit width if specified
289+
let maskedValue = value;
290+
if (bits && bits > 0 && bits < 64) {
291+
const mask = (BigInt(1) << BigInt(bits)) - BigInt(1);
292+
maskedValue = value & mask;
293+
}
294+
const hex = maskedValue.toString(16).toUpperCase();
262295
const padded = width > 0 ? hex.padStart(width, '0') : hex;
263296
return '0x' + padded;
264297
}
265298
const n = Number(value);
266299
if (!Number.isFinite(n)) {
267300
return `${value}`;
268301
}
302+
303+
// For 64-bit values, convert to bigint to properly handle the full range
304+
if (bits && bits === 64) {
305+
const bi = BigInt(Math.trunc(n));
306+
const mask = (BigInt(1) << BigInt(64)) - BigInt(1);
307+
const maskedValue = bi & mask;
308+
const widthRaw = Math.ceil(bits / 4);
309+
const width = padZeroes && widthRaw > 0 ? Math.min(widthRaw, 16) : 0;
310+
const hex = maskedValue.toString(16).toUpperCase();
311+
const padded = width > 0 ? hex.padStart(width, '0') : hex;
312+
return '0x' + padded;
313+
}
314+
269315
const widthRaw = bits ? Math.ceil(bits / 4) : 0;
270316
const width = padZeroes && widthRaw > 0 ? Math.min(widthRaw, 16) : 0; // cap padding to 64-bit to avoid runaway zeros
271-
const hex = (n >>> 0).toString(16);
317+
// Mask to bit width if specified, otherwise use 32-bit unsigned
318+
let maskedValue = n >>> 0;
319+
if (bits && bits > 0 && bits < 32) {
320+
const mask = (1 << bits) - 1;
321+
maskedValue = (n >>> 0) & mask;
322+
}
323+
const hex = maskedValue.toString(16).toUpperCase();
272324
const padded = width > 0 ? hex.padStart(width, '0') : hex;
273325
return '0x' + padded;
274326
}
@@ -331,7 +383,11 @@ export class ScvdFormatSpecifier {
331383
if (!Number.isFinite(n)) {
332384
return `${value}`;
333385
}
334-
return this.formatHex(n, typeInfo, padZeroes);
386+
// When value is a string and no typeInfo provided, default to 32-bit for padding
387+
const isStringValue = typeof value === 'string';
388+
const effectiveType = typeInfo ?? (isStringValue ? { kind: 'int' as const, bits: 32 } : undefined);
389+
const effectivePadding = padZeroes || isStringValue; // Always pad string values
390+
return this.formatHex(n, effectiveType, effectivePadding);
335391
}
336392

337393
public format_address_like(value: number | string): string {

src/views/component-viewer/model/scvd-member.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { Json } from './scvd-base';
2424
import { ScvdNode } from './scvd-node';
2525
import { getArrayFromJson, getStringFromJson } from './scvd-utils';
2626

27-
// Offset to base address in [Bytes]. Use the uVision debug dialog Symbols to find the offset. You can use Expressions.
27+
// Offset to base address in bytes. You can use expressions to compute the offset dynamically.
2828
// For imported members, the offset is recalculated. Refer to the description of attribute import in typedef.
2929
export class ScvdMember extends ScvdNode {
3030
private _type: ScvdDataType | undefined;

0 commit comments

Comments
 (0)