Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): add progress indicator when formatting SD cards #3523

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/.changelog.d/3035.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[T2T1] Added a progress indicator for the formatting operation
46 changes: 41 additions & 5 deletions core/embed/extmod/modtrezorio/ff.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@
#define MKCVTBL(hd, cp) MERGE_2STR(hd, cp)


/* Helper macro for progress report */
#define PROGRESS_SECTION(section_start, section_size, section_progress) (section_start + (section_progress * section_size))


/*--------------------------------------------------------------------------
Expand Down Expand Up @@ -3346,17 +3348,24 @@ FRESULT f_mkfs (
const TCHAR* path, /* Logical drive number */
const MKFS_PARM* opt, /* Format options */
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 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 WORD progress_initial = 0;
static const WORD progress_before_initialize_fat_area = 10;
static const WORD progress_initialize_fat_area_section = 790;
static const WORD progress_before_initialize_root_directory = progress_before_initialize_fat_area + progress_initialize_fat_area_section;
static const WORD progress_initialize_root_directory_section = 100;
static const WORD progress_final = 1000;
BYTE fsopt = 0, fsty = 0, sys = 0, pdrv = 0, ipart = 0;
BYTE *buf = NULL;
BYTE *pte = NULL;
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 sect = 0, lba[2] = {0};
DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved, fat, dir, data, cluster */
Expand All @@ -3365,6 +3374,9 @@ FRESULT f_mkfs (
DSTATUS ds = 0;
FRESULT res = 0;

if (progress_callback) {
progress_callback(progress_initial);
}

/* Check mounted drive and clear work area */
vol = get_ldnumber(&path); /* Get target logical drive */
Expand Down Expand Up @@ -3570,6 +3582,10 @@ FRESULT f_mkfs (
disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */
}

if (progress_callback) {
progress_callback(progress_before_initialize_fat_area);
}

/* Initialize FAT area */
memset(buf, 0, sz_buf * ss);
sect = b_fat; /* FAT start sector */
Expand All @@ -3581,24 +3597,41 @@ FRESULT f_mkfs (
} else {
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 */
do { /* Fill FAT sectors */
n = (nsect > sz_buf) ? sz_buf : nsect;
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 */
sect += n; nsect -= n;

if (progress_callback) {
progress_callback(PROGRESS_SECTION(progress_before_initialize_fat_area, progress_initialize_fat_area_section, (1 - nsect / (float)nsect0)));
}

} while (nsect);
}

if (progress_callback) {
progress_callback(progress_before_initialize_root_directory);
}

/* 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 */
do {
n = (nsect > sz_buf) ? sz_buf : nsect;
if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
sect += n; nsect -= n;

if (progress_callback) {
progress_callback(PROGRESS_SECTION(progress_before_initialize_root_directory, progress_initialize_root_directory_section, (1 - nsect / (float)nsect0)));
}
} while (nsect);
}

if (progress_callback) {
progress_callback(progress_before_initialize_root_directory + progress_initialize_root_directory_section);
}

/* A FAT volume has been created here */

/* Determine system ID in the MBR partition table */
Expand Down Expand Up @@ -3632,6 +3665,10 @@ FRESULT f_mkfs (

if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);

if (progress_callback) {
progress_callback(progress_final);
}

LEAVE_MKFS(FR_OK);
}

Expand All @@ -3646,4 +3683,3 @@ FRESULT f_mkfs (




2 changes: 1 addition & 1 deletion core/embed/extmod/modtrezorio/ff.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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_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_setcp (WORD cp); /* Set current code page */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
Expand Down
20 changes: 15 additions & 5 deletions core/embed/extmod/modtrezorio/modtrezorio-fatfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -528,24 +528,34 @@ STATIC mp_obj_t mod_trezorio_fatfs_is_mounted() {
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_is_mounted_obj,
mod_trezorio_fatfs_is_mounted);

/// def mkfs() -> None:
/// def mkfs(callback: Callable[[int], None] | None = None) -> None:
/// """
/// 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()) {
FATFS_RAISE(FatFSError, FR_LOCKED);
}
MKFS_PARM params = {FM_FAT32, 0, 0, 0, 0};
uint8_t working_buf[FF_MAX_SS] = {0};
FRESULT res = f_mkfs("", &params, working_buf, sizeof(working_buf));
FRESULT res;
if (n_args == 1) {
// format with a progress callback
ui_wait_callback = args[0];
res = f_mkfs("", &params, working_buf, sizeof(working_buf), wrapped_ui_wait_callback);
ui_wait_callback = mp_const_none;
} else {
// format without a progress callback
res = f_mkfs("", &params, working_buf, sizeof(working_buf), NULL);
}

if (res != FR_OK) {
FATFS_RAISE(FatFSError, res);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_mkfs_obj,
mod_trezorio_fatfs_mkfs);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_fatfs_mkfs_obj, 0,
1, mod_trezorio_fatfs_mkfs);

/// def setlabel(label: str) -> None:
/// """
Expand Down
10 changes: 10 additions & 0 deletions core/embed/extmod/modtrezorio/modtrezorio.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ bool usb_connected_previously = true;
#include "modtrezorio-sbu.h"
#endif
#ifdef USE_SD_CARD

#include "py/runtime.h"

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));
}
}
#include "modtrezorio-fatfs.h"
#include "modtrezorio-sdcard.h"
#endif
Expand Down
2 changes: 1 addition & 1 deletion core/mocks/generated/trezorio/fatfs.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def is_mounted() -> bool:


# 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,
"""
Expand Down
41 changes: 39 additions & 2 deletions core/src/apps/common/sdcard.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
from typing import TYPE_CHECKING

from storage.sd_salt import SD_CARD_HOT_SWAPPABLE
from trezor import io, wire
from trezor import io, utils, wire
from trezor.ui.layouts import confirm_action, show_error_and_raise

if TYPE_CHECKING:
from trezor.ui.layouts.common import ProgressLayout


class SdCardUnavailable(wire.ProcessError):
pass
Expand Down Expand Up @@ -120,9 +125,15 @@ async def ensure_sdcard(ensure_filesystem: bool = True) -> None:

# Proceed to formatting. Failure is caught by the outside OSError handler
with sdcard.filesystem(mounted=False):
fatfs.mkfs()
render_func = None
if not utils.DISABLE_ANIMATION:
_start_progress()
render_func = _render_progress
fatfs.mkfs(render_func)
fatfs.mount()
fatfs.setlabel("TREZOR")
if not utils.DISABLE_ANIMATION:
_finish_progress()

# format and mount succeeded
return
Expand Down Expand Up @@ -150,3 +161,29 @@ async def request_sd_salt() -> bytearray | None:
# In either case, there is no good way to recover. If the user clicks Retry,
# we will try again.
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

# 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