Skip to content

Commit 3262e2b

Browse files
ihex: Remove assumption that records have 16 bytes in data fields.
1 parent 7a410a0 commit 3262e2b

File tree

9 files changed

+11221
-46
lines changed

9 files changed

+11221
-46
lines changed

src/__tests__/hex-files/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test-output-*.hex
File renamed without changes.

src/__tests__/hex-files/1-duck-umbrella-32.hex

Lines changed: 8197 additions & 0 deletions
Large diffs are not rendered by default.
File renamed without changes.

src/__tests__/hex-files/2-ghost-music-32.hex

Lines changed: 2915 additions & 0 deletions
Large diffs are not rendered by default.

src/__tests__/ihex.spec.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,16 @@ describe('Test createRecord() for standard records', () => {
5757
// TODO: Add tests for the StartLinearAddress record
5858

5959
it('Throws error when data given is too large', () => {
60+
let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
61+
data = data.concat(data);
6062
expect(() => {
61-
const d = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
62-
ihex.createRecord(0, ihex.RecordType.Data, new Uint8Array(d));
63+
ihex.createRecord(0, ihex.RecordType.Data, new Uint8Array(data));
64+
}).not.toThrow();
65+
66+
data.push(33);
67+
68+
expect(() => {
69+
ihex.createRecord(0, ihex.RecordType.Data, new Uint8Array(data));
6370
}).toThrow();
6471
});
6572

@@ -336,14 +343,12 @@ describe('Test blockEndRecord()', () => {
336343

337344
it('Throws error when the number of bytes to pad is too large', () => {
338345
expect(() => {
339-
ihex.blockEndRecord(17);
340-
}).toThrow('has too many bytes');
341-
});
342-
});
346+
ihex.blockEndRecord(32);
347+
}).not.toThrow('has too many bytes');
343348

344-
describe('Test recordPaddingCapacity()', () => {
345-
it('Check return value is 0x10', () => {
346-
expect(ihex.recordPaddingCapacity()).toEqual(16);
349+
expect(() => {
350+
ihex.blockEndRecord(33);
351+
}).toThrow('has too many bytes');
347352
});
348353
});
349354

@@ -365,7 +370,11 @@ describe('Test paddedDataRecord()', () => {
365370

366371
it('Throws error when the number of bytes to pad is too large', () => {
367372
expect(() => {
368-
ihex.paddedDataRecord(17);
373+
ihex.paddedDataRecord(32);
374+
}).not.toThrow('has too many bytes');
375+
376+
expect(() => {
377+
ihex.paddedDataRecord(33);
369378
}).toThrow('has too many bytes');
370379
});
371380
});

src/__tests__/universal-hex.spec.ts

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import * as fs from 'fs';
33
import * as uh from '../universal-hex';
44

55
const hex1 = fs.readFileSync(
6-
'./src/__tests__/hex-files/1-duck-umbrella.hex',
6+
'./src/__tests__/hex-files/1-duck-umbrella-16.hex',
77
'utf8'
88
);
99
const hex2 = fs.readFileSync(
10-
'./src/__tests__/hex-files/2-ghost-music.hex',
10+
'./src/__tests__/hex-files/2-ghost-music-16.hex',
1111
'utf8'
1212
);
1313

