From d274545e6379ebaaeab6914dfa0b189788cd528d Mon Sep 17 00:00:00 2001 From: deadprogram Date: Wed, 8 Apr 2026 20:22:17 +0200 Subject: [PATCH] targets: add "adb" flash method using Android Debug Bridge Add a new flash method that uses adb to flash boards over Android Debug Bridge. The method supports running pre-flash shell commands via "adb shell", pushing the firmware binary via "adb push", and running post-flash shell commands with a {remote} token for the remote path. New target JSON fields: - adb-pre-commands: shell commands to run before pushing firmware - adb-push-remote: remote device path for adb push - adb-post-commands: shell commands to run after pushing firmware Switch arduino-uno-q target to use the new adb flash method with openocd running on the remote device. Signed-off-by: deadprogram --- compileopts/config.go | 2 +- compileopts/target.go | 3 +++ main.go | 34 ++++++++++++++++++++++++++++++++++ targets/arduino-uno-q.json | 8 +++++--- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/compileopts/config.go b/compileopts/config.go index 7ce7ae547..1920d2b9c 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -536,7 +536,7 @@ func (c *Config) Programmer() (method, openocdInterface string) { case "": // No configuration supplied. return c.Target.FlashMethod, c.Target.OpenOCDInterface - case "openocd", "msd", "command": + case "openocd", "msd", "command", "adb": // The -programmer flag only specifies the flash method. return c.Options.Programmer, c.Target.OpenOCDInterface case "bmp": diff --git a/compileopts/target.go b/compileopts/target.go index 29b3733bd..4e0269e6b 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -64,6 +64,9 @@ type TargetSpec struct { OpenOCDCommands []string `json:"openocd-commands,omitempty"` OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd JLinkDevice string `json:"jlink-device,omitempty"` + ADBPreCommands []string `json:"adb-pre-commands,omitempty"` + ADBPushRemote string `json:"adb-push-remote,omitempty"` + ADBPostCommands []string `json:"adb-post-commands,omitempty"` CodeModel string `json:"code-model,omitempty"` RelocationModel string `json:"relocation-model,omitempty"` WITPackage string `json:"wit-package,omitempty"` diff --git a/main.go b/main.go index a798b9fb4..5ae4765bf 100644 --- a/main.go +++ b/main.go @@ -396,6 +396,8 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error { fileExt = ".hex" case "bmp": fileExt = ".elf" + case "adb": + fileExt = ".hex" case "esp32flash", "esp32jtag": fileExt = ".bin" case "native": @@ -532,6 +534,38 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error { if err != nil { return &commandError{"failed to flash", result.Binary, err} } + case "adb": + // Run pre-flash adb shell commands. + for _, preCmd := range config.Target.ADBPreCommands { + cmd := executeCommand(config.Options, "adb", "shell", preCmd) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return &commandError{"failed to run adb pre-command", preCmd, err} + } + } + + // Push the binary to the device. + if config.Target.ADBPushRemote == "" { + return errors.New("invalid target file: flash-method was set to \"adb\" but no adb-push-remote was set") + } + cmd := executeCommand(config.Options, "adb", "push", result.Binary, config.Target.ADBPushRemote) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return &commandError{"adb push failed to " + config.Target.ADBPushRemote, result.Binary, err} + } + + // Run post-flash adb shell commands. + for _, postCmd := range config.Target.ADBPostCommands { + postCmd = strings.ReplaceAll(postCmd, "{remote}", config.Target.ADBPushRemote) + cmd := executeCommand(config.Options, "adb", "shell", postCmd) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return &commandError{"failed to run adb post-command", postCmd, err} + } + } case "esp32flash": port, err := getDefaultPort(port, config.Target.SerialPort) if err != nil { diff --git a/targets/arduino-uno-q.json b/targets/arduino-uno-q.json index 8309d2ca6..95600ebc5 100644 --- a/targets/arduino-uno-q.json +++ b/targets/arduino-uno-q.json @@ -2,7 +2,9 @@ "inherits": ["stm32u585"], "build-tags": ["arduino_uno_q"], "serial": "uart", - "openocd-interface": "stlink", - "openocd-target": "stm32u5x", - "openocd-commands": ["adapter driver linuxgpiod adapter gpio swclk -chip 1 26 adapter gpio swdio -chip 1 25 adapter gpio srst -chip 1 38 transport select swd adapter speed 1000 reset_config srst_only srst_push_pull"] + "flash-method": "adb", + "adb-push-remote": "/tmp/firmware.hex", + "adb-post-commands": [ + "/opt/openocd/bin/openocd -s /opt/openocd/share/openocd/scripts -s /opt/openocd -c \"adapter driver linuxgpiod\" -c \"adapter gpio swclk -chip 1 26\" -c \"adapter gpio swdio -chip 1 25\" -c \"adapter gpio srst -chip 1 38\" -c \"transport select swd\" -c \"adapter speed 1000\" -c \"reset_config srst_only srst_push_pull\" -f /opt/openocd/stm32u5x.cfg -c \"program {remote} verify reset exit\"" + ] }