Unverified Commit aa15421a authored by Cristian Maglie's avatar Cristian Maglie Committed by GitHub

[skip-changelog] Replaced internal serialutils package with the equivalent library (#2528)

parent 2b2394e5
This diff is collapsed.
......@@ -31,12 +31,12 @@ import (
"github.com/arduino/arduino-cli/internal/arduino/cores/packagemanager"
"github.com/arduino/arduino-cli/internal/arduino/discovery"
"github.com/arduino/arduino-cli/internal/arduino/globals"
"github.com/arduino/arduino-cli/internal/arduino/serialutils"
"github.com/arduino/arduino-cli/internal/arduino/sketch"
"github.com/arduino/arduino-cli/internal/i18n"
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
paths "github.com/arduino/go-paths-helper"
properties "github.com/arduino/go-properties-orderedmap"
serialutils "github.com/arduino/go-serial-utils"
"github.com/sirupsen/logrus"
)
......@@ -470,7 +470,7 @@ func runProgramAction(pme *packagemanager.Explorer,
},
}
if newPortAddress, err := serialutils.Reset(portToTouch, wait, cb, dryRun); err != nil {
if newPortAddress, err := serialutils.Reset(portToTouch, wait, dryRun, nil, cb); err != nil {
errStream.Write([]byte(fmt.Sprintln(tr("Cannot perform port reset: %s", err))))
} else {
if newPortAddress != "" {
......
......@@ -9,6 +9,7 @@ require (
github.com/ProtonMail/go-crypto v1.1.0-alpha.0
github.com/arduino/go-paths-helper v1.12.0
github.com/arduino/go-properties-orderedmap v1.8.0
github.com/arduino/go-serial-utils v0.1.2
github.com/arduino/go-timeutils v0.0.0-20171220113728-d1dd9e313b1b
github.com/arduino/go-win32-utils v1.0.0
github.com/arduino/pluggable-discovery-protocol-handler/v2 v2.1.2
......@@ -36,7 +37,6 @@ require (
go.bug.st/cleanup v1.0.0
go.bug.st/downloader/v2 v2.1.1
go.bug.st/relaxed-semver v0.12.0
go.bug.st/serial v1.6.1
go.bug.st/testifyjson v1.1.1
golang.org/x/term v0.16.0
golang.org/x/text v0.14.0
......@@ -93,6 +93,7 @@ require (
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
go.bug.st/serial v1.6.1 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
......
// This file is part of arduino-cli
//
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
//
// This software is released under the GNU General Public License version 3,
// which covers the main part of arduino-cli.
// The terms of this license can be found at:
// https://www.gnu.org/licenses/gpl-3.0.en.html
//
// You can be released from the requirements of the above licenses by purchasing
// a commercial license. Buying such a license is mandatory if you want to
// modify or otherwise use the software for commercial activities involving the
// Arduino software without disclosing the source code of your own applications.
// To purchase a commercial license, send an email to license@arduino.cc.
package serialutils
import (
"fmt"
"runtime"
"strings"
"time"
"github.com/arduino/arduino-cli/internal/i18n"
"go.bug.st/serial"
)
var tr = i18n.Tr
// TouchSerialPortAt1200bps open and close the serial port at 1200 bps. This
// is used on many Arduino boards as a signal to put the board in "bootloader"
// mode.
func TouchSerialPortAt1200bps(port string) error {
// Open port
p, err := serial.Open(port, &serial.Mode{BaudRate: 1200})
if err != nil {
return fmt.Errorf("%s: %w", tr("opening port at 1200bps"), err)
}
if runtime.GOOS != "windows" {
// This is not required on Windows
// TODO: Investigate if it can be removed for other OS too
// Set DTR to false
if err = p.SetDTR(false); err != nil {
p.Close()
return fmt.Errorf("%s: %w", tr("setting DTR to OFF"), err)
}
}
// Close serial port
p.Close()
// Scanning for available ports seems to open the port or
// otherwise assert DTR, which would cancel the WDT reset if
// it happens within 250 ms. So we wait until the reset should
// have already occurred before going on.
time.Sleep(500 * time.Millisecond)
return nil
}
func getPortMap() (map[string]bool, error) {
ports, err := serial.GetPortsList()
if err != nil {
return nil, fmt.Errorf("%s: %w", tr("listing serial ports"), err)
}
res := map[string]bool{}
for _, port := range ports {
res[port] = true
}
return res, nil
}
// ResetProgressCallbacks is a struct that defines a bunch of function callback
// to observe the Reset function progress.
type ResetProgressCallbacks struct {
// TouchingPort is called to signal the 1200-bps touch of the reported port
TouchingPort func(port string)
// WaitingForNewSerial is called to signal that we are waiting for a new port
WaitingForNewSerial func()
// BootloaderPortFound is called to signal that the wait is completed and to
// report the port found, or the empty string if no ports have been found and
// the wait has timed-out.
BootloaderPortFound func(port string)
// Debug reports messages useful for debugging purposes. In normal conditions
// these messages should not be displayed to the user.
Debug func(msg string)
}
// Reset a board using the 1200 bps port-touch and wait for new ports.
// Both reset and wait are optional:
// - if port is "" touch will be skipped
// - if wait is false waiting will be skipped
// If wait is true, this function will wait for a new port to appear and returns that
// one, otherwise the empty string is returned if the new port can not be detected or
// if the wait parameter is false.
// If dryRun is set to true this function will only emulate the port reset without actually
// performing it, this is useful to mockup for unit-testing and CI.
// In dryRun mode if the `portToTouch` ends with `"999"` and wait is true, Reset will
// return a new "bootloader" port as `portToTouch+"0"`.
// The error is set if the port listing fails.
func Reset(portToTouch string, wait bool, cb *ResetProgressCallbacks, dryRun bool) (string, error) {
getPorts := getPortMap // non dry-run default
if dryRun {
emulatedPort := portToTouch
getPorts = func() (map[string]bool, error) {
res := map[string]bool{}
if emulatedPort != "" {
res[emulatedPort] = true
}
if strings.HasSuffix(emulatedPort, "999") {
emulatedPort += "0"
} else if emulatedPort == "" {
emulatedPort = "newport"
}
return res, nil
}
}
last, err := getPorts()
if cb != nil && cb.Debug != nil {
cb.Debug(fmt.Sprintf("LAST: %v", last))
}
if err != nil {
return "", err
}
if portToTouch != "" && last[portToTouch] {
if cb != nil && cb.Debug != nil {
cb.Debug(fmt.Sprintf("TOUCH: %v", portToTouch))
}
if cb != nil && cb.TouchingPort != nil {
cb.TouchingPort(portToTouch)
}
if dryRun {
// do nothing!
} else {
if err := TouchSerialPortAt1200bps(portToTouch); err != nil && !wait {
return "", fmt.Errorf("%s: %w", tr("error during board reset"), err)
}
}
}
if !wait {
return "", nil
}
if cb != nil && cb.WaitingForNewSerial != nil {
cb.WaitingForNewSerial()
}
deadline := time.Now().Add(10 * time.Second)
if dryRun {
// use a much lower timeout in dryRun
deadline = time.Now().Add(100 * time.Millisecond)
}
for time.Now().Before(deadline) {
now, err := getPorts()
if err != nil {
return "", err
}
if cb != nil && cb.Debug != nil {
cb.Debug(fmt.Sprintf("WAIT: %v", now))
}
hasNewPorts := false
for p := range now {
if !last[p] {
hasNewPorts = true
break
}
}
if hasNewPorts {
if cb != nil && cb.Debug != nil {
cb.Debug("New ports found!")
}
// on OS X, if the port is opened too quickly after it is detected,
// a "Resource busy" error occurs, add a delay to workaround.
// This apply to other platforms as well.
time.Sleep(time.Second)
// Some boards have a glitch in the bootloader: some user experienced
// the USB serial port appearing and disappearing rapidly before
// settling.
// This check ensure that the port is stable after one second.
check, err := getPorts()
if err != nil {
return "", err
}
if cb != nil && cb.Debug != nil {
cb.Debug(fmt.Sprintf("CHECK: %v", check))
}
for p := range check {
if !last[p] {
if cb != nil && cb.BootloaderPortFound != nil {
cb.BootloaderPortFound(p)
}
return p, nil // Found it!
}
}
if cb != nil && cb.Debug != nil {
cb.Debug("Port check failed... still waiting")
}
}
last = now
time.Sleep(250 * time.Millisecond)
}
if cb != nil && cb.BootloaderPortFound != nil {
cb.BootloaderPortFound("")
}
return "", nil
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment