11# pragma: no cover
22"""Reformat the filesystem block device, keeping the board on MicroPython.
33
4- Run on the board via ``mpremote run``. It locates the port's filesystem
5- ``bdev`` (the same one ``_boot.py`` mounts), detects the current filesystem
6- type (``VfsLfs2`` or ``VfsFat``) and recreates an empty filesystem of that
7- type, then remounts it.
4+ Run on the board via ``mpremote run``. It discovers the mounted filesystem
5+ using the same ``vfs.mount()`` enumeration as ``mpremote df`` (so the mount
6+ point and filesystem type are detected at runtime, not hardcoded per port),
7+ locates the port's block device, then recreates an empty filesystem of the
8+ same type and remounts it at the same mount point.
89
910Only the filesystem storage region is reformatted - the firmware itself lives
1011in a separate flash region and is left untouched.
@@ -23,50 +24,79 @@ def _vfs():
2324 return os
2425
2526
26- def _get_bdev ():
27- """Return (bdev, mount_point) for the running port, or (None, None)."""
28- try :
29- import rp2
27+ # (module, attribute, kwargs): the block-device factory each MicroPython port
28+ # exposes. Instantiated as ``module.attribute(**kwargs)``. Adding a new port is
29+ # a new entry here, not a port-name check elsewhere.
30+ _BDEV_FACTORIES = (
31+ ("rp2" , "Flash" , {}),
32+ ("samd" , "Flash" , {}),
33+ ("nrf" , "Flash" , {}),
34+ ("mimxrt" , "Flash" , {}),
35+ ("alif" , "Flash" , {}),
36+ ("pyb" , "Flash" , {"start" : 0 }), # stm32
37+ ("psoc_edge" , "QSPI_Flash" , {}),
38+ )
3039
31- return rp2 .Flash (), "/"
32- except Exception :
33- pass
34- try :
35- import samd
3640
37- return samd .Flash (), "/"
38- except Exception :
39- pass
40- try :
41- import nrf
41+ def _get_bdev ():
42+ """Return the internal-flash block device for the running port, or None.
4243
43- return nrf .Flash (), "/flash"
44- except Exception :
45- pass
44+ Polls the known block-device factories in turn; the first that imports and
45+ instantiates wins. esp32 / esp8266 instead expose a ready-made ``bdev``.
46+ """
47+ for mod_name , attr , kwargs in _BDEV_FACTORIES :
48+ try :
49+ return getattr (__import__ (mod_name ), attr )(** kwargs )
50+ except Exception :
51+ pass
4652 try :
4753 from flashbdev import bdev # esp32 / esp8266
4854
49- return bdev , "/"
55+ return bdev
5056 except Exception :
5157 pass
58+ return None
59+
60+
61+ def _list_mounts (vfs ):
62+ """Return [(fs, mount_point), ...] via ``vfs.mount()`` (like ``mpremote df``)."""
5263 try :
53- import pyb # stm32
64+ return list (vfs .mount ())
65+ except (AttributeError , TypeError ):
66+ return []
5467
55- return pyb .Flash (start = 0 ), "/"
56- except Exception :
57- pass
58- return None , None
68+
69+ def _target_mount (vfs ):
70+ """Return (fs, mount_point) for the writable internal filesystem.
71+
72+ Uses the runtime mount table, skipping the read-only ROM filesystem and
73+ removable SD cards. Falls back to probing the usual internal-flash mount
74+ points when the mount table cannot be enumerated (older firmware).
75+ """
76+ for fs , point in _list_mounts (vfs ):
77+ if "Rom" in str (fs ) or point .startswith ("/sd" ):
78+ continue
79+ return fs , point
80+ import os
81+
82+ for point in ("/" , "/flash" ):
83+ try :
84+ os .statvfs (point )
85+ return None , point
86+ except OSError :
87+ pass
88+ return None , "/"
5989
6090
6191def _detect_fs (vfs , bdev ):
62- """Detect the current filesystem class, defaulting to the first available .
92+ """Probe the block device to detect its filesystem class .
6393
6494 Only Vfs* classes present in this firmware build are considered; some ports
6595 (for example nrf) are built without ``VfsFat``, so look them up defensively
6696 to avoid an ``AttributeError``.
6797 """
6898 candidates = []
69- for name in ("VfsLfs2" , "VfsFat" ):
99+ for name in ("VfsLfs2" , "VfsLfs1" , " VfsFat" ):
70100 cls = getattr (vfs , name , None )
71101 if cls is not None :
72102 candidates .append (cls )
@@ -79,13 +109,31 @@ def _detect_fs(vfs, bdev):
79109 return candidates [0 ] if candidates else None
80110
81111
112+ def _fs_class (vfs , fs , bdev ):
113+ """Return the Vfs* class to recreate.
114+
115+ Prefers the type of the currently mounted filesystem (from its repr, e.g.
116+ ``<VfsLfs2>``), which is the most reliable signal; if there is no mounted
117+ filesystem to learn from, probe the block device instead.
118+ """
119+ if fs is not None :
120+ text = str (fs )
121+ for name in ("VfsLfs2" , "VfsLfs1" , "VfsFat" ):
122+ if name in text :
123+ cls = getattr (vfs , name , None )
124+ if cls is not None :
125+ return cls
126+ return _detect_fs (vfs , bdev )
127+
128+
82129def main ():
83130 vfs = _vfs ()
84- bdev , mount_point = _get_bdev ()
131+ bdev = _get_bdev ()
85132 if bdev is None :
86133 print ("FORMAT: no filesystem block device found" )
87134 return
88- fs_cls = _detect_fs (vfs , bdev )
135+ fs , mount_point = _target_mount (vfs )
136+ fs_cls = _fs_class (vfs , fs , bdev )
89137 if fs_cls is None :
90138 print ("FORMAT: no supported filesystem type available" )
91139 return
@@ -97,11 +145,11 @@ def main():
97145 try :
98146 if fs_cls is getattr (vfs , "VfsLfs2" , None ):
99147 fs_cls .mkfs (bdev , progsize = 256 )
100- fs = fs_cls (bdev , progsize = 256 )
148+ new_fs = fs_cls (bdev , progsize = 256 )
101149 else :
102150 fs_cls .mkfs (bdev )
103- fs = fs_cls (bdev )
104- vfs .mount (fs , mount_point or "/" )
151+ new_fs = fs_cls (bdev )
152+ vfs .mount (new_fs , mount_point or "/" )
105153 except Exception as exc :
106154 print ("FORMAT: failed:" , exc )
107155 return
0 commit comments