Skip to content

Commit 5361a6b

Browse files
Merge pull request #26 from microbit-foundation/new-device
Add support for MicroPython for the new micro:bit
2 parents cb2393c + c8d43bf commit 5361a6b

20 files changed

+54904
-519
lines changed

docs/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ nav_order: 1
99
# micro:bit Filesystem
1010
{: .fs-9 }
1111

12-
<img alt="microbit-fs logo" src="img/microbit-fs-logo.png" style="max-height: 100px; float: left; padding-right: 16px;">
12+
<img alt="microbit-fs logo" src="img/microbit-fs-logo.png" style="max-height: 125px; float: left; padding-right: 16px;">
1313

1414
Manipulate files in a micro:bit MicroPython Intel Hex file.
1515
{: .fs-6 .fw-300 }

docs/quick-guide.md

+39-11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Initialise a File System instance with a MicroPython Intel Hex string and start
1414
```js
1515
// Create a new FileSystem instance passing the MicroPython Intel Hex string
1616
var micropythonFs = new microbitFs.MicropythonFsHex(IntelHexStr);
17+
// There are some options available in the constructor
18+
micropythonFs = new microbitFs.MicropythonFsHex(IntelHexStr, { maxFsSize: 20 * 1024});
1719

1820
// Import files from a different MicroPython hex file with filesystem
1921
var addedFilenames = micropythonFs.importFilesFromIntelHex(UploadedHexWithUserFiles);
@@ -45,7 +47,31 @@ var intelHexStrWithFs = micropythonFs.getIntelHex();
4547
var intelHexBytesWithFs = micropythonFs.getIntelHexBytes();
4648
```
4749

48-
Public interface can be found in the `src/fs-interface.ts` file.
50+
Using multiple MicroPython Intel Hex files to generate a Universal Hex:
51+
52+
```js
53+
// Create a new FileSystem instance passing the MicroPython Intel Hex string
54+
var micropythonFs = new microbitFs.MicropythonFsHex([
55+
{ hex: uPy1HexFile, boardId: 0x9900 },
56+
{ hex: uPy2HexFile, boardId: 0x9903 },
57+
]);;
58+
59+
// Import files from a different MicroPython Intel hex file with filesystem
60+
var addedFilenames = micropythonFs.importFilesFromIntelHex(UploadedHexWithUserFiles);
61+
addedFilenames = micropythonFs.importFilesFromIntelHex(UploadedHexWithUserFiles, {overwrite: false, formatFirst: false});
62+
63+
// Generate a new Intel hex string or Uint8Array with MicroPython and the files
64+
var uPy1IntelHexStrWithFs = micropythonFs.getIntelHex(0x9900);
65+
var uPy1IntelHexBytesWithFs = micropythonFs.getIntelHexBytes(0x9900);
66+
var uPy2IntelHexStrWithFs = micropythonFs.getIntelHex(0x9903);
67+
var uPy2IntelHexBytesWithFs = micropythonFs.getIntelHexBytes(0x9903);
68+
69+
// Generate a new Universal hex string with all MicroPython+files data
70+
var universalHexStrWithFs = micropythonFs.getUniversalHex();
71+
```
72+
73+
The `MicropythonFsHex` class public interface can be found in the
74+
`src/fs-interface.ts` file.
4975

