From c38ef12d02c6e6bb464afa440a31ec96c2234480 Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Tue, 21 Oct 2025 15:45:31 +0200 Subject: [PATCH 1/4] feat: flash sketch in ram --- internal/orchestrator/orchestrator.go | 66 +++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 41890fa4..55e4233e 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -1078,8 +1078,6 @@ func compileUploadSketch( arduinoApp *app.ArduinoApp, w io.Writer, ) error { - const fqbn = "arduino:zephyr:unoq" - logrus.SetLevel(logrus.ErrorLevel) // Reduce the log level of arduino-cli srv := commands.NewArduinoCoreServer() @@ -1101,6 +1099,9 @@ func compileUploadSketch( } sketch := sketchResp.GetSketch() profile := sketch.GetDefaultProfile().GetName() + if profile == "" { + return fmt.Errorf("sketch %q has no default profile", sketchPath) + } initReq := &rpc.InitRequest{ Instance: inst, SketchPath: sketchPath, @@ -1140,18 +1141,13 @@ func compileUploadSketch( // build the sketch server, getCompileResult := commands.CompilerServerToStreams(ctx, w, w, nil) - - // TODO: add build cache compileReq := rpc.CompileRequest{ Instance: inst, - Fqbn: fqbn, + Fqbn: "arduino:zephyr:unoq", SketchPath: sketchPath, BuildPath: buildPath, Jobs: 2, } - if profile == "" { - compileReq.Libraries = []string{sketchPath + "/../../sketch-libraries"} - } err = srv.Compile(&compileReq, server) if err != nil { @@ -1174,12 +1170,62 @@ func compileUploadSketch( slog.Info("Used library " + lib.GetName() + " (" + lib.GetVersion() + ") in " + lib.GetInstallDir()) } + if err := uploadSketchInRam(ctx, w, srv, inst, sketchPath, buildPath); err != nil { + slog.Warn("failed to upload in ram mode, trying to configure the board in ram mode, and retry", slog.String("error", err.Error())) + if err := configureMicroInRamMode(ctx, w, srv, inst); err != nil { + return err + } + return uploadSketchInRam(ctx, w, srv, inst, sketchPath, buildPath) + } + return nil +} + +func uploadSketchInRam(ctx context.Context, + w io.Writer, + srv rpc.ArduinoCoreServiceServer, + inst *rpc.Instance, + sketchPath string, + buildPath string, +) error { stream, _ := commands.UploadToServerStreams(ctx, w, w) - return srv.Upload(&rpc.UploadRequest{ + if err := srv.Upload(&rpc.UploadRequest{ Instance: inst, - Fqbn: fqbn, + Fqbn: "arduino:zephyr:unoq:flash_mode=ram", SketchPath: sketchPath, ImportDir: buildPath, + }, stream); err != nil { + return err + } + return nil +} + +// configureMicroInRamMode uploads an empty binary overing any sketch previously uploaded in flash. +// This is required to be able to upload sketches in ram mode after if there is already a sketch in flash. +func configureMicroInRamMode( + ctx context.Context, + w io.Writer, + srv rpc.ArduinoCoreServiceServer, + inst *rpc.Instance, +) error { + zeros, err := os.Open("/dev/zero") + if err != nil { + return err + } + defer zeros.Close() + empty, err := os.Create("/tmp/empty.elf-zsk.bin") //nolint:gosec + if err != nil { + return err + } + defer empty.Close() + if _, err := io.CopyN(empty, zeros, 50); err != nil { + return err + } + + stream, _ := commands.UploadToServerStreams(ctx, w, w) + return srv.Upload(&rpc.UploadRequest{ + Instance: inst, + Fqbn: "arduino:zephyr:unoq:flash_mode=flash", + ImportFile: "/tmp/empty", }, stream) } From e47186c48ee9185fdb9c1c229979b060a60bd9fe Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Wed, 5 Nov 2025 12:28:50 +0100 Subject: [PATCH 2/4] workaround file check --- internal/orchestrator/orchestrator.go | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index d4738549..8a8f937a 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -1258,13 +1258,23 @@ func configureMicroInRamMode( return err } defer zeros.Close() - empty, err := os.Create("/tmp/empty.elf-zsk.bin") //nolint:gosec - if err != nil { - return err - } - defer empty.Close() - if _, err := io.CopyN(empty, zeros, 50); err != nil { - return err + + // FIXME: arduino-cli upload checks that a file exist but the extension is added after by the platform configuration. + // So we create two temporary files with some zeros. + for _, tmpFile := range paths.NewPathList("/tmp/empty", "/tmp/empty.elf-zsk.bin") { + if err := func(path *paths.Path) error { + empty, err := path.Create() + if err != nil { + return err + } + defer empty.Close() + if _, err := io.CopyN(empty, zeros, 50); err != nil { + return err + } + return nil + }(tmpFile); err != nil { + return fmt.Errorf("failed to write empty file %q: %w", tmpFile.String(), err) + } } stream, _ := commands.UploadToServerStreams(ctx, w, w) From a251fda00634a0b1ba40069a07acc350a2840507 Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Wed, 5 Nov 2025 13:03:33 +0100 Subject: [PATCH 3/4] a better workaround --- internal/orchestrator/orchestrator.go | 35 ++++++++++++--------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 8a8f937a..463692fd 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -1253,35 +1253,32 @@ func configureMicroInRamMode( srv rpc.ArduinoCoreServiceServer, inst *rpc.Instance, ) error { + emptyBinDir := paths.New("/tmp/empty") + defer emptyBinDir.RemoveAll() + if err := emptyBinDir.MkdirAll(); err != nil { + return err + } + zeros, err := os.Open("/dev/zero") if err != nil { return err } defer zeros.Close() - // FIXME: arduino-cli upload checks that a file exist but the extension is added after by the platform configuration. - // So we create two temporary files with some zeros. - for _, tmpFile := range paths.NewPathList("/tmp/empty", "/tmp/empty.elf-zsk.bin") { - if err := func(path *paths.Path) error { - empty, err := path.Create() - if err != nil { - return err - } - defer empty.Close() - if _, err := io.CopyN(empty, zeros, 50); err != nil { - return err - } - return nil - }(tmpFile); err != nil { - return fmt.Errorf("failed to write empty file %q: %w", tmpFile.String(), err) - } + empty, err := emptyBinDir.Join("empty.ino.elf-zsk.bin").Create() + if err != nil { + return err + } + defer empty.Close() + if _, err := io.CopyN(empty, zeros, 50); err != nil { + return err } stream, _ := commands.UploadToServerStreams(ctx, w, w) return srv.Upload(&rpc.UploadRequest{ - Instance: inst, - Fqbn: "arduino:zephyr:unoq:flash_mode=flash", - ImportFile: "/tmp/empty", + Instance: inst, + Fqbn: "arduino:zephyr:unoq:flash_mode=flash", + ImportDir: emptyBinDir.String(), }, stream) } From 20782390633335e1aa819c9d2e1fd64f5c593a48 Mon Sep 17 00:00:00 2001 From: lucarin91 Date: Wed, 5 Nov 2025 15:16:16 +0100 Subject: [PATCH 4/4] fix linter --- internal/orchestrator/orchestrator.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index 463692fd..19181998 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -1254,10 +1254,8 @@ func configureMicroInRamMode( inst *rpc.Instance, ) error { emptyBinDir := paths.New("/tmp/empty") - defer emptyBinDir.RemoveAll() - if err := emptyBinDir.MkdirAll(); err != nil { - return err - } + _ = emptyBinDir.MkdirAll() + defer func() { _ = emptyBinDir.RemoveAll() }() zeros, err := os.Open("/dev/zero") if err != nil {