Skip to content

Commit 501aac6

Browse files
committed
Make SD cards available over web workflow
This changes storage.mount() to require that a mount point exist on the parent file system. A bug in background tasks is also fixed where the function parameter is cleared on pending callbacks during "reset". Disk usage is shown on the directory listing and changes based on the mounted file system. Writable is also loaded per-directory. Fixes micropython#8108. Fixes micropython#8690. Fixes micropython#8107.
1 parent 156f417 commit 501aac6

File tree

18 files changed

+317
-126
lines changed

18 files changed

+317
-126
lines changed

docs/workflows.md

+26-11
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,13 @@ Returns a JSON representation of the directory.
165165
* `403 Forbidden` - No `CIRCUITPY_WEB_API_PASSWORD` set
166166
* `404 Not Found` - Missing directory
167167

168+
Returns directory information:
169+
* `free`: Count of free blocks on the disk holding this directory.
170+
* `total`: Total blocks that make up the disk holding this directory.
171+
* `block_size`: Size of a block in bytes.
172+
* `writable`: True when CircuitPython and the web workflow can write to the disk. USB may claim a disk instead.
173+
* `files`: Array of objects. One for each file.
174+
168175
Returns information about each file in the directory:
169176

170177
* `name` - File name. No trailing `/` on directory names
@@ -179,14 +186,20 @@ curl -v -u :passw0rd -H "Accept: application/json" -L --location-trusted http://
179186
```
180187

181188
```json
182-
[
183-
{
184-
"name": "world.txt",
185-
"directory": false,
186-
"modified_ns": 946934328000000000,
187-
"file_size": 12
188-
}
189-
]
189+
{
190+
"free": 451623,
191+
"total": 973344,
192+
"block_size": 32768,
193+
"writable": true,
194+
"files": [
195+
{
196+
"name": "world.txt",
197+
"directory": false,
198+
"modified_ns": 946934328000000000,
199+
"file_size": 12
200+
}
201+
]
202+
}
190203
```
191204

192205
##### PUT
@@ -373,10 +386,10 @@ curl -v -L http://circuitpython.local/cp/devices.json
373386
Returns information about the attached disk(s). A list of objects, one per disk.
374387

375388
* `root`: Filesystem path to the root of the disk.
376-
* `free`: Count of free bytes on the disk.
389+
* `free`: Count of free blocks on the disk.
390+
* `total`: Total blocks that make up the disk.
377391
* `block_size`: Size of a block in bytes.
378392
* `writable`: True when CircuitPython and the web workflow can write to the disk. USB may claim a disk instead.
379-
* `total`: Total bytes that make up the disk.
380393

381394
Example:
382395
```sh
@@ -405,7 +418,7 @@ This is an authenticated endpoint in both modes.
405418

406419
Returns information about the device.
407420

408-
* `web_api_version`: Between `1` and `3`. This versions the rest of the API and new versions may not be backwards compatible. See below for more info.
421+
* `web_api_version`: Between `1` and `4`. This versions the rest of the API and new versions may not be backwards compatible. See below for more info.
409422
* `version`: CircuitPython build version.
410423
* `build_date`: CircuitPython build date.
411424
* `board_name`: Human readable name of the board.
@@ -467,3 +480,5 @@ Only one WebSocket at a time is supported.
467480
* `1` - Initial version.
468481
* `2` - Added `/cp/diskinfo.json`.
469482
* `3` - Changed `/cp/diskinfo.json` to return a list in preparation for multi-disk support.
483+
* `4` - Changed directory json to an object with additional data. File list is under `files` and is
484+
the same as the old format.

extmod/vfs_blockdev.c

+42-4
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,41 @@
3030
#include "py/mperrno.h"
3131
#include "extmod/vfs.h"
3232

33+
#if CIRCUITPY_SDCARDIO
34+
#include "shared-bindings/sdcardio/SDCard.h"
35+
#endif
36+
#if CIRCUITPY_SDIOIO
37+
#include "shared-bindings/sdioio/SDCard.h"
38+
#endif
39+
40+
3341
#if MICROPY_VFS
3442

