simon 0299ba44fd Add bench UART ports and cold-start reset to goTool autotest.
Bench configs define command and console serial paths; scenarios can
reset nodes via esptool before tests. Smoke resets all nodes then waits
for ESP-NOW join.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 23:44:58 +02:00

104 lines
2.5 KiB
Go

package autotest
import (
"fmt"
"os"
"os/exec"
"time"
)
const defaultResetWaitMS = 2000
// ResetESP32 toggles EN via esptool (USB-JTAG / ttyACM console port).
func ResetESP32(port string) error {
if port == "" {
return fmt.Errorf("empty console port")
}
tries := [][]string{
{"python", "-m", "esptool", "--chip", "esp32s3", "-p", port,
"--before", "default_reset", "--after", "hard_reset", "chip_id"},
{"esptool.py", "--chip", "esp32s3", "-p", port,
"--before", "default_reset", "--after", "hard_reset", "chip_id"},
{"esptool", "--chip", "esp32s3", "-p", port,
"--before", "default_reset", "--after", "hard_reset", "chip_id"},
}
var lastErr error
for _, argv := range tries {
if _, err := exec.LookPath(argv[0]); err != nil {
lastErr = err
continue
}
cmd := exec.Command(argv[0], argv[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
lastErr = err
continue
}
return nil
}
if lastErr != nil {
return fmt.Errorf("esptool reset on %s: %w (install ESP-IDF esptool or python -m esptool)", port, lastErr)
}
return fmt.Errorf("esptool not found; cannot reset %s", port)
}
func (b *Bench) resetNode(target string) (string, error) {
switch target {
case "master", "":
if b.UART.MasterConsole == "" {
return "", fmt.Errorf("uart.master_console not set in config %q", b.ID)
}
return b.UART.MasterConsole, nil
default:
s, err := b.Slave(target)
if err != nil {
return "", err
}
if s.Console == "" {
return "", fmt.Errorf("slave %q has no console port in config", target)
}
return s.Console, nil
}
}
func (b *Bench) ResetTargets(targets []string, waitMS int) error {
if waitMS <= 0 {
waitMS = defaultResetWaitMS
}
if len(targets) == 0 {
targets = []string{"master"}
}
for _, t := range targets {
port, err := b.resetNode(t)
if err != nil {
return err
}
if err := ResetESP32(port); err != nil {
return err
}
time.Sleep(time.Duration(waitMS) * time.Millisecond)
}
return nil
}
func (b *Bench) ResetAll(waitMS int) error {
// Slaves first, master last — master discover runs after slaves are booting.
var targets []string
for i := range b.Slaves {
if b.Slaves[i].Console != "" {
targets = append(targets, b.Slaves[i].ID)
}
}
if b.UART.MasterConsole != "" {
targets = append(targets, "master")
}
if len(targets) == 0 {
return fmt.Errorf("config %q: no console ports defined for reset", b.ID)
}
return b.ResetTargets(targets, waitMS)
}