mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-15 09:50:57 +00:00
feat(core): add progress indicator when formatting SD cards
This commit is contained in:
parent
8fa602cefe
commit
a64b22cdef
1
core/.changelog.d/3035.fixed
Normal file
1
core/.changelog.d/3035.fixed
Normal file
@ -0,0 +1 @@
|
|||||||
|
[T2T1] Added a progress indicator for the formatting operation
|
@ -418,8 +418,6 @@
|
|||||||
#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp)
|
#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------
|
||||||
|
|
||||||
Module Private Work Area
|
Module Private Work Area
|
||||||
@ -3262,12 +3260,9 @@ FRESULT f_setlabel (
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int progress_section(int start, int size, int current, int first) {
|
||||||
|
return start + size - (current ? ((current * size) / first) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if !FF_FS_READONLY && FF_USE_MKFS
|
#if !FF_FS_READONLY && FF_USE_MKFS
|
||||||
@ -3346,17 +3341,25 @@ FRESULT f_mkfs (
|
|||||||
const TCHAR* path, /* Logical drive number */
|
const TCHAR* path, /* Logical drive number */
|
||||||
const MKFS_PARM* opt, /* Format options */
|
const MKFS_PARM* opt, /* Format options */
|
||||||
void* work, /* Pointer to working buffer (null: use len bytes of heap memory) */
|
void* work, /* Pointer to working buffer (null: use len bytes of heap memory) */
|
||||||
UINT len /* Size of working buffer [byte] */
|
UINT len, /* Size of working buffer [byte] */
|
||||||
|
void (*progress_callback)(uint32_t current /* 0-1000 */) /* Callback used to report progress (NULL: no progress reporting) */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */
|
static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */
|
||||||
static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */
|
static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */
|
||||||
static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */
|
static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */
|
||||||
|
static const WORD p_initial = 0;
|
||||||
|
static const WORD p_fat_area_before = 10;
|
||||||
|
static const WORD p_fat_area_sz = 790;
|
||||||
|
static const WORD p_root_dir_before = p_fat_area_before + p_fat_area_sz;
|
||||||
|
static const WORD p_root_dir_sz = 100;
|
||||||
|
static const WORD p_final = 1000;
|
||||||
|
static const WORD p_num_calls = 10; /* Limit of number of calls to report progress in each loop */
|
||||||
BYTE fsopt = 0, fsty = 0, sys = 0, pdrv = 0, ipart = 0;
|
BYTE fsopt = 0, fsty = 0, sys = 0, pdrv = 0, ipart = 0;
|
||||||
BYTE *buf = NULL;
|
BYTE *buf = NULL;
|
||||||
BYTE *pte = NULL;
|
BYTE *pte = NULL;
|
||||||
WORD ss = 0; /* Sector size */
|
WORD ss = 0; /* Sector size */
|
||||||
DWORD sz_buf = 0, sz_blk = 0, n_clst = 0, pau = 0, nsect = 0, n = 0, vsn = 0;
|
DWORD sz_buf = 0, sz_blk = 0, n_clst = 0, pau = 0, nsect = 0, nsect0 = 0, n = 0, vsn = 0;
|
||||||
LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */
|
LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */
|
||||||
LBA_t sect = 0, lba[2] = {0};
|
LBA_t sect = 0, lba[2] = {0};
|
||||||
DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved, fat, dir, data, cluster */
|
DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved, fat, dir, data, cluster */
|
||||||
@ -3364,7 +3367,11 @@ FRESULT f_mkfs (
|
|||||||
int vol = 0;
|
int vol = 0;
|
||||||
DSTATUS ds = 0;
|
DSTATUS ds = 0;
|
||||||
FRESULT res = 0;
|
FRESULT res = 0;
|
||||||
|
DWORD iter, progress_steps;
|
||||||
|
|
||||||
|
if (progress_callback) {
|
||||||
|
progress_callback(p_initial);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check mounted drive and clear work area */
|
/* Check mounted drive and clear work area */
|
||||||
vol = get_ldnumber(&path); /* Get target logical drive */
|
vol = get_ldnumber(&path); /* Get target logical drive */
|
||||||
@ -3570,6 +3577,10 @@ FRESULT f_mkfs (
|
|||||||
disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */
|
disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (progress_callback) {
|
||||||
|
progress_callback(p_fat_area_before);
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize FAT area */
|
/* Initialize FAT area */
|
||||||
memset(buf, 0, sz_buf * ss);
|
memset(buf, 0, sz_buf * ss);
|
||||||
sect = b_fat; /* FAT start sector */
|
sect = b_fat; /* FAT start sector */
|
||||||
@ -3581,24 +3592,46 @@ FRESULT f_mkfs (
|
|||||||
} else {
|
} else {
|
||||||
st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] */
|
st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] */
|
||||||
}
|
}
|
||||||
nsect = sz_fat; /* Number of FAT sectors */
|
nsect0 = nsect = sz_fat; /* Number of FAT sectors */
|
||||||
|
progress_steps = nsect / sz_buf / p_num_calls;
|
||||||
|
iter = 0;
|
||||||
do { /* Fill FAT sectors */
|
do { /* Fill FAT sectors */
|
||||||
n = (nsect > sz_buf) ? sz_buf : nsect;
|
n = (nsect > sz_buf) ? sz_buf : nsect;
|
||||||
if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
|
if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
|
||||||
memset(buf, 0, ss); /* Rest of FAT all are cleared */
|
memset(buf, 0, ss); /* Rest of FAT all are cleared */
|
||||||
sect += n; nsect -= n;
|
sect += n; nsect -= n;
|
||||||
|
iter++;
|
||||||
|
|
||||||
|
if (progress_callback && progress_steps && iter % progress_steps == 0) {
|
||||||
|
progress_callback(progress_section(p_fat_area_before, p_fat_area_sz, nsect, nsect0));
|
||||||
|
}
|
||||||
} while (nsect);
|
} while (nsect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (progress_callback) {
|
||||||
|
progress_callback(p_root_dir_before);
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize root directory (fill with zero) */
|
/* Initialize root directory (fill with zero) */
|
||||||
nsect = (fsty == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */
|
nsect0 = nsect = (fsty == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */
|
||||||
|
progress_steps = nsect / sz_buf / p_num_calls;
|
||||||
|
iter = 0;
|
||||||
do {
|
do {
|
||||||
n = (nsect > sz_buf) ? sz_buf : nsect;
|
n = (nsect > sz_buf) ? sz_buf : nsect;
|
||||||
if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
|
if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
|
||||||
sect += n; nsect -= n;
|
sect += n; nsect -= n;
|
||||||
|
iter++;
|
||||||
|
|
||||||
|
if (progress_callback && progress_steps && iter % progress_steps == 0) {
|
||||||
|
progress_callback(progress_section(p_root_dir_before, p_root_dir_sz, nsect, nsect0));
|
||||||
|
}
|
||||||
} while (nsect);
|
} while (nsect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (progress_callback) {
|
||||||
|
progress_callback(p_root_dir_before + p_root_dir_sz);
|
||||||
|
}
|
||||||
|
|
||||||
/* A FAT volume has been created here */
|
/* A FAT volume has been created here */
|
||||||
|
|
||||||
/* Determine system ID in the MBR partition table */
|
/* Determine system ID in the MBR partition table */
|
||||||
@ -3632,6 +3665,10 @@ FRESULT f_mkfs (
|
|||||||
|
|
||||||
if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
|
if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
|
||||||
|
|
||||||
|
if (progress_callback) {
|
||||||
|
progress_callback(p_final);
|
||||||
|
}
|
||||||
|
|
||||||
LEAVE_MKFS(FR_OK);
|
LEAVE_MKFS(FR_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
|||||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||||
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||||
FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */
|
FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len, void (*progress_callback)(uint32_t current)); /* Create a FAT volume */
|
||||||
FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */
|
FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */
|
||||||
FRESULT f_setcp (WORD cp); /* Set current code page */
|
FRESULT f_setcp (WORD cp); /* Set current code page */
|
||||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||||
|
@ -528,24 +528,43 @@ STATIC mp_obj_t mod_trezorio_fatfs_is_mounted() {
|
|||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_is_mounted_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_is_mounted_obj,
|
||||||
mod_trezorio_fatfs_is_mounted);
|
mod_trezorio_fatfs_is_mounted);
|
||||||
|
|
||||||
/// def mkfs() -> None:
|
STATIC mp_obj_t ui_wait_callback = mp_const_none;
|
||||||
|
|
||||||
|
STATIC void wrapped_ui_wait_callback(uint32_t current) {
|
||||||
|
if (mp_obj_is_callable(ui_wait_callback)) {
|
||||||
|
mp_call_function_1_protected(ui_wait_callback, mp_obj_new_int(current));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// def mkfs(callback: Callable[[int], None] | None = None) -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Create a FAT volume on the SD card,
|
/// Create a FAT volume on the SD card,
|
||||||
/// """
|
/// """
|
||||||
STATIC mp_obj_t mod_trezorio_fatfs_mkfs() {
|
STATIC mp_obj_t mod_trezorio_fatfs_mkfs(size_t n_args, const mp_obj_t *args) {
|
||||||
if (_fatfs_instance_is_mounted()) {
|
if (_fatfs_instance_is_mounted()) {
|
||||||
FATFS_RAISE(FatFSError, FR_LOCKED);
|
FATFS_RAISE(FatFSError, FR_LOCKED);
|
||||||
}
|
}
|
||||||
MKFS_PARM params = {FM_FAT32, 0, 0, 0, 0};
|
MKFS_PARM params = {FM_FAT32, 0, 0, 0, 0};
|
||||||
uint8_t working_buf[FF_MAX_SS] = {0};
|
uint8_t working_buf[FF_MAX_SS] = {0};
|
||||||
FRESULT res = f_mkfs("", ¶ms, working_buf, sizeof(working_buf));
|
FRESULT res;
|
||||||
|
if (n_args == 1) {
|
||||||
|
// format with a progress callback
|
||||||
|
ui_wait_callback = args[0];
|
||||||
|
res = f_mkfs("", ¶ms, working_buf, sizeof(working_buf),
|
||||||
|
wrapped_ui_wait_callback);
|
||||||
|
ui_wait_callback = mp_const_none;
|
||||||
|
} else {
|
||||||
|
// format without a progress callback
|
||||||
|
res = f_mkfs("", ¶ms, working_buf, sizeof(working_buf), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (res != FR_OK) {
|
if (res != FR_OK) {
|
||||||
FATFS_RAISE(FatFSError, res);
|
FATFS_RAISE(FatFSError, res);
|
||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_mkfs_obj,
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_fatfs_mkfs_obj, 0, 1,
|
||||||
mod_trezorio_fatfs_mkfs);
|
mod_trezorio_fatfs_mkfs);
|
||||||
|
|
||||||
/// def setlabel(label: str) -> None:
|
/// def setlabel(label: str) -> None:
|
||||||
/// """
|
/// """
|
||||||
|
@ -166,7 +166,7 @@ def is_mounted() -> bool:
|
|||||||
|
|
||||||
|
|
||||||
# extmod/modtrezorio/modtrezorio-fatfs.h
|
# extmod/modtrezorio/modtrezorio-fatfs.h
|
||||||
def mkfs() -> None:
|
def mkfs(callback: Callable[[int], None] | None = None) -> None:
|
||||||
"""
|
"""
|
||||||
Create a FAT volume on the SD card,
|
Create a FAT volume on the SD card,
|
||||||
"""
|
"""
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
from trezor import TR, io, wire
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from trezor import TR, io, utils, wire
|
||||||
from trezor.ui.layouts import confirm_action, show_error_and_raise
|
from trezor.ui.layouts import confirm_action, show_error_and_raise
|
||||||
from trezor.utils import sd_hotswap_enabled
|
from trezor.utils import sd_hotswap_enabled
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from trezor.ui.layouts.common import ProgressLayout
|
||||||
|
|
||||||
|
|
||||||
class SdCardUnavailable(wire.ProcessError):
|
class SdCardUnavailable(wire.ProcessError):
|
||||||
pass
|
pass
|
||||||
@ -120,9 +125,11 @@ async def ensure_sdcard(ensure_filesystem: bool = True) -> None:
|
|||||||
|
|
||||||
# Proceed to formatting. Failure is caught by the outside OSError handler
|
# Proceed to formatting. Failure is caught by the outside OSError handler
|
||||||
with sdcard.filesystem(mounted=False):
|
with sdcard.filesystem(mounted=False):
|
||||||
fatfs.mkfs()
|
_start_progress()
|
||||||
|
fatfs.mkfs(_render_progress)
|
||||||
fatfs.mount()
|
fatfs.mount()
|
||||||
fatfs.setlabel("TREZOR")
|
fatfs.setlabel("TREZOR")
|
||||||
|
_finish_progress()
|
||||||
|
|
||||||
# format and mount succeeded
|
# format and mount succeeded
|
||||||
return
|
return
|
||||||
@ -150,3 +157,30 @@ async def request_sd_salt() -> bytearray | None:
|
|||||||
# In either case, there is no good way to recover. If the user clicks Retry,
|
# In either case, there is no good way to recover. If the user clicks Retry,
|
||||||
# we will try again.
|
# we will try again.
|
||||||
await confirm_retry_sd()
|
await confirm_retry_sd()
|
||||||
|
|
||||||
|
|
||||||
|
_progress_obj: ProgressLayout | None = None
|
||||||
|
|
||||||
|
|
||||||
|
def _start_progress() -> None:
|
||||||
|
from trezor import workflow
|
||||||
|
from trezor.ui.layouts.progress import progress
|
||||||
|
|
||||||
|
global _progress_obj
|
||||||
|
|
||||||
|
if not utils.DISABLE_ANIMATION:
|
||||||
|
# Because we are drawing to the screen manually, without a layout, we
|
||||||
|
# should make sure that no other layout is running.
|
||||||
|
workflow.close_others()
|
||||||
|
_progress_obj = progress()
|
||||||
|
|
||||||
|
|
||||||
|
def _render_progress(progress: int) -> None:
|
||||||
|
global _progress_obj
|
||||||
|
if _progress_obj is not None:
|
||||||
|
_progress_obj.report(progress)
|
||||||
|
|
||||||
|
|
||||||
|
def _finish_progress() -> None:
|
||||||
|
global _progress_obj
|
||||||
|
_progress_obj = None
|
||||||
|
Loading…
Reference in New Issue
Block a user