Skip to content

Commit

Permalink
Add -info option to tinygo monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
sago35 committed Oct 30, 2023
1 parent 938ce22 commit 0847681
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 29 deletions.
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) {
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.
Expand Down

0 comments on commit 0847681

Please sign in to comment.