3543
void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) {
3644
mp_load_method(bdev, MP_QSTR_readblocks, self->readblocks);
3745
mp_load_method_maybe(bdev, MP_QSTR_writeblocks, self->writeblocks);
3846
mp_load_method_maybe(bdev, MP_QSTR_ioctl, self->u.ioctl);
47+
48+
// CIRCUITPY-CHANGE: Support native SD cards.
49+
#if CIRCUITPY_SDCARDIO
50+
if (mp_obj_get_type(bdev) == &sdcardio_SDCard_type) {
51+
self->flags |= MP_BLOCKDEV_FLAG_NATIVE | MP_BLOCKDEV_FLAG_HAVE_IOCTL;
52+
self->readblocks[0] = mp_const_none;
53+
self->readblocks[1] = bdev;
54+
self->readblocks[2] = (mp_obj_t)sdcardio_sdcard_readblocks; // native version
55+
self->writeblocks[0] = mp_const_none;
56+
self->writeblocks[1] = bdev;
57+
self->writeblocks[2] = (mp_obj_t)sdcardio_sdcard_writeblocks; // native version
58+
self->u.ioctl[0] = mp_const_none;
59+
self->u.ioctl[1] = bdev;
60+
self->u.ioctl[2] = (mp_obj_t)sdcardio_sdcard_ioctl; // native version
61+
}
62+
#endif
63+
#if CIRCUITPY_SDIOIO
64+
if (mp_obj_get_type(bdev) == &sdioio_SDCard_type) {
65+
// TODO: Enable native blockdev for SDIO too.
66+
}
67+
#endif
3968
if (self->u.ioctl[0] != MP_OBJ_NULL) {
4069
// Device supports new block protocol, so indicate it
4170
self->flags |= MP_BLOCKDEV_FLAG_HAVE_IOCTL;
@@ -48,8 +77,8 @@ void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) {
4877

4978
int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf) {
5079
if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) {
51-
mp_uint_t (*f)(uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->readblocks[2];
52-
return f(buf, block_num, num_blocks);
80+
mp_uint_t (*f)(mp_obj_t self, uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->readblocks[2];
81+
return f(self->readblocks[1], buf, block_num, num_blocks);
5382
} else {
5483
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, num_blocks *self->block_size, buf};
5584
self->readblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num);
@@ -80,8 +109,8 @@ int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_
80109
}
81110

82111
if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) {
83-
mp_uint_t (*f)(const uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->writeblocks[2];
84-
return f(buf, block_num, num_blocks);
112+
mp_uint_t (*f)(mp_obj_t self, const uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->writeblocks[2];
113+
return f(self->writeblocks[1], buf, block_num, num_blocks);
85114
} else {
86115
mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, num_blocks *self->block_size, (void *)buf};
87116
self->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num);
@@ -112,6 +141,15 @@ int mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t
112141

113142
mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg) {
114143
if (self->flags & MP_BLOCKDEV_FLAG_HAVE_IOCTL) {
144+
if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) {
145+
size_t out_value;
146+
bool (*f)(mp_obj_t self, uint32_t, uint32_t, size_t *) = (void *)(uintptr_t)self->u.ioctl[2];
147+
bool b = f(self->u.ioctl[1], cmd, arg, &out_value);
148+
if (!b) {
149+
return mp_const_none;
150+
}
151+
return MP_OBJ_NEW_SMALL_INT(out_value);
152+
}
115153
// New protocol with ioctl
116154
self->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(cmd);
117155
self->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(arg);

locale/circuitpython.pot

+4
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,10 @@ msgstr ""
13641364
msgid "Missing jmp_pin. %q[%u] jumps on pin"
13651365
msgstr ""
13661366

1367+
#: shared-module/storage/__init__.c
1368+
msgid "Mount point missing. Create first (maybe via USB)"
1369+
msgstr ""
1370+
13671371
#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c
13681372
msgid "Must be a %q subclass."
13691373
msgstr ""

ports/espressif/supervisor/internal_flash.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ STATIC uint32_t _cache_lba = 0xffffffff;
6060
#define SECSIZE(fs) ((fs)->ssize)
6161
#endif // FF_MAX_SS == FF_MIN_SS
6262
STATIC DWORD fatfs_bytes(void) {
63-
FATFS *fatfs = filesystem_circuitpy();
63+
fs_user_mount_t *fs_mount = filesystem_circuitpy();
64+
FATFS *fatfs = &fs_mount->fatfs;
6465
return (fatfs->csize * SECSIZE(fatfs)) * (fatfs->n_fatent - 2);
6566
}
6667
STATIC bool storage_extended = true;

shared-bindings/sdcardio/SDCard.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_deinit_obj, sdcardio_sdcard_deinit);
131131
//|
132132
//| :return: None"""
133133

134-
STATIC mp_obj_t sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
134+
STATIC mp_obj_t _sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
135135
uint32_t start_block = mp_obj_get_int(start_block_in);
136136
mp_buffer_info_t bufinfo;
137137
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
@@ -143,7 +143,7 @@ STATIC mp_obj_t sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_bloc
143143
return mp_const_none;
144144
}
145145

146-
MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, sdcardio_sdcard_readblocks);
146+
MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, _sdcardio_sdcard_readblocks);
147147

148148
//| def sync(self) -> None:
149149
//| """Ensure all blocks written are actually committed to the SD card
@@ -171,7 +171,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_sync_obj, sdcardio_sdcard_sync);
171171
//| :return: None"""
172172
//|
173173

174-
STATIC mp_obj_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
174+
STATIC mp_obj_t _sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
175175
uint32_t start_block = mp_obj_get_int(start_block_in);
176176
mp_buffer_info_t bufinfo;
177177
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
@@ -182,7 +182,7 @@ STATIC mp_obj_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_blo
182182
}
183183
return mp_const_none;
184184
}
185-
MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, sdcardio_sdcard_writeblocks);
185+
MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, _sdcardio_sdcard_writeblocks);
186186

187187
STATIC const mp_rom_map_elem_t sdcardio_sdcard_locals_dict_table[] = {
188188
{ MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdcardio_sdcard_count_obj) },

shared-bindings/sdcardio/SDCard.h

+15
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,19 @@
2727

2828
#pragma once
2929

30+
#include "shared-module/sdcardio/SDCard.h"
31+
3032
extern const mp_obj_type_t sdcardio_SDCard_type;
33+
34+
void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *cs, int baudrate);
35+
void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self);
36+
void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self);
37+
int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self);
38+
int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf);
39+
int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self);
40+
int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf);
41+
42+
// Used by native vfs blockdev.
43+
mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen);
44+
mp_uint_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen);
45+
bool sdcardio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *out_value);

shared-bindings/sdioio/SDCard.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_count_obj, sdioio_sdcard_count);
164164
//| :param ~circuitpython_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512.
165165
//|
166166
//| :return: None"""
167-
STATIC mp_obj_t sdioio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
167+
STATIC mp_obj_t _sdioio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
168168
uint32_t start_block = mp_obj_get_int(start_block_in);
169169
mp_buffer_info_t bufinfo;
170170
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
@@ -176,7 +176,7 @@ STATIC mp_obj_t sdioio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_
176176
return mp_const_none;
177177
}
178178

179-
MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_readblocks_obj, sdioio_sdcard_readblocks);
179+
MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_readblocks_obj, _sdioio_sdcard_readblocks);
180180

181181
//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None:
182182
//| """Write one or more blocks to the card
@@ -185,7 +185,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_readblocks_obj, sdioio_sdcard_readblocks
185185
//| :param ~circuitpython_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512.
186186
//|
187187
//| :return: None"""
188-
STATIC mp_obj_t sdioio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
188+
STATIC mp_obj_t _sdioio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) {
189189
uint32_t start_block = mp_obj_get_int(start_block_in);
190190
mp_buffer_info_t bufinfo;
191191
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
@@ -197,7 +197,7 @@ STATIC mp_obj_t sdioio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block
197197
return mp_const_none;
198198
}
199199

200-
MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_writeblocks_obj, sdioio_sdcard_writeblocks);
200+
MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_writeblocks_obj, _sdioio_sdcard_writeblocks);
201201

202202
//| frequency: int
203203
//| """The actual SDIO bus frequency. This may not match the frequency

shared-module/os/getenv.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,12 @@ STATIC bool open_file(const char *name, file_arg *active_file) {
6262
return false;
6363
}
6464
#else
65-
FATFS *fs = filesystem_circuitpy();
66-
FRESULT result = f_open(fs, active_file, name, FA_READ);
65+
fs_user_mount_t *fs_mount = filesystem_circuitpy();
66+
if (fs_mount == NULL) {
67+
return false;
68+
}
69+
FATFS *fatfs = &fs_mount->fatfs;
70+
FRESULT result = f_open(fatfs, active_file, name, FA_READ);
6771
return result == FR_OK;
6872
#endif
6973
}

0 commit comments

Comments
 (0)