@@ -18,10 +18,14 @@ package updater
1818import (
1919 "context"
2020 "encoding/hex"
21+ "errors"
2122 "fmt"
23+ "log/slog"
24+ "os/exec"
2225 "runtime"
2326 "strconv"
2427 "strings"
28+ "time"
2529
2630 "github.com/arduino/go-paths-helper"
2731 "github.com/fatih/color"
@@ -104,27 +108,13 @@ type FlashEvent struct {
104108type FlashCallback func (FlashEvent )
105109
106110func FlashBoard (ctx context.Context , downloadedImagePath * paths.Path , version string , preserveUser bool , callback FlashCallback ) error {
107- flashDir , err := searchForFlashDir (downloadedImagePath )
108- if err != nil {
109- return err
110- }
111-
112- qdlDir , err := paths .MkTempDir ("" , "qdl-" )
111+ qdlPath , cleanup , err := installQdl ()
113112 if err != nil {
114113 return err
115114 }
116- defer func () { _ = qdlDir .RemoveAll () }()
117-
118- qdlPath := qdlDir .Join ("qdl" )
119- if runtime .GOOS == "windows" {
120- qdlPath = qdlDir .Join ("qdl.exe" )
121- }
115+ defer cleanup ()
122116
123- err = qdlPath .WriteFile (artifacts .QdlBinary )
124- if err != nil {
125- return err
126- }
127- err = qdlPath .Chmod (0755 )
117+ flashDir , err := searchForFlashDir (downloadedImagePath )
128118 if err != nil {
129119 return err
130120 }
@@ -223,6 +213,27 @@ func searchForFlashDir(extractPath *paths.Path) (*paths.Path, error) {
223213 }
224214}
225215
216+ func installQdl () (* paths.Path , func (), error ) {
217+ qdlDir , err := paths .MkTempDir ("" , "qdl-" )
218+ if err != nil {
219+ return nil , nil , err
220+ }
221+
222+ qdlPath := qdlDir .Join ("qdl" )
223+ if runtime .GOOS == "windows" {
224+ qdlPath = qdlDir .Join ("qdl.exe" )
225+ }
226+
227+ if err = qdlPath .WriteFile (artifacts .QdlBinary ); err != nil {
228+ return nil , nil , err
229+ }
230+ if err = qdlPath .Chmod (0755 ); err != nil {
231+ return nil , nil , err
232+ }
233+
234+ return qdlPath , func () { _ = qdlDir .RemoveAll () }, nil
235+ }
236+
226237// Checks the board GPT table and counts the number of partitions, this tells if the board supports preserving or not user's data.
227238func checkBoardGPTTable (ctx context.Context , qdlPath , flashDir * paths.Path ) error {
228239 dumpBinPath := qdlPath .Parent ().Join ("dump.bin" )
@@ -272,3 +283,35 @@ func checkBoardGPTTable(ctx context.Context, qdlPath, flashDir *paths.Path) erro
272283
273284 return nil
274285}
286+
287+ // WantForQdlDevice waits for a QDL device to be connected.
288+ // This is like and hack because QDL does not have a specific command to wait for a device,
289+ // so we use the read command with a dummy ELF and XML file to detect when a device is connected.
290+ func WaitForQdlDevice (ctx context.Context ) error {
291+ qdlPath , cleanup , err := installQdl ()
292+ if err != nil {
293+ return err
294+ }
295+ defer cleanup ()
296+
297+ for {
298+ cmd , err := paths .NewProcess (nil , qdlPath .String (), "--list" )
299+ if err != nil {
300+ return err
301+ }
302+ if out , err := cmd .RunAndCaptureCombinedOutput (ctx ); err != nil {
303+ slog .Debug ("wait for qdl device command exit" , "out" , string (out ), "err" , err )
304+ var exitErr * exec.ExitError
305+ if errors .As (err , & exitErr ) {
306+ if exitErr .ExitCode () != 1 {
307+ return fmt .Errorf ("error waiting for QDL device: %w: %s" , err , out )
308+ }
309+ }
310+ } else {
311+ slog .Debug ("qdl device detected" , "out" , string (out ))
312+ return nil
313+ }
314+
315+ time .Sleep (1 * time .Second )
316+ }
317+ }
0 commit comments