Skip to content

Commit 425a234

Browse files
upy-fs-builder: Add header description, make a FsFile method private.
1 parent 839b7f1 commit 425a234

File tree

1 file changed

+54
-24
lines changed

1 file changed

+54
-24
lines changed

src/micropython-fs-builder.ts

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
/**
2+
* Builds and reads a micro:bit MicroPython File System from Intel Hex data.
3+
*
4+
* Follows this implementation:
5+
* https://github.com/bbcmicrobit/micropython/blob/v1.0.1/source/microbit/filesystem.c
6+
*
7+
* How it works:
8+
* The File system size is calculated based on the UICR data addded to the
9+
* MicroPython final hex to determine the limits of the filesystem space.
10+
* Based on how many space there is available it calculates how many free
11+
* chunks it can fit, each chunk being of CHUNK_LEN size in bytes.
12+
* There is one spare page which holds persistent configuration data that is
13+
* used by MicroPython for bulk erasing, so we also mark it as such here.
14+
*
15+
* Each chunk is enumerated with an index number. The first chunk starts with
16+
* index 1 (as value 0 is reserved to indicate a Freed chunk) at the bottom of
17+
* the File System (lowest address), and the indexes increase sequentially.
18+
* Each chunk consists of a one byte marker at the head and a one tail byte.
19+
* The byte at the tail is a pointer to the next chunk index.
20+
* The head byte marker is either one of the values in the ChunkMarker enum, to
21+
* indicate the a special type of chunk, or a pointer to the previous chunk
22+
* index.
23+
* The special markers indicate whether the chunk is the start of a file, if it
24+
* is Unused, if it is Freed (same as unused, but not yet erased) or if this
25+
* is the start of a flash page used for Persistent Data (bulk erase operation).
26+
*
27+
* A file consists of a double linked list of chunks. The first chunk in a
28+
* file, indicated by the FileStart marker, contains the data end offset for
29+
* the last chunk and the file name.
30+
*/
131
import MemoryMap from 'nrf-intel-hex';
232

333
import {
@@ -167,37 +197,14 @@ class FsFile {
167197
}
168198
this._dataBytes = data;
169199
// Generate a single byte array with the filesystem data bytes.
170-
const fileHeader = this.generateFileHeaderBytes();
200+
const fileHeader = this._generateFileHeaderBytes();
171201
this._fsDataBytes = new Uint8Array(
172202
fileHeader.length + this._dataBytes.length
173203
);
174204
this._fsDataBytes.set(fileHeader, 0);
175205
this._fsDataBytes.set(this._dataBytes, fileHeader.length);
176206
}
177207

178-
/**
179-
* Generates a byte array for the file header as expected by the MicroPython
180-
* file system.
181-
*
182-
* @return Byte array with the header data.
183-
*/
184-
generateFileHeaderBytes(): Uint8Array {
185-
const headerSize =
186-
CHUNK_HEADER_END_OFFSET_LEN +
187-
CHUNK_HEADER_NAME_LEN +
188-
this._filenameBytes.length;
189-
const endOffset = (headerSize + this._dataBytes.length) % CHUNK_DATA_LEN;
190-
const fileNameOffset: number = headerSize - this._filenameBytes.length;
191-
// Format header byte array
192-
const headerBytes: Uint8Array = new Uint8Array(headerSize);
193-
headerBytes[ChunkFormatIndex.EndOffset - 1] = endOffset;
194-
headerBytes[ChunkFormatIndex.NameLength - 1] = this._filenameBytes.length;
195-
for (let i = fileNameOffset; i < headerSize; ++i) {
196-
headerBytes[i] = this._filenameBytes[i - fileNameOffset];
197-
}
198-
return headerBytes;
199-
}
200-
201208
/**
202209
* Generate an array of file system chunks for all this file content.
203210
*
@@ -272,6 +279,29 @@ class FsFile {
272279
}
273280
return chunksUsed * CHUNK_LEN;
274281
}
282+
283+
/**
284+
* Generates a byte array for the file header as expected by the MicroPython
285+
* file system.
286+
*
287+
* @return Byte array with the header data.
288+
*/
289+
private _generateFileHeaderBytes(): Uint8Array {
290+
const headerSize =
291+
CHUNK_HEADER_END_OFFSET_LEN +
292+
CHUNK_HEADER_NAME_LEN +
293+
this._filenameBytes.length;
294+
const endOffset = (headerSize + this._dataBytes.length) % CHUNK_DATA_LEN;
295+
const fileNameOffset: number = headerSize - this._filenameBytes.length;
296+
// Format header byte array
297+
const headerBytes: Uint8Array = new Uint8Array(headerSize);
298+
headerBytes[ChunkFormatIndex.EndOffset - 1] = endOffset;
299+
headerBytes[ChunkFormatIndex.NameLength - 1] = this._filenameBytes.length;
300+
for (let i = fileNameOffset; i < headerSize; ++i) {
301+
headerBytes[i] = this._filenameBytes[i - fileNameOffset];
302+
}
303+
return headerBytes;
304+
}
275305
}
276306

277307
/**

0 commit comments

Comments
 (0)