Skip to content

Commit 7e4b2a0

Browse files
authored
Merge pull request #7000 from MicroDev1/storage-extend
Add Storage Extension Support
2 parents 2ebb45d + 728fea4 commit 7e4b2a0

File tree

10 files changed

+175
-28
lines changed

10 files changed

+175
-28
lines changed

locale/circuitpython.pot

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ msgstr ""
117117
msgid "%q init failed"
118118
msgstr ""
119119

120+
#: shared-bindings/dualbank/__init__.c
121+
msgid "%q is %q"
122+
msgstr ""
123+
120124
#: py/argcheck.c
121125
msgid "%q length must be %d"
122126
msgstr ""
@@ -211,7 +215,7 @@ msgstr ""
211215
msgid "%q, %q, and %q must all be the same length"
212216
msgstr ""
213217

214-
#: py/objint.c
218+
#: py/objint.c shared-bindings/storage/__init__.c
215219
msgid "%q=%q"
216220
msgstr ""
217221

ports/espressif/common-hal/dualbank/__init__.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include "esp_log.h"
3333
#include "esp_ota_ops.h"
3434

35+
#include "supervisor/flash.h"
36+
3537
static const esp_partition_t *update_partition = NULL;
3638
static esp_ota_handle_t update_handle = 0;
3739

ports/espressif/supervisor/internal_flash.c

Lines changed: 104 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2525
* THE SOFTWARE.
2626
*/
27+
2728
#include "supervisor/internal_flash.h"
2829

2930
#include <stdint.h>
@@ -32,47 +33,114 @@
3233

3334
#include "extmod/vfs.h"
3435
#include "extmod/vfs_fat.h"
36+
3537
#include "py/mphal.h"
3638
#include "py/obj.h"
3739
#include "py/runtime.h"
38-
#include "lib/oofatfs/ff.h"
3940

40-
#include "components/spi_flash/include/esp_partition.h"
41+
#include "esp_ota_ops.h"
42+
#include "esp_partition.h"
4143

44+
#include "supervisor/filesystem.h"
4245
#include "supervisor/flash.h"
4346
#include "supervisor/usb.h"
4447

45-
STATIC const esp_partition_t *_partition;
48+
#define OP_READ 0
49+
#define OP_WRITE 1
4650

4751
// TODO: Split the caching out of supervisor/shared/external_flash so we can use it.
4852
#define SECTOR_SIZE 4096
4953
STATIC uint8_t _cache[SECTOR_SIZE];
5054
STATIC uint32_t _cache_lba = 0xffffffff;
5155

56+
#if CIRCUITPY_STORAGE_EXTEND
57+
#if FF_MAX_SS == FF_MIN_SS
58+
#define SECSIZE(fs) (FF_MIN_SS)
59+
#else
60+
#define SECSIZE(fs) ((fs)->ssize)
61+
#endif // FF_MAX_SS == FF_MIN_SS
62+
STATIC DWORD fatfs_bytes(void) {
63+
FATFS *fatfs = filesystem_circuitpy();
64+
return (fatfs->csize * SECSIZE(fatfs)) * (fatfs->n_fatent - 2);
65+
}
66+
STATIC bool storage_extended = true;
67+
STATIC const esp_partition_t *_partition[2];
68+
#else
69+
STATIC const esp_partition_t *_partition[1];
70+
#endif // CIRCUITPY_STORAGE_EXTEND
71+
5272
void supervisor_flash_init(void) {
53-
_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
73+
if (_partition[0] != NULL) {
74+
return;
75+
}
76+
_partition[0] = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
5477
ESP_PARTITION_SUBTYPE_DATA_FAT,
5578
NULL);
79+
#if CIRCUITPY_STORAGE_EXTEND
80+
_partition[1] = esp_ota_get_next_update_partition(NULL);
81+
#endif
5682
}
5783

5884
uint32_t supervisor_flash_get_block_size(void) {
5985
return FILESYSTEM_BLOCK_SIZE;
6086
}
6187

6288
uint32_t supervisor_flash_get_block_count(void) {
63-
return _partition->size / FILESYSTEM_BLOCK_SIZE;
89+
#if CIRCUITPY_STORAGE_EXTEND
90+
return ((storage_extended) ? (_partition[0]->size + _partition[1]->size) : _partition[0]->size) / FILESYSTEM_BLOCK_SIZE;
91+
#else
92+
return _partition[0]->size / FILESYSTEM_BLOCK_SIZE;
93+
#endif
6494
}
6595

