Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -info option to tinygo monitor #3982

Merged
merged 2 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 18 additions & 29 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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":
Expand Down
93 changes: 93 additions & 0 deletions monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
deadprogram marked this conversation as resolved.
Show resolved Hide resolved
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)
deadprogram marked this conversation as resolved.
Show resolved Hide resolved
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.
Expand Down
Loading