aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--main.go47
-rw-r--r--monitor.go93
2 files changed, 111 insertions, 29 deletions
diff --git a/main.go b/main.go
index ddbc6080c..288cdf44a 100644
--- a/main.go
+++ b/main.go
@@ -1436,6 +1436,7 @@ func main() {
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
monitor := flag.Bool("monitor", false, "enable serial monitor")
+ info := flag.Bool("info", false, "print information")
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
// Internal flags, that are only intended for TinyGo development.
@@ -1731,41 +1732,29 @@ func main() {
os.Exit(1)
}
case "monitor":
- err := Monitor("", *port, options)
- handleCompilerError(err)
+ if *info {
+ serialPortInfo, err := ListSerialPorts()
+ handleCompilerError(err)
+ for _, s := range serialPortInfo {
+ fmt.Printf("%s %4s %4s %s\n", s.Name, s.VID, s.PID, s.Target)
+ }
+ } else {
+ err := Monitor("", *port, options)
+ handleCompilerError(err)
+ }
case "targets":
- dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
- entries, err := os.ReadDir(dir)
+ specs, err := GetTargetSpecs()
if err != nil {
fmt.Fprintln(os.Stderr, "could not list targets:", err)
os.Exit(1)
return
}
- for _, entry := range entries {
- entryInfo, err := entry.Info()
- if err != nil {
- fmt.Fprintln(os.Stderr, "could not get entry info:", err)
- os.Exit(1)
- return
- }
- if !entryInfo.Mode().IsRegular() || !strings.HasSuffix(entry.Name(), ".json") {
- // Only inspect JSON files.
- continue
- }
- path := filepath.Join(dir, entry.Name())
- spec, err := compileopts.LoadTarget(&compileopts.Options{Target: path})
- if err != nil {
- fmt.Fprintln(os.Stderr, "could not list target:", err)
- os.Exit(1)
- return
- }
- if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
- // This doesn't look like a regular target file, but rather like
- // a parent target (such as targets/cortex-m.json).
- continue
- }
- name := entry.Name()
- name = name[:len(name)-5]
+ names := []string{}
+ for key := range specs {
+ names = append(names, key)
+ }
+ sort.Strings(names)
+ for _, name := range names {
fmt.Println(name)
}
case "info":
diff --git a/monitor.go b/monitor.go
index 9bef531f9..23846b352 100644
--- a/monitor.go
+++ b/monitor.go
@@ -11,14 +11,19 @@ import (
"io"
"os"
"os/signal"
+ "path/filepath"
"regexp"
"strconv"
+ "strings"
"time"
"github.com/mattn/go-tty"
"github.com/tinygo-org/tinygo/builder"
"github.com/tinygo-org/tinygo/compileopts"
+ "github.com/tinygo-org/tinygo/goenv"
+
"go.bug.st/serial"
+ "go.bug.st/serial/enumerator"
)
// Monitor connects to the given port and reads/writes the serial port.
@@ -128,6 +133,94 @@ func Monitor(executable, port string, options *compileopts.Options) error {
return <-errCh
}
+// SerialPortInfo is a structure that holds information about the port and its
+// associated TargetSpec.
+type SerialPortInfo struct {
+ Name string
+ IsUSB bool
+ VID string
+ PID string
+ Target string
+ Spec *compileopts.TargetSpec
+}
+
+// ListSerialPort returns serial port information and any detected TinyGo
+// target
+func ListSerialPorts() ([]SerialPortInfo, error) {
+ maps, err := GetTargetSpecs()
+ if err != nil {
+ return nil, err
+ }
+
+ portsList, err := enumerator.GetDetailedPortsList()
+ if err != nil {
+ return nil, err
+ }
+
+ serialPortInfo := []SerialPortInfo{}
+ for _, p := range portsList {
+ info := SerialPortInfo{
+ Name: p.Name,
+ IsUSB: p.IsUSB,
+ VID: p.VID,
+ PID: p.PID,
+ }
+ vid := strings.ToLower(p.VID)
+ pid := strings.ToLower(p.PID)
+ for k, v := range maps {
+ usbInterfaces := v.SerialPort
+ for _, s := range usbInterfaces {
+ parts := strings.Split(s, ":")
+ if len(parts) != 2 {
+ continue
+ }
+ if vid == strings.ToLower(parts[0]) && pid == strings.ToLower(parts[1]) {
+ info.Target = k
+ info.Spec = v
+ }
+ }
+ }
+ serialPortInfo = append(serialPortInfo, info)
+ }
+
+ return serialPortInfo, nil
+}
+
+func GetTargetSpecs() (map[string]*compileopts.TargetSpec, error) {
+ dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
+ entries, err := os.ReadDir(dir)
+ if err != nil {
+ return nil, fmt.Errorf("could not list targets: %w", err)
+ }
+
+ maps := map[string]*compileopts.TargetSpec{}
+ for _, entry := range entries {
+ entryInfo, err := entry.Info()
+ if err != nil {
+ return nil, fmt.Errorf("could not get entry info: %w", err)
+ }
+ if !entryInfo.Mode().IsRegular() || !strings.HasSuffix(entry.Name(), ".json") {
+ // Only inspect JSON files.
+ continue
+ }
+ path := filepath.Join(dir, entry.Name())
+ spec, err := compileopts.LoadTarget(&compileopts.Options{Target: path})
+ if err != nil {
+ return nil, fmt.Errorf("cnuld not list target: %w", err)
+ }
+ if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
+ // This doesn't look like a regular target file, but rather like
+ // a parent target (such as targets/cortex-m.json).
+ continue
+ }
+ name := entry.Name()
+ name = name[:len(name)-5]
+ //fmt.Println(name)
+ maps[name] = spec
+ }
+ return maps, nil
+}
+
var addressMatch = regexp.MustCompile(`^panic: runtime error at 0x([0-9a-f]+): `)
// Extract the address from the "panic: runtime error at" message.