6696
void port_internal_flash_flush(void) {
97+
}
6798

99+
STATIC void single_partition_rw(const esp_partition_t *partition, uint8_t *data,
100+
const uint32_t offset, const uint32_t size_total, const bool op) {
101+
if (op == OP_READ) {
102+
esp_partition_read(partition, offset, data, size_total);
103+
} else {
104+
esp_partition_erase_range(partition, offset, size_total);
105+
esp_partition_write(partition, offset, _cache, size_total);
106+
}
107+
}
108+
109+
#if CIRCUITPY_STORAGE_EXTEND
110+
STATIC void multi_partition_rw(uint8_t *data,
111+
const uint32_t offset, const uint32_t size_total, const bool op) {
112+
if (offset > _partition[0]->size) {
113+
// only r/w partition 1
114+
single_partition_rw(_partition[1], data, (offset - _partition[0]->size), size_total, op);
115+
} else if ((offset + size_total) > _partition[0]->size) {
116+
// first r/w partition 0, then partition 1
117+
uint32_t size_0 = _partition[0]->size - offset;
118+
uint32_t size_1 = size_total - size_0;
119+
if (op == OP_READ) {
120+
esp_partition_read(_partition[0], offset, data, size_0);
121+
esp_partition_read(_partition[1], 0, (data + size_0), size_1);
122+
} else {
123+
esp_partition_erase_range(_partition[0], offset, size_0);
124+
esp_partition_write(_partition[0], offset, _cache, size_0);
125+
esp_partition_erase_range(_partition[1], 0, size_1);
126+
esp_partition_write(_partition[1], 0, (_cache + size_0), size_1);
127+
}
128+
} else {
129+
// only r/w partition 0
130+
single_partition_rw(_partition[0], data, offset, size_total, op);
131+
}
68132
}
133+
#endif
69134

70135
mp_uint_t supervisor_flash_read_blocks(uint8_t *dest, uint32_t block, uint32_t num_blocks) {
71-
esp_partition_read(_partition,
72-
block * FILESYSTEM_BLOCK_SIZE,
73-
dest,
74-
num_blocks * FILESYSTEM_BLOCK_SIZE);
75-
return 0;
136+
const uint32_t offset = block * FILESYSTEM_BLOCK_SIZE;
137+
const uint32_t read_total = num_blocks * FILESYSTEM_BLOCK_SIZE;
138+
#if CIRCUITPY_STORAGE_EXTEND
139+
multi_partition_rw(dest, offset, read_total, OP_READ);
140+
#else
141+
single_partition_rw(_partition[0], dest, offset, read_total, OP_READ);
142+
#endif
143+
return 0; // success
76144
}
77145

78146
mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t lba, uint32_t num_blocks) {
@@ -82,12 +150,8 @@ mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t lba, uint32
82150
uint32_t block_address = lba + block;
83151
uint32_t sector_offset = block_address / blocks_per_sector * SECTOR_SIZE;
84152
uint8_t block_offset = block_address % blocks_per_sector;
85-
86153
if (_cache_lba != block_address) {
87-
esp_partition_read(_partition,
88-
sector_offset,
89-
_cache,
90-
SECTOR_SIZE);
154+
supervisor_flash_read_blocks(_cache, sector_offset / FILESYSTEM_BLOCK_SIZE, blocks_per_sector);
91155
_cache_lba = sector_offset;
92156
}
93157
for (uint8_t b = block_offset; b < blocks_per_sector; b++) {
@@ -100,15 +164,34 @@ mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t lba, uint32
100164
FILESYSTEM_BLOCK_SIZE);
101165
block++;
102166
}
103-
esp_partition_erase_range(_partition, sector_offset, SECTOR_SIZE);
104-
esp_partition_write(_partition,
105-
sector_offset,
106-
_cache,
107-
SECTOR_SIZE);
167+
#if CIRCUITPY_STORAGE_EXTEND
168+
multi_partition_rw(_cache, sector_offset, SECTOR_SIZE, OP_WRITE);
169+
#else
170+
single_partition_rw(_partition[0], _cache, sector_offset, SECTOR_SIZE, OP_READ);
171+
#endif
108172
}
109-
110173
return 0; // success
111174
}
112175

113176
void supervisor_flash_release_cache(void) {
114177
}
178+
179+
void supervisor_flash_set_extended(bool extended) {
180+
#if CIRCUITPY_STORAGE_EXTEND
181+
storage_extended = extended;
182+
#endif
183+
}
184+
185+
bool supervisor_flash_get_extended(void) {
186+
#if CIRCUITPY_STORAGE_EXTEND
187+
return storage_extended;
188+
#else
189+
return false;
190+
#endif
191+
}
192+
193+
void supervisor_flash_update_extended(void) {
194+
#if CIRCUITPY_STORAGE_EXTEND
195+
storage_extended = (_partition[0]->size < fatfs_bytes());
196+
#endif
197+
}

py/circuitpy_mpconfig.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@ CFLAGS += -DCIRCUITPY_STATUS_BAR=$(CIRCUITPY_STATUS_BAR)
401401
CIRCUITPY_STORAGE ?= 1
402402
CFLAGS += -DCIRCUITPY_STORAGE=$(CIRCUITPY_STORAGE)
403403

404+
CIRCUITPY_STORAGE_EXTEND ?= $(CIRCUITPY_DUALBANK)
405+
CFLAGS += -DCIRCUITPY_STORAGE_EXTEND=$(CIRCUITPY_STORAGE_EXTEND)
406+
404407
CIRCUITPY_STRUCT ?= 1
405408
CFLAGS += -DCIRCUITPY_STRUCT=$(CIRCUITPY_STRUCT)
406409

shared-bindings/dualbank/__init__.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626

2727
#include "shared-bindings/dualbank/__init__.h"
2828

29+
#if CIRCUITPY_STORAGE_EXTEND
30+
#include "supervisor/flash.h"
31+
#endif
32+
2933
//| """DUALBANK Module
3034
//|
3135
//| The `dualbank` module adds ability to update and switch
@@ -55,6 +59,14 @@
5559
//| """
5660
//| ...
5761

62+
#if CIRCUITPY_STORAGE_EXTEND
63+
STATIC void raise_error_if_storage_extended(void) {
64+
if (supervisor_flash_get_extended()) {
65+
mp_raise_msg_varg(&mp_type_RuntimeError, translate("%q is %q"), MP_QSTR_storage, MP_QSTR_extended);
66+
}
67+
}
68+
#endif
69+
5870
//| def flash(buffer: ReadableBuffer, offset: int = 0) -> None:
5971
//| """Writes one of two app partitions at the given offset.
6072
//|
@@ -70,6 +82,10 @@ STATIC mp_obj_t dualbank_flash(size_t n_args, const mp_obj_t *pos_args, mp_map_t
7082
{ MP_QSTR_offset, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} },
7183
};
7284

85+
#if CIRCUITPY_STORAGE_EXTEND
86+
raise_error_if_storage_extended();
87+
#endif
88+
7389
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
7490
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
7591

@@ -94,6 +110,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(dualbank_flash_obj, 0, dualbank_flash);
94110
//| ...
95111
//|
96112
STATIC mp_obj_t dualbank_switch(void) {
113+
#if CIRCUITPY_STORAGE_EXTEND
114+
raise_error_if_storage_extended();
115+
#endif
97116
common_hal_dualbank_switch();
98117
return mp_const_none;
99118
}

shared-bindings/storage/__init__.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "py/runtime.h"
3535
#include "shared-bindings/storage/__init__.h"
3636
#include "supervisor/shared/translate/translate.h"
37+
#include "supervisor/flash.h"
3738

3839
//| """Storage management
3940
//|
@@ -150,7 +151,7 @@ STATIC mp_obj_t storage_getmount(const mp_obj_t mnt_in) {
150151
}
151152
MP_DEFINE_CONST_FUN_OBJ_1(storage_getmount_obj, storage_getmount);
152153

153-
//| def erase_filesystem() -> None:
154+
//| def erase_filesystem(extended: Optional[bool] = None) -> None:
154155
//| """Erase and re-create the ``CIRCUITPY`` filesystem.
155156
//|
156157
//| On boards that present USB-visible ``CIRCUITPY`` drive (e.g., SAMD21 and SAMD51),
@@ -160,16 +161,38 @@ MP_DEFINE_CONST_FUN_OBJ_1(storage_getmount_obj, storage_getmount);
160161
//| This function can be called from the REPL when ``CIRCUITPY``
161162
//| has become corrupted.
162163
//|
164+
//| :param bool extended: On boards that support ``dualbank`` module
165+
//| and the ``extended`` parameter, the ``CIRCUITPY`` storage can be
166+
//| extended by setting this to `True`. If this isn't provided or
167+
//| set to `None` (default), the existing configuration will be used.
168+
//|
163169
//| .. warning:: All the data on ``CIRCUITPY`` will be lost, and
164170
//| CircuitPython will restart on certain boards."""
165171
//| ...
166172
//|
167173

