Skip to content

Commit b25113a

Browse files
Add filesystem limit. (#55)
- Limit approximately matches the device and prevents running out of space. - Allow flash to exceed limit to avoid new error scenario. This would be good to revisit in future. - Fix broken listdir due to missing Module prefix. - Align flash and reset behaviour. Closes microbit-foundation/python-editor-v3#950
1 parent 9c9f107 commit b25113a

File tree

6 files changed

+56
-20
lines changed

6 files changed

+56
-20
lines changed

src/board/fs.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
// Size as per C implementation.
2+
const maxSize = 31.5 * 1024;
3+
14
export class FileSystem {
25
// Each entry is an FsFile object. The indexes are used as identifiers.
36
// When a file is deleted the entry becomes ['', null] and can be reused.
47
private _content: Array<FsFile | null> = [];
8+
private _size = 0;
59

610
create(name: string) {
711
let free_idx = -1;
@@ -49,21 +53,29 @@ export class FileSystem {
4953
}
5054

5155
remove(idx: number) {
52-
this._content[idx] = null;
56+
const file = this._content[idx];
57+
if (file) {
58+
this._size -= file.size();
59+
this._content[idx] = null;
60+
}
5361
}
5462

5563
readbyte(idx: number, offset: number) {
5664
const file = this._content[idx];
5765
return file ? file.readbyte(offset) : -1;
5866
}
5967

60-
write(idx: number, data: Uint8Array) {
68+
write(idx: number, data: Uint8Array, force: boolean = false): boolean {
6169
const file = this._content[idx];
6270
if (!file) {
6371
throw new Error("File must exist");
6472
}
73+
if (!force && this._size + data.length > maxSize) {
74+
return false;
75+
}
76+
this._size += data.length;
6577
file.append(data);
66-
return data.length;
78+
return true;
6779
}
6880

6981
clear() {

src/board/index.ts

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,10 @@ export class Board {
8282
*/
8383
private modulePromise: Promise<ModuleWrapper> | undefined;
8484
/**
85-
* Flag to trigger a reset after start finishes.
85+
* If undefined, then when main finishes we stay stopped.
86+
* Otherwise we perform the action then clear this field.
8687
*/
87-
private resetWhenDone: boolean = false;
88+
private afterStopped: (() => void) | undefined;
8889

8990
constructor(
9091
private notifications: Notifications,
@@ -339,17 +340,20 @@ export class Board {
339340
if (panicCode !== undefined) {
340341
this.displayPanic(panicCode);
341342
} else {
342-
if (this.resetWhenDone) {
343-
this.resetWhenDone = false;
343+
if (this.afterStopped) {
344+
this.afterStopped();
345+
this.afterStopped = undefined;
344346
setTimeout(() => this.start(), 0);
345347
} else {
346348
this.displayStoppedState();
347349
}
348350
}
349351
}
350352

351-
async stop(reset: boolean = false): Promise<void> {
352-
this.resetWhenDone = reset;
353+
async stop(
354+
afterStopped: (() => void) | undefined = undefined
355+
): Promise<void> {
356+
this.afterStopped = afterStopped;
353357
if (this.panicTimeout) {
354358
clearTimeout(this.panicTimeout);
355359
this.panicTimeout = null;
@@ -366,17 +370,24 @@ export class Board {
366370
}
367371

368372
async reset(): Promise<void> {
369-
this.stop(true);
373+
const noChangeRestart = () => {};
374+
this.stop(noChangeRestart);
370375
}
371376

372377
async flash(filesystem: Record<string, Uint8Array>): Promise<void> {
373-
await this.stop();
374-
this.fs.clear();
375-
Object.entries(filesystem).forEach(([name, value]) => {
376-
const idx = this.fs.create(name);
377-
this.fs.write(idx, value);
378-
});
379-
this.dataLogging.delete();
378+
const flashFileSystem = () => {
379+
this.fs.clear();
380+
Object.entries(filesystem).forEach(([name, value]) => {
381+
const idx = this.fs.create(name);
382+
this.fs.write(idx, value, true);
383+
});
384+
this.dataLogging.delete();
385+
};
386+
if (this.modulePromise) {
387+
// If it's running then we need to stop before flash.
388+
return this.stop(flashFileSystem);
389+
}
390+
flashFileSystem();
380391
return this.start();
381392
}
382393

src/demo.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,14 @@ <h1>MicroPython-micro:bit simulator example embedding</h1>
197197
);
198198
break;
199199
}
200+
case "internal_error": {
201+
console.error("Simulator internal error:");
202+
console.error(e.data.error);
203+
break;
204+
}
205+
default: {
206+
// Ignore unknown message
207+
}
200208
}
201209
}
202210
});

src/jshal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ int mp_js_hal_filesystem_name(int idx, char *buf);
3737
int mp_js_hal_filesystem_size(int idx);
3838
void mp_js_hal_filesystem_remove(int idx);
3939
int mp_js_hal_filesystem_readbyte(int idx, size_t offset);
40-
int mp_js_hal_filesystem_write(int idx, const char *buf, size_t len);
40+
bool mp_js_hal_filesystem_write(int idx, const char *buf, size_t len);
4141

4242
void mp_js_hal_panic(int code);
4343
void mp_js_hal_reset(void);

src/jshal.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ mergeInto(LibraryManager.library, {
5656
},
5757

5858
mp_js_hal_filesystem_name: function (idx, buf) {
59-
const name = fs.name(idx);
59+
const name = Module.fs.name(idx);
6060
if (name === undefined) {
6161
return -1;
6262
}

src/microbitfs.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,12 @@ STATIC mp_uint_t microbit_file_write(mp_obj_t self_in, const void *buf, mp_uint_
209209
*errcode = MP_EBADF;
210210
return MP_STREAM_ERROR;
211211
}
212-
return mp_js_hal_filesystem_write(self->idx, buf, size);
212+
bool success = mp_js_hal_filesystem_write(self->idx, buf, size);
213+
if (!success) {
214+
*errcode = MP_ENOSPC;
215+
return MP_STREAM_ERROR;
216+
}
217+
return size;
213218
}
214219

215220
STATIC mp_uint_t microbit_file_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {

0 commit comments

Comments
 (0)