Skip to content

Commit 3b5e25f

Browse files
committed
feat: add speed and ETA display to progress bar with quiet option
Progress bar now displays transfer speed (KB/s or MB/s) and estimated time remaining during read, write, verify, and blank-check operations. The --quiet / -q option suppresses all progress output for scripted or background use. Speed is calculated from elapsed time using monotonic clock, and ETA is derived from remaining bytes and current transfer rate. Signed-off-by: Vincent Jardin <[email protected]>
1 parent 3940274 commit 3b5e25f

File tree

4 files changed

+100
-5
lines changed

4 files changed

+100
-5
lines changed

radfu.h2m

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,20 @@ radfu osis
395395
radfu config-read
396396
radfu boundary-set --cfs1 0 --cfs2 0 --dfs 0 --srs1 0 --srs2 0
397397
radfu -u -p /dev/ttyUSB0 info # UART via USB-UART adapter
398+
radfu write -q firmware.bin # Write without progress bar
398399
.fi
399400

401+
[progress display]
402+
During read, write, verify, and blank-check operations, radfu displays a progress
403+
bar with transfer speed and estimated time remaining:
404+
405+
.nf
406+
Writing: [###############...............] 50% (32768/65536) 125.3 KB/s ETA 2s
407+
.fi
408+
409+
The \\fB-q\\fR (\\fB--quiet\\fR) option suppresses progress output. This is useful
410+
for scripting or when running operations in the background.
411+
400412
[warnings]
401413
.B USE AT YOUR OWN RISK
402414

src/main.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "compat.h"
1010
#include "formats.h"
11+
#include "progress.h"
1112
#include "raconnect.h"
1213
#include "radfu.h"
1314
#include "raosis.h"
@@ -64,6 +65,7 @@ usage(int status) {
6465
" -F, --output-format <fmt> Output file format (auto/bin/ihex/srec)\n"
6566
" --area <type> Select memory area (code/data/config or KOA value)\n"
6667
" -u, --uart Use plain UART mode (P109/P110 pins)\n"
68+
" -q, --quiet Suppress progress bar output\n"
6769
" --cfs1 <KB> Code flash secure region size without NSC\n"
6870
" --cfs2 <KB> Code flash secure region size (total)\n"
6971
" --dfs <KB> Data flash secure region size\n"
@@ -328,6 +330,7 @@ static const struct option longopts[] = {
328330
{ "input-format", required_argument, NULL, 'f' },
329331
{ "output-format", required_argument, NULL, 'F' },
330332
{ "uart", no_argument, NULL, 'u' },
333+
{ "quiet", no_argument, NULL, 'q' },
331334
{ "cfs1", required_argument, NULL, OPT_CFS1 },
332335
{ "cfs2", required_argument, NULL, OPT_CFS2 },
333336
{ "dfs", required_argument, NULL, OPT_DFS },
@@ -368,7 +371,7 @@ main(int argc, char *argv[]) {
368371
enum command cmd = CMD_NONE;
369372
int opt;
370373

371-
while ((opt = getopt_long(argc, argv, "p:a:s:b:i:evf:F:uhV", longopts, NULL)) != -1) {
374+
while ((opt = getopt_long(argc, argv, "p:a:s:b:i:evf:F:uqhV", longopts, NULL)) != -1) {
372375
switch (opt) {
373376
case 'p':
374377
port = optarg;
@@ -418,6 +421,9 @@ main(int argc, char *argv[]) {
418421
case 'u':
419422
uart_mode = true;
420423
break;
424+
case 'q':
425+
progress_global_quiet = 1;
426+
break;
421427
case OPT_CFS1:
422428
bnd.cfs1 = (uint16_t)strtoul(optarg, NULL, 10);
423429
bnd_cfs1_set = true;

src/progress.c

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,27 @@
66
* Minimal terminal progress bar with optional callback for library integration
77
*/
88

9+
#define _DEFAULT_SOURCE /* clock_gettime, CLOCK_MONOTONIC */
10+
911
#include "progress.h"
1012
#include <stdio.h>
1113
#include <string.h>
1214

1315
#define BAR_WIDTH 30
1416

17+
/* Global quiet mode */
18+
int progress_global_quiet = 0;
19+
20+
/* Get elapsed time in seconds */
21+
static double
22+
get_elapsed_secs(const struct timespec *start) {
23+
struct timespec now;
24+
clock_gettime(CLOCK_MONOTONIC, &now);
25+
double secs = (double)(now.tv_sec - start->tv_sec);
26+
secs += (double)(now.tv_nsec - start->tv_nsec) / 1e9;
27+
return secs;
28+
}
29+
1530
void
1631
progress_init(progress_t *p, size_t total, const char *desc) {
1732
p->total = total;
@@ -20,6 +35,8 @@ progress_init(progress_t *p, size_t total, const char *desc) {
2035
p->desc = desc;
2136
p->callback = NULL;
2237
p->user_data = NULL;
38+
p->quiet = progress_global_quiet;
39+
clock_gettime(CLOCK_MONOTONIC, &p->start_time);
2340
progress_update(p, 0);
2441
}
2542

@@ -29,16 +46,27 @@ progress_set_callback(progress_t *p, progress_cb_t cb, void *user_data) {
2946
p->user_data = user_data;
3047
}
3148

49+
void
50+
progress_set_quiet(progress_t *p, int quiet) {
51+
p->quiet = quiet;
52+
}
53+
3254
void
3355
progress_update(progress_t *p, size_t current) {
3456
p->current = current;
3557

3658
/* Use callback if set */
3759
if (p->callback != NULL) {
3860
p->callback(current, p->total, p->desc, p->user_data);
39-
return;
61+
/* If quiet, skip default output even after callback */
62+
if (p->quiet)
63+
return;
4064
}
4165

66+
/* Skip output in quiet mode */
67+
if (p->quiet)
68+
return;
69+
4270
/* Default: print to stderr */
4371
int percent = 0;
4472
int filled = 0;
@@ -58,19 +86,52 @@ progress_update(progress_t *p, size_t current) {
5886
memset(bar, '#', filled);
5987
bar[p->width] = '\0';
6088

89+
/* Calculate speed and ETA */
90+
double elapsed = get_elapsed_secs(&p->start_time);
91+
char speed_str[32] = "";
92+
char eta_str[32] = "";
93+
94+
if (elapsed > 0.1 && current > 0) {
95+
/* Speed in KB/s */
96+
double speed = (double)current / elapsed / 1024.0;
97+
if (speed >= 1000.0)
98+
snprintf(speed_str, sizeof(speed_str), " %.1f MB/s", speed / 1024.0);
99+
else
100+
snprintf(speed_str, sizeof(speed_str), " %.1f KB/s", speed);
101+
102+
/* ETA calculation */
103+
if (current < p->total && speed > 0) {
104+
double remaining_bytes = (double)(p->total - current);
105+
double eta_secs = remaining_bytes / (speed * 1024.0);
106+
if (eta_secs < 60)
107+
snprintf(eta_str, sizeof(eta_str), " ETA %ds", (int)eta_secs);
108+
else if (eta_secs < 3600)
109+
snprintf(
110+
eta_str, sizeof(eta_str), " ETA %dm%02ds", (int)(eta_secs / 60), (int)eta_secs % 60);
111+
else
112+
snprintf(eta_str,
113+
sizeof(eta_str),
114+
" ETA %dh%02dm",
115+
(int)(eta_secs / 3600),
116+
(int)(eta_secs / 60) % 60);
117+
}
118+
}
119+
61120
fprintf(stderr,
62-
"\r%s: [%s] %3d%% (%zu/%zu)",
121+
"\r%s: [%s] %3d%% (%zu/%zu)%s%s ",
63122
p->desc ? p->desc : "",
64123
bar,
65124
percent,
66125
current,
67-
p->total);
126+
p->total,
127+
speed_str,
128+
eta_str);
68129
fflush(stderr);
69130
}
70131

71132
void
72133
progress_finish(progress_t *p) {
73134
progress_update(p, p->total);
74-
if (p->callback == NULL)
135+
if (p->callback == NULL && !p->quiet)
75136
fprintf(stderr, "\n");
76137
}

src/progress.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#define PROGRESS_H
1111

1212
#include <stddef.h>
13+
#include <stdint.h>
14+
#include <time.h>
1315

1416
/*
1517
* Progress callback function type
@@ -25,6 +27,8 @@ typedef struct {
2527
const char *desc;
2628
progress_cb_t callback;
2729
void *user_data;
30+
struct timespec start_time; /* Start time for speed/ETA calculation */
31+
int quiet; /* Suppress output if set */
2832
} progress_t;
2933

3034
void progress_init(progress_t *p, size_t total, const char *desc);
@@ -37,4 +41,16 @@ void progress_finish(progress_t *p);
3741
*/
3842
void progress_set_callback(progress_t *p, progress_cb_t cb, void *user_data);
3943

44+
/*
45+
* Set quiet mode (suppress default progress output to stderr)
46+
* Callbacks are still invoked if set
47+
*/
48+
void progress_set_quiet(progress_t *p, int quiet);
49+
50+
/*
51+
* Global quiet mode setting (affects all progress instances)
52+
* Set before calling progress_init to apply to new instances
53+
*/
54+
extern int progress_global_quiet;
55+
4056
#endif /* PROGRESS_H */

0 commit comments

Comments
 (0)