5076
### Append and extract Python code from known flash location
5177
To add and remove the Python code using the old format:
@@ -57,16 +83,18 @@ if (microbitFs.isAppendedScriptPresent(finalHexStr)) {
5783
}
5884
```
5985

60-
### Read UICR data
86+
### Read Device Memory Info data
6187

6288
```js
63-
var uicrData = getIntelHexUicrData(IntelHexStr);
64-
console.log('Flash Page Size:' + uicrData.flashPageSize);
65-
console.log('Flash Size:' + uicrData.flashSize);
66-
console.log('Runtime Start Page:' + uicrData.runtimeStartPage);
67-
console.log('Runtime Start Address:' + uicrData.runtimeStartAddress);
68-
console.log('Runtime End Used:' + uicrData.runtimeEndUsed);
69-
console.log('Runtime End Address:' + uicrData.runtimeEndAddress);
70-
console.log('Version Address:' + uicrData.versionAddress);
71-
console.log('Version: ' + uicrData.version);
89+
var deviceMemInfoData = getIntelHexDeviceMemInfo(IntelHexStr);
90+
console.log('Flash Page Size:' + deviceMemInfoData.flashPageSize);
91+
console.log('Flash Size:' + deviceMemInfoData.flashSize);
92+
console.log('Flash Start Address:' + deviceMemInfoData.flashStartAddress);
93+
console.log('Flash End Address:' + deviceMemInfoData.flashEndAddress);
94+
console.log('Runtime Start Address:' + deviceMemInfoData.runtimeStartAddress);
95+
console.log('Runtime End Address:' + deviceMemInfoData.runtimeEndAddress);
96+
console.log('Filesystem Start Address:' + deviceMemInfoData.fsStartAddress);
97+
console.log('Filesystem End Address:' + deviceMemInfoData.fsEndAddress);
98+
console.log('MicroPython Version:' + deviceMemInfoData.uPyVersion);
99+
console.log('Device Version: ' + deviceMemInfoData.deviceVersion);
72100
```

package-lock.json

+7-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"tslib": ">=1.9.0"
4949
},
5050
"dependencies": {
51+
"@microbit/microbit-universal-hex": "0.2.1",
5152
"nrf-intel-hex": "1.3.0",
5253
"text-encoder-lite": "2.0.0"
5354
},

src/__tests__/common.spec.ts

+103-9
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22
* (c) 2019 Micro:bit Educational Foundation and the microbit-fs contributors.
33
* SPDX-License-Identifier: MIT
44
*/
5-
import { bytesToStr, strToBytes } from '../common';
5+
import {
6+
bytesToStr,
7+
strToBytes,
8+
concatUint8Array,
9+
areUint8ArraysEqual,
10+
} from '../common';
611

7-
describe(`strToBytes`, () => {
8-
it(`works with 1 byte characters`, () => {
12+
describe('strToBytes', () => {
13+
it('works with 1 byte characters', () => {
914
const testString = 'test';
1015
const testCodes = [116, 101, 115, 116];
1116

@@ -15,7 +20,8 @@ describe(`strToBytes`, () => {
1520
expect(tester.next().value).toEqual(code);
1621
}
1722
});
18-
it(`works with 2 byte characters`, () => {
23+
24+
it('works with 2 byte characters', () => {
1925
const testString = 'Ση';
2026
const testCodes = [206, 163, 206, 183];
2127

@@ -25,7 +31,8 @@ describe(`strToBytes`, () => {
2531
expect(tester.next().value).toEqual(code);
2632
}
2733
});
28-
it(`works with 3 byte characters`, () => {
34+
35+
it('works with 3 byte characters', () => {
2936
const testString = '世';
3037
const testCodes = [228, 184, 150];
3138

@@ -37,20 +44,107 @@ describe(`strToBytes`, () => {
3744
});
3845
});
3946

40-
describe(`bytesToStr`, () => {
41-
it(`works with 1 byte characters`, () => {
47+
describe('bytesToStr', () => {
48+
it('works with 1 byte characters', () => {
4249
const testCodes: Uint8Array = new Uint8Array([116, 101, 115, 116]);
4350

4451
expect(bytesToStr(testCodes)).toEqual('test');
4552
});
46-
it(`works with 2 byte characters`, () => {
53+
54+
it('works with 2 byte characters', () => {
4755
const testCodes: Uint8Array = new Uint8Array([206, 163, 206, 183]);
4856

4957
expect(bytesToStr(testCodes)).toEqual('Ση');
5058
});
51-
it(`works with 3 byte characters`, () => {
59+
60+
it('works with 3 byte characters', () => {
5261
const testCodes: Uint8Array = new Uint8Array([228, 184, 150]);
5362

5463
expect(bytesToStr(testCodes)).toEqual('世');
5564
});
5665
});
66+
67+
describe('concatUint8Array', () => {
68+
it('concatenates correctly', () => {
69+
const firstArray = [116, 101, 115, 116];
70+
const secondArray = [234, 56, 45, 98];
71+
const first: Uint8Array = new Uint8Array(firstArray);
72+
const second: Uint8Array = new Uint8Array(secondArray);
73+
74+
const result1 = concatUint8Array(first, first);
75+
const result2 = concatUint8Array(second, second);
76+
const result3 = concatUint8Array(first, second);
77+
78+
expect(result1).toEqual(new Uint8Array(firstArray.concat(firstArray)));
79+
expect(result2).toEqual(new Uint8Array(secondArray.concat(secondArray)));
80+
expect(result3).toEqual(new Uint8Array(firstArray.concat(secondArray)));
81+
});
82+
83+
it('concatenates correctly empty arrays', () => {
84+
const first: Uint8Array = new Uint8Array([]);
85+
const second: Uint8Array = new Uint8Array([]);
86+
87+
const result = concatUint8Array(first, second);
88+
89+
expect(result).toEqual(new Uint8Array([]));
90+
});
91+
92+
it('concatenates arrays of different length', () => {
93+
const firstArray = [116, 101, 115, 116];
94+
const secondArray = [234, 56, 45, 98, 0];
95+
const first: Uint8Array = new Uint8Array(firstArray);
96+
const second: Uint8Array = new Uint8Array(secondArray);
97+
98+
const result1 = concatUint8Array(first, second);
99+
const result2 = concatUint8Array(second, first);
100+
101+
expect(result1).toEqual(new Uint8Array(firstArray.concat(secondArray)));
102+
expect(result2).toEqual(new Uint8Array(secondArray.concat(firstArray)));
103+
});
104+
});
105+
106+
describe('areUint8ArraysEqual', () => {
107+
it('compares correctly equal arrays', () => {
108+
const first: Uint8Array = new Uint8Array([116, 101, 115, 116]);
109+
const second: Uint8Array = new Uint8Array([116, 101, 115, 116]);
110+
111+
const result1 = areUint8ArraysEqual(first, first);
112+
const result2 = areUint8ArraysEqual(second, second);
113+
const result3 = areUint8ArraysEqual(first, second);
114+
115+
expect(result1).toBeTruthy();
116+
expect(result2).toBeTruthy();
117+
expect(result3).toBeTruthy();
118+
});
119+
120+
it('compares correctly empty arrays', () => {
121+
const first: Uint8Array = new Uint8Array([]);
122+
const second: Uint8Array = new Uint8Array([]);
123+
124+
const result = areUint8ArraysEqual(first, second);
125+
126+
expect(result).toBeTruthy();
127+
});
128+
129+
it('compares arrays of different length', () => {
130+
const first: Uint8Array = new Uint8Array([5, 12, 46]);
131+
const second: Uint8Array = new Uint8Array([5, 12, 46, 0]);
132+
133+
const result1 = areUint8ArraysEqual(first, second);
134+
const result2 = areUint8ArraysEqual(second, first);
135+
136+
expect(result1).toBeFalsy();
137+
expect(result2).toBeFalsy();
138+
});
139+
140+
it('compares different arrays', () => {
141+
const first: Uint8Array = new Uint8Array([1, 2, 3]);
142+
const second: Uint8Array = new Uint8Array([4, 5, 6]);
143+
144+
const result1 = areUint8ArraysEqual(first, second);
145+
const result2 = areUint8ArraysEqual(second, first);
146+
147+
expect(result1).toBeFalsy();
148+
expect(result2).toBeFalsy();
149+
});
150+
});

src/__tests__/flash-regions.spec.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* (c) 2019 Micro:bit Educational Foundation and the microbit-fs contributors.
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
import * as fs from 'fs';
6+
7+
import * as flashRegions from '../flash-regions';
8+
9+
describe('Read MicroPython UICR data.', () => {
10+
const uPyHexFile = fs.readFileSync(
11+
'./src/__tests__/upy-v2-beta-region.hex',
12+
'utf8'
13+
);
14+
15+
it('Read MicroPython v2-beta-region hex file flash regions table', () => {
16+
const expectedPageSize = 4096;
17+
const expectedFlashSize = 512 * 1024;
18+
const MicroPythonLastByteUsed = 0x61f24;
19+
const expectedRuntimeEndPage = Math.ceil(
20+
MicroPythonLastByteUsed / expectedPageSize
21+
);
22+
const expectedFsStartAddress = 0x6d000;
23+
const expectedFsEndAddress = 0x73000;
24+
const expectedUpyVersion =
25+
'micro:bit v2.0.99+b260810 on 2020-11-17; ' +
26+
'MicroPython b260810 on 2020-11-17';
27+
28+
const result = flashRegions.getIntelHexFlashRegionsData(uPyHexFile);
29+
30+
expect(result.flashPageSize).toEqual(expectedPageSize);
31+
expect(result.flashSize).toEqual(expectedFlashSize);
32+
expect(result.flashStartAddress).toEqual(0);
33+
expect(result.flashEndAddress).toEqual(expectedFlashSize);
34+
expect(result.runtimeStartAddress).toEqual(0);
35+
expect(result.runtimeEndAddress).toEqual(
36+
expectedRuntimeEndPage * expectedPageSize
37+
);
38+
expect(result.fsStartAddress).toEqual(expectedFsStartAddress);
39+
expect(result.fsEndAddress).toEqual(expectedFsEndAddress);
40+
expect(result.uPyVersion).toEqual(expectedUpyVersion);
41+
expect(result.deviceVersion).toEqual(2);
42+
});
43+
});

0 commit comments

Comments
 (0)