@@ -375,30 +375,58 @@ describe('Test createUniversalHex()', () => {
375375

376376
/*
377377
// Not real unit tests, just converting files for manual testing
378-
const hex1 = fs.readFileSync(
379-
'./src/__tests__/hex-files/1-duck-umbrella.hex',
378+
const hex1_32 = fs.readFileSync(
379+
'./src/__tests__/hex-files/1-duck-umbrella-32.hex',
380380
'utf8'
381381
);
382-
const hex2 = fs.readFileSync(
383-
'./src/__tests__/hex-files/2-ghost-music.hex',
382+
const hex2_32 = fs.readFileSync(
383+
'./src/__tests__/hex-files/2-ghost-music-32.hex',
384384
'utf8'
385385
);
386386
387-
it('.', () => {
388-
const result1 = uh.iHexToCustomFormat(hex1, 0x9901);
389-
fs.writeFileSync('./src/__tests__/hex-files/test-output-1.hex', result1);
390-
const result2 = uh.iHexToCustomFormat(hex2, 0x9903);
391-
fs.writeFileSync('./src/__tests__/hex-files/test-output-2.hex', result2);
387+
it('Creates Universal Hex files for a single target', () => {
388+
const result1_16 = uh.iHexToCustomFormat(hex1, 0x9901);
389+
fs.writeFileSync(
390+
'./src/__tests__/hex-files/test-output-1-16.hex',
391+
result1_16
392+
);
393+
const result2_16 = uh.iHexToCustomFormat(hex2, 0x9903);
394+
fs.writeFileSync(
395+
'./src/__tests__/hex-files/test-output-2-16.hex',
396+
result2_16
397+
);
398+
const result1_32 = uh.iHexToCustomFormat(hex1_32, 0x9901);
399+
fs.writeFileSync(
400+
'./src/__tests__/hex-files/test-output-1-32.hex',
401+
result1_32
402+
);
403+
const result2_32 = uh.iHexToCustomFormat(hex2_32, 0x9903);
404+
fs.writeFileSync(
405+
'./src/__tests__/hex-files/test-output-2-32.hex',
406+
result2_32
407+
);
392408
393409
expect('').toEqual('');
394410
});
395411
396-
it('..', () => {
412+
it('Creates a combined universal hex file for both targets', () => {
397413
const result = uh.createUniversalHex([
398-
{ hex: hex1, boardID: 0x9901 },
399-
{ hex: hex2, boardID: 0x9903 },
414+
{ hex: hex1, boardId: 0x9900 },
415+
{ hex: hex2, boardId: 0x9903 },
400416
]);
401-
fs.writeFileSync('./src/__tests__/hex-files/test-output-universal.hex', result);
417+
fs.writeFileSync(
418+
'./src/__tests__/hex-files/test-output-universal-16.hex',
419+
result
420+
);
421+
422+
const result32 = uh.createUniversalHex([
423+
{ hex: hex1_32, boardId: 0x9900 },
424+
{ hex: hex2_32, boardId: 0x9903 },
425+
]);
426+
fs.writeFileSync(
427+
'./src/__tests__/hex-files/test-output-universal-32.hex',
428+
result32
429+
);
402430
403431
expect('').toEqual('');
404432
});

src/ihex.ts

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ interface Record {
3030

3131
/**
3232
* The maximum data bytes per record is 0xFF, 16 and 32 bytes are the two most
33-
* common lengths, but to start we'll only support 16 bytes
33+
* common lengths, but DAPLink doesn't support more than 32 bytes.
3434
*/
35-
const RECORD_DATA_MAX_BYTES = 16;
35+
const RECORD_DATA_MAX_BYTES = 32;
3636

3737
/**
3838
* Constants for the record character lengths.
@@ -318,16 +318,6 @@ function blockEndRecord(padBytesLen: number): string {
318318
}
319319
}
320320

321-
/**
322-
* The Block end record can add bytes to the data field to be generate 512 byte
323-
* blocks. This function exposes how many bytes the record can fit.
324-
*
325-
* @returns Number of padding bytes that fit inside a Block End (custom) Record.
326-
*/
327-
function recordPaddingCapacity(): number {
328-
return RECORD_DATA_MAX_BYTES;
329-
}
330-
331321
/**
332322
* Create a Padded Data (custom) Intel Hex Record.
333323
* This record is used to add padding data, to be ignored by DAPLink, to be able
@@ -380,7 +370,42 @@ function iHexToRecordStrs(iHexStr: string): string[] {
380370
return output.filter(Boolean);
381371
}
382372

373+
/**
374+
* Iterates through the beginning of an array of Intel Hex records to find the
375+
* longest record data field length.
376+
*
377+
* Once it finds 10 records at the maximum size found so far (starts at 16
378+
* bytes) it will stop iterating.
379+
*
380+
* This is useful to identify the expected max size of the data records for an
381+
* Intel Hex, and then be able to generate new custom records of the same size.
382+
*
383+
* @param iHexRecords Array of Intel Hex Records
384+
* @returns Number of data bytes th
385+
*/
386+
function findDataFieldLength(iHexRecords: string[]): number {
387+
let maxDataBytes = 16;
388+
let maxDataBytesCount = 0;
389+
for (const record of iHexRecords) {
390+
const dataBytesLength = (record.length - MIN_RECORD_STR_LEN) / 2;
391+
if (dataBytesLength > maxDataBytes) {
392+
maxDataBytes = dataBytesLength;
393+
maxDataBytesCount = 0;
394+
} else if (dataBytesLength === maxDataBytes) {
395+
maxDataBytesCount++;
396+
}
397+
if (maxDataBytesCount > 10) {
398+
break;
399+
}
400+
}
401+
if (maxDataBytes > RECORD_DATA_MAX_BYTES) {
402+
throw new Error(`Intel Hex record data size is too large: ${maxDataBytes}`);
403+
}
404+
return maxDataBytes;
405+
}
406+
383407
export {
408+
MAX_RECORD_STR_LEN,
384409
RecordType,
385410
createRecord,
386411
getRecordType,
@@ -391,7 +416,7 @@ export {
391416
blockStartRecord,
392417
blockEndRecord,
393418
paddedDataRecord,
394-
recordPaddingCapacity,
395419
convertRecordTo,
396420
iHexToRecordStrs,
421+
findDataFieldLength,
397422
};

src/universal-hex.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ interface IndividualHex {
1616
}
1717

1818
/**
19-
* Converts a hex file string into a Universal Hex ready hex string using custom
19+
* Converts an Intel Hex file string into a Universal Hex ready hex string using custom
2020
* records and 512 byte blocks.
2121
*
2222
* Block format:
@@ -43,10 +43,10 @@ function iHexToCustomFormat(iHexStr: string, boardId: number): string {
4343
const extAddrRecordLen = currentExtAddr.length;
4444
const startRecordLen = startRecord.length;
4545
const endRecordBaseLen = ihex.blockEndRecord(0).length;
46-
const recordPaddingCapacity = ihex.recordPaddingCapacity();
4746
const padRecordBaseLen = ihex.paddedDataRecord(0).length;
4847

4948
const hexRecords = ihex.iHexToRecordStrs(iHexStr);
49+
const recordPaddingCapacity = ihex.findDataFieldLength(hexRecords);
5050

5151
// Each loop iteration corresponds to a 512-bytes block
5252
let ih = 0;
@@ -164,16 +164,16 @@ function createUniversalHex(hexes: IndividualHex[]): string {
164164
*/
165165
function isUniversalHex(hexStr: string): boolean {
166166
// Check the beginning of the Extended Linear Address record
167-
const startOfElaRecord = ':02000004';
168-
if (hexStr.slice(0, startOfElaRecord.length) !== startOfElaRecord) {
167+
const elaRecordBeginning = ':02000004';
168+
if (hexStr.slice(0, elaRecordBeginning.length) !== elaRecordBeginning) {
169169
return false;
170170
}
171171
// Find the index for the next record, as we have unknown line endings
172-
let i = startOfElaRecord.length;
173-
while (hexStr[++i] !== ':' && i < 50);
172+
let i = elaRecordBeginning.length;
173+
while (hexStr[++i] !== ':' && i < ihex.MAX_RECORD_STR_LEN + 3);
174174
// Check the beginning of the Block Start record
175-
const startOfBsRecord = ':0400000A';
176-
if (hexStr.slice(i, i + startOfBsRecord.length) !== startOfBsRecord) {
175+
const blockStartBeginning = ':0400000A';
176+
if (hexStr.slice(i, i + blockStartBeginning.length) !== blockStartBeginning) {
177177
return false;
178178
}
179179
return true;

0 commit comments

Comments
 (0)