168-
STATIC mp_obj_t storage_erase_filesystem(void) {
169-
common_hal_storage_erase_filesystem();
174+
STATIC mp_obj_t storage_erase_filesystem(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
175+
enum { ARG_extended };
176+
static const mp_arg_t allowed_args[] = {
177+
{ MP_QSTR_extended, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
178+
};
179+
180+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
181+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
182+
183+
#if CIRCUITPY_STORAGE_EXTEND
184+
bool extended = (args[ARG_extended].u_obj == mp_const_none) ? supervisor_flash_get_extended() : mp_obj_is_true(args[ARG_extended].u_obj);
185+
common_hal_storage_erase_filesystem(extended);
186+
#else
187+
if (mp_obj_is_true(args[ARG_extended].u_obj)) {
188+
mp_raise_NotImplementedError_varg(translate("%q=%q"), MP_QSTR_extended, MP_QSTR_True);
189+
}
190+
common_hal_storage_erase_filesystem(false);
191+
#endif
192+
170193
return mp_const_none;
171194
}
172-
MP_DEFINE_CONST_FUN_OBJ_0(storage_erase_filesystem_obj, storage_erase_filesystem);
195+
MP_DEFINE_CONST_FUN_OBJ_KW(storage_erase_filesystem_obj, 0, storage_erase_filesystem);
173196

174197
//| def disable_usb_drive() -> None:
175198
//| """Disable presenting ``CIRCUITPY`` as a USB mass storage device.

shared-bindings/storage/__init__.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void common_hal_storage_umount_path(const char *path);
3737
void common_hal_storage_umount_object(mp_obj_t vfs_obj);
3838
void common_hal_storage_remount(const char *path, bool readonly, bool disable_concurrent_write_protection);
3939
mp_obj_t common_hal_storage_getmount(const char *path);
40-
void common_hal_storage_erase_filesystem(void);
40+
void common_hal_storage_erase_filesystem(bool extended);
4141

4242
bool common_hal_storage_disable_usb_drive(void);
4343
bool common_hal_storage_enable_usb_drive(void);

shared-module/storage/__init__.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,14 @@ void common_hal_storage_remount(const char *mount_path, bool readonly, bool disa
267267
filesystem_set_internal_concurrent_write_protection(!disable_concurrent_write_protection);
268268
}
269269

270-
void common_hal_storage_erase_filesystem(void) {
270+
void common_hal_storage_erase_filesystem(bool extended) {
271271
#if CIRCUITPY_USB
272272
usb_disconnect();
273273
#endif
274274
mp_hal_delay_ms(1000);
275+
#if CIRCUITPY_STORAGE_EXTEND
276+
supervisor_flash_set_extended(extended);
277+
#endif
275278
(void)filesystem_init(false, true); // Force a re-format. Ignore failure.
276279
common_hal_mcu_reset();
277280
// We won't actually get here, since we're resetting.

supervisor/flash.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,8 @@ void supervisor_flash_init_vfs(struct _fs_user_mount_t *vfs);
5050
void supervisor_flash_flush(void);
5151
void supervisor_flash_release_cache(void);
5252

53+
void supervisor_flash_set_extended(bool extended);
54+
bool supervisor_flash_get_extended(void);
55+
void supervisor_flash_update_extended(void);
56+
5357
#endif // MICROPY_INCLUDED_SUPERVISOR_FLASH_H

supervisor/shared/filesystem.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,22 @@ bool filesystem_init(bool create_allowed, bool force_create) {
143143
} else if (res != FR_OK) {
144144
return false;
145145
}
146+
146147
vfs->str = "/";
147148
vfs->len = 1;
148149
vfs->obj = MP_OBJ_FROM_PTR(vfs_fat);
149150
vfs->next = NULL;
151+
150152
MP_STATE_VM(vfs_mount_table) = vfs;
151153

152154
// The current directory is used as the boot up directory.
153155
// It is set to the internal flash filesystem by default.
154156
MP_STATE_PORT(vfs_cur) = vfs;
155157

158+
#if CIRCUITPY_STORAGE_EXTEND
159+
supervisor_flash_update_extended();
160+
#endif
161+
156162
return true;
157163
}
158164

0 commit comments

Comments
 (0)