18
18
package otaapi
19
19
20
20
import (
21
+ "strconv"
21
22
"strings"
22
23
"time"
23
24
@@ -26,10 +27,13 @@ import (
26
27
"github.com/arduino/arduino-cli/table"
27
28
)
28
29
30
+ const progressBarMultiplier = 2
31
+
29
32
type (
30
33
OtaStatusResponse struct {
31
- Ota Ota `json:"ota"`
32
- States []State `json:"states,omitempty"`
34
+ FirmwareSize * int64 `json:"firmware_size,omitempty"`
35
+ Ota Ota `json:"ota"`
36
+ States []State `json:"states,omitempty"`
33
37
}
34
38
35
39
OtaStatusList struct {
53
57
}
54
58
55
59
OtaStatusDetail struct {
56
- Ota Ota `json:"ota"`
57
- Details []State `json:"details,omitempty"`
60
+ FirmwareSize * int64 `json:"firmware_size,omitempty"`
61
+ Ota Ota `json:"ota"`
62
+ Details []State `json:"details,omitempty"`
58
63
}
59
64
)
60
65
@@ -154,15 +159,62 @@ func (r OtaStatusDetail) String() string {
154
159
if len (r .Details ) > 0 {
155
160
t = table .New ()
156
161
t .SetHeader ("Time" , "Status" , "Detail" )
162
+ fwSize := int64 (0 )
163
+ if r .FirmwareSize != nil {
164
+ fwSize = * r .FirmwareSize
165
+ }
157
166
for _ , s := range r .Details {
158
- t .AddRow (formatHumanReadableTs (s .Timestamp ), upperCaseFirst (s .State ), s .StateData )
167
+ stateData := formatStateData (s .State , s .StateData , fwSize , hasReachedFlashState (r .Details ))
168
+ t .AddRow (formatHumanReadableTs (s .Timestamp ), upperCaseFirst (s .State ), stateData )
159
169
}
160
170
output += "\n Details:\n " + t .Render ()
161
171
}
162
172
163
173
return output
164
174
}
165
175
176
+ func hasReachedFlashState (states []State ) bool {
177
+ for _ , s := range states {
178
+ if s .State == "flash" || s .State == "reboot" {
179
+ return true
180
+ }
181
+ }
182
+ return false
183
+ }
184
+
185
+ func formatStateData (state , data string , firmware_size int64 , hasReceivedFlashState bool ) string {
186
+ if data == "" || data == "Unknown" {
187
+ return ""
188
+ }
189
+ if state == "fetch" {
190
+ // This is the state 'fetch' of OTA progress. This contains a number that represents the number of bytes fetched
191
+ actualDownloadedData , err := strconv .Atoi (data )
192
+ if err != nil || actualDownloadedData <= 0 || firmware_size <= 0 { // Sanitize and avoid division by zero
193
+ return data
194
+ }
195
+ if hasReceivedFlashState {
196
+ return buildSimpleProgressBar (float64 (100 ))
197
+ }
198
+ percentage := (float64 (actualDownloadedData ) / float64 (firmware_size )) * 100
199
+ return buildSimpleProgressBar (percentage )
200
+ }
201
+ return data
202
+ }
203
+
204
+ func buildSimpleProgressBar (progress float64 ) string {
205
+ progressInt := int (progress ) / 10
206
+ progressInt = progressInt * progressBarMultiplier
207
+ maxProgress := 10 * progressBarMultiplier
208
+ var bar strings.Builder
209
+ bar .WriteString ("[" )
210
+ bar .WriteString (strings .Repeat ("=" , progressInt ))
211
+ bar .WriteString (strings .Repeat (" " , maxProgress - progressInt ))
212
+ bar .WriteString ("] " )
213
+ bar .WriteString (strconv .FormatFloat (progress , 'f' , 2 , 64 ))
214
+ bar .WriteString ("%" )
215
+ return bar .String ()
216
+ }
217
+
166
218
func upperCaseFirst (s string ) string {
167
219
if len (s ) > 0 {
168
220
s = strings .ReplaceAll (s , "_" , " " )
0